diff options
| author | Laurențiu Nicola <lnicola@users.noreply.github.com> | 2025-03-10 09:52:17 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-03-10 09:52:17 +0000 |
| commit | 52f39ffe8320955868ce03eb22d9020c568472da (patch) | |
| tree | 6e32a4f4ff812cdbfb923b455777d48dbb1c45aa /src/tools | |
| parent | af32b22982ef0244cf4cf6a7f7b63274429289f8 (diff) | |
| parent | 1d983bf7941bb89985d53e741cabcf113912a40d (diff) | |
Merge pull request #19331 from lnicola/sync-from-rust
minor: Sync from downstream
Diffstat (limited to 'src/tools')
80 files changed, 832 insertions, 1069 deletions
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index cd5ca74f8ad..dfc8f3bc7e0 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -97,7 +97,6 @@ static TARGETS: &[&str] = &[ "bpfeb-unknown-none", "bpfel-unknown-none", "i386-apple-ios", - "i586-pc-windows-msvc", "i586-unknown-linux-gnu", "i586-unknown-linux-musl", "i586-unknown-redox", diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 8d1e893cb1a..33ba401d60c 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -150,6 +150,8 @@ impl<'tcx> Delegate<'tcx> for EscapeDelegate<'_, 'tcx> { } } + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) { if cmt.place.projections.is_empty() { if let PlaceBase::Local(lid) = cmt.place.base { diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs index 39e5e140b7a..fb5d49a1004 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs @@ -79,6 +79,8 @@ struct MutatePairDelegate<'a, 'tcx> { impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) { if bk == ty::BorrowKind::Mutable { if let PlaceBase::Local(id) = cmt.place.base { diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index b679fdfadc3..dd7a6f77acf 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -160,6 +160,7 @@ fn never_loop_expr<'tcx>( | ExprKind::UnsafeBinderCast(_, e, _) => never_loop_expr(cx, e, local_labels, main_loop_id), ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, local_labels, main_loop_id), ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, es.iter(), local_labels, main_loop_id), + ExprKind::Use(expr, _) => never_loop_expr(cx, expr, local_labels, main_loop_id), ExprKind::MethodCall(_, receiver, es, _) => { never_loop_expr_all(cx, once(receiver).chain(es.iter()), local_labels, main_loop_id) }, diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs index 09440c396ee..d0905733ab5 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs @@ -99,7 +99,7 @@ where }); if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(l), .. })) = e.kind { match captures.get(l) { - Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None, + Some(CaptureKind::Value | CaptureKind::Use | CaptureKind::Ref(Mutability::Mut)) => return None, Some(CaptureKind::Ref(Mutability::Not)) if binding_ref_mutability == Mutability::Mut => { return None; }, diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs index a80977459f2..f51bdc78f8a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -147,6 +147,8 @@ impl<'tcx> Delegate<'tcx> for MoveDelegate { } } + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: BorrowKind) {} fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs index d5c5679c990..dc10de24bc8 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -396,6 +396,8 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { } } + fn use_cloned(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {} + #[allow(clippy::if_same_then_else)] fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId, borrow: ty::BorrowKind) { self.prev_bind = None; diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 380cc380ad0..dc85176ebb9 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -326,6 +326,8 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt { self.move_common(cmt); } + fn use_cloned(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {} fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {} diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs index 5737a91031d..03b907ebdf4 100644 --- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs @@ -112,6 +112,7 @@ fn imm_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> HirIdSet { } fn consume(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} fn mutate(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} fn fake_read(&mut self, _: &PlaceWithHirId<'_>, _: FakeReadCause, _: HirId) {} fn copy(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} @@ -137,6 +138,7 @@ fn mut_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> HirIdSet { } fn consume(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} fn mutate(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} fn fake_read(&mut self, _: &PlaceWithHirId<'_>, _: FakeReadCause, _: HirId) {} fn copy(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs index de9f055863c..75b18bc651e 100644 --- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs @@ -177,7 +177,7 @@ fn try_get_option_occurrence<'tcx>( .then_some(()) .and_then(|()| none_captures.get(local_id)) }) { - Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None, + Some(CaptureKind::Value | CaptureKind::Use | CaptureKind::Ref(Mutability::Mut)) => return None, Some(CaptureKind::Ref(Mutability::Not)) if as_mut => return None, Some(CaptureKind::Ref(Mutability::Not)) | None => (), } diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index 76b9bbbd32f..6f6683eb971 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -230,6 +230,8 @@ impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 5fc166438e8..9d8c161873c 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -426,6 +426,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { kind!("Tup({elements})"); self.slice(elements, |e| self.expr(e)); }, + ExprKind::Use(expr, _) => { + bind!(self, expr); + kind!("Use({expr})"); + self.expr(expr); + }, ExprKind::Binary(op, left, right) => { bind!(self, op, left, right); kind!("Binary({op}, {left}, {right})"); @@ -488,6 +493,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { }) => { let capture_clause = match capture_clause { CaptureBy::Value { .. } => "Value { .. }", + CaptureBy::Use { .. } => "Use { .. }", CaptureBy::Ref => "Ref", }; diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index ab5f97199ce..4f024ecaf29 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -682,19 +682,20 @@ pub fn eq_generics(l: &Generics, r: &Generics) -> bool { pub fn eq_where_predicate(l: &WherePredicate, r: &WherePredicate) -> bool { use WherePredicateKind::*; - match (&l.kind, &r.kind) { - (BoundPredicate(l), BoundPredicate(r)) => { - over(&l.bound_generic_params, &r.bound_generic_params, |l, r| { - eq_generic_param(l, r) - }) && eq_ty(&l.bounded_ty, &r.bounded_ty) - && over(&l.bounds, &r.bounds, eq_generic_bound) - }, - (RegionPredicate(l), RegionPredicate(r)) => { - eq_id(l.lifetime.ident, r.lifetime.ident) && over(&l.bounds, &r.bounds, eq_generic_bound) - }, - (EqPredicate(l), EqPredicate(r)) => eq_ty(&l.lhs_ty, &r.lhs_ty) && eq_ty(&l.rhs_ty, &r.rhs_ty), - _ => false, - } + over(&l.attrs, &r.attrs, eq_attr) + && match (&l.kind, &r.kind) { + (BoundPredicate(l), BoundPredicate(r)) => { + over(&l.bound_generic_params, &r.bound_generic_params, |l, r| { + eq_generic_param(l, r) + }) && eq_ty(&l.bounded_ty, &r.bounded_ty) + && over(&l.bounds, &r.bounds, eq_generic_bound) + }, + (RegionPredicate(l), RegionPredicate(r)) => { + eq_id(l.lifetime.ident, r.lifetime.ident) && over(&l.bounds, &r.bounds, eq_generic_bound) + }, + (EqPredicate(l), EqPredicate(r)) => eq_ty(&l.lhs_ty, &r.lhs_ty) && eq_ty(&l.rhs_ty, &r.rhs_ty), + _ => false, + } } pub fn eq_use_tree(l: &UseTree, r: &UseTree) -> bool { diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index aaea8d71efb..4543a20cc2c 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -291,6 +291,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS ExprKind::ConstBlock(_) | ExprKind::Array(_) | ExprKind::Tup(_) + | ExprKind::Use(..) | ExprKind::Lit(_) | ExprKind::Cast(..) | ExprKind::Type(..) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 4bd86a25335..9938e64d242 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -393,6 +393,7 @@ impl HirEqInterExpr<'_, '_, '_> { && over(lf, rf, |l, r| self.eq_expr_field(l, r)) }, (&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup), + (&ExprKind::Use(l_expr, _), &ExprKind::Use(r_expr, _)) => self.eq_expr(l_expr, r_expr), (&ExprKind::Type(le, lt), &ExprKind::Type(re, rt)) => self.eq_expr(le, re) && self.eq_ty(lt, rt), (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re), (&ExprKind::Yield(le, _), &ExprKind::Yield(re, _)) => return self.eq_expr(le, re), @@ -425,6 +426,7 @@ impl HirEqInterExpr<'_, '_, '_> { | &ExprKind::Ret(..) | &ExprKind::Struct(..) | &ExprKind::Tup(..) + | &ExprKind::Use(..) | &ExprKind::Type(..) | &ExprKind::Unary(..) | &ExprKind::Yield(..) @@ -1053,6 +1055,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { ExprKind::Tup(tup) => { self.hash_exprs(tup); }, + ExprKind::Use(expr, _) => { + self.hash_expr(expr); + }, ExprKind::Unary(lop, le) => { std::mem::discriminant(&lop).hash(&mut self.s); self.hash_expr(le); @@ -1108,14 +1113,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_ty_pat(&mut self, pat: &TyPat<'_>) { std::mem::discriminant(&pat.kind).hash(&mut self.s); match pat.kind { - TyPatKind::Range(s, e, i) => { - if let Some(s) = s { - self.hash_const_arg(s); - } - if let Some(e) = e { - self.hash_const_arg(e); - } - std::mem::discriminant(&i).hash(&mut self.s); + TyPatKind::Range(s, e) => { + self.hash_const_arg(s); + self.hash_const_arg(e); }, TyPatKind::Err(_) => {}, } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index d850cc41000..d8969246844 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1129,6 +1129,7 @@ pub fn can_move_expr_to_closure_no_visit<'tcx>( #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CaptureKind { Value, + Use, Ref(Mutability), } impl CaptureKind { @@ -1141,6 +1142,7 @@ impl std::ops::BitOr for CaptureKind { fn bitor(self, rhs: Self) -> Self::Output { match (self, rhs) { (CaptureKind::Value, _) | (_, CaptureKind::Value) => CaptureKind::Value, + (CaptureKind::Use, _) | (_, CaptureKind::Use) => CaptureKind::Use, (CaptureKind::Ref(Mutability::Mut), CaptureKind::Ref(_)) | (CaptureKind::Ref(_), CaptureKind::Ref(Mutability::Mut)) => CaptureKind::Ref(Mutability::Mut), (CaptureKind::Ref(Mutability::Not), CaptureKind::Ref(Mutability::Not)) => CaptureKind::Ref(Mutability::Not), @@ -1220,7 +1222,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { }, ExprKind::Let(let_expr) => { let mutability = match pat_capture_kind(cx, let_expr.pat) { - CaptureKind::Value => Mutability::Not, + CaptureKind::Value | CaptureKind::Use => Mutability::Not, CaptureKind::Ref(m) => m, }; return CaptureKind::Ref(mutability); @@ -1229,7 +1231,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { let mut mutability = Mutability::Not; for capture in arms.iter().map(|arm| pat_capture_kind(cx, arm.pat)) { match capture { - CaptureKind::Value => break, + CaptureKind::Value | CaptureKind::Use => break, CaptureKind::Ref(Mutability::Mut) => mutability = Mutability::Mut, CaptureKind::Ref(Mutability::Not) => (), } @@ -1239,7 +1241,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { _ => break, }, Node::LetStmt(l) => match pat_capture_kind(cx, l.pat) { - CaptureKind::Value => break, + CaptureKind::Value | CaptureKind::Use => break, capture @ CaptureKind::Ref(_) => return capture, }, _ => break, @@ -1294,6 +1296,7 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<' if !self.locals.contains(&local_id) { let capture = match capture.info.capture_kind { UpvarCapture::ByValue => CaptureKind::Value, + UpvarCapture::ByUse => CaptureKind::Use, UpvarCapture::ByRef(kind) => match kind { BorrowKind::Immutable => CaptureKind::Ref(Mutability::Not), BorrowKind::UniqueImmutable | BorrowKind::Mutable => { @@ -3489,7 +3492,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // a::b::c ::d::sym refers to // e::f::sym:: :: // result should be super::super::super::super::e::f - if let DefPathData::TypeNs(s) = l { + if let DefPathData::TypeNs(Some(s)) = l { path.push(s.to_string()); } if let DefPathData::TypeNs(_) = r { @@ -3500,7 +3503,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // a::b::sym:: :: refers to // c::d::e ::f::sym // when looking at `f` - Left(DefPathData::TypeNs(sym)) => path.push(sym.to_string()), + Left(DefPathData::TypeNs(Some(sym))) => path.push(sym.to_string()), // consider: // a::b::c ::d::sym refers to // e::f::sym:: :: @@ -3514,7 +3517,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // `super` chain would be too long, just use the absolute path instead once(String::from("crate")) .chain(to.data.iter().filter_map(|el| { - if let DefPathData::TypeNs(sym) = el.data { + if let DefPathData::TypeNs(Some(sym)) = el.data { Some(sym.to_string()) } else { None diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index 3ce2cdfebe9..1a457bc7f21 100644 --- a/src/tools/clippy/clippy_utils/src/macros.rs +++ b/src/tools/clippy/clippy_utils/src/macros.rs @@ -1,6 +1,6 @@ #![allow(clippy::similar_names)] // `expr` and `expn` -use std::sync::Arc; +use std::sync::{Arc, OnceLock}; use crate::get_unique_attr; use crate::visitors::{Descend, for_each_expr_without_closures}; @@ -8,7 +8,6 @@ use crate::visitors::{Descend, for_each_expr_without_closures}; use arrayvec::ArrayVec; use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder}; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::OnceLock; use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; use rustc_lint::{LateContext, LintContext}; use rustc_span::def_id::DefId; diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 4a9ab17d4a6..24b4f0d9e6d 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -147,6 +147,7 @@ impl<'a> Sugg<'a> { | ExprKind::Become(..) | ExprKind::Struct(..) | ExprKind::Tup(..) + | ExprKind::Use(..) | ExprKind::Err(_) | ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(get_snippet(expr.span)), ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet), @@ -217,6 +218,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Try(..) | ast::ExprKind::TryBlock(..) | ast::ExprKind::Tup(..) + | ast::ExprKind::Use(..) | ast::ExprKind::Array(..) | ast::ExprKind::While(..) | ast::ExprKind::Await(..) @@ -835,6 +837,8 @@ impl<'tcx> DerefDelegate<'_, 'tcx> { impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) { if let PlaceBase::Local(id) = cmt.place.base { let map = self.cx.tcx.hir(); diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index 3bf518f7fe7..a079fd940c0 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -66,6 +66,8 @@ impl MutVarsDelegate { impl<'tcx> Delegate<'tcx> for MutVarsDelegate { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) { if bk == ty::BorrowKind::Mutable { self.update(cmt); diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index 2ac0efd7e39..63dd00f2de0 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -648,6 +648,9 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( helper(typeck, true, arg, f)?; } }, + ExprKind::Use(expr, _) => { + helper(typeck, true, expr, f)?; + }, ExprKind::Index(borrowed, consumed, _) | ExprKind::Assign(borrowed, consumed, _) | ExprKind::AssignOp(_, borrowed, consumed) => { diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index b302c6a49f5..978836cb663 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -190,6 +190,9 @@ pub struct Config { /// The cargo executable. pub cargo_path: Option<PathBuf>, + /// Rustc executable used to compile run-make recipes. + pub stage0_rustc_path: Option<PathBuf>, + /// The rustdoc executable. pub rustdoc_path: Option<PathBuf>, diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs index 8c909bcb195..b2ad5a3b3d0 100644 --- a/src/tools/compiletest/src/directive-list.rs +++ b/src/tools/compiletest/src/directive-list.rs @@ -52,6 +52,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-coverage-run", "ignore-cross-compile", "ignore-eabi", + "ignore-elf", "ignore-emscripten", "ignore-endian-big", "ignore-enzyme", @@ -182,6 +183,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-bpf", "only-cdb", "only-dist", + "only-elf", "only-emscripten", "only-gnu", "only-i686-pc-windows-gnu", diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 53ee901b8bc..7675e13990d 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -709,11 +709,11 @@ impl TestProps { /// returns a struct containing various parts of the directive. fn line_directive<'line>( line_number: usize, - comment: &str, original_line: &'line str, ) -> Option<DirectiveLine<'line>> { // Ignore lines that don't start with the comment prefix. - let after_comment = original_line.trim_start().strip_prefix(comment)?.trim_start(); + let after_comment = + original_line.trim_start().strip_prefix(COMPILETEST_DIRECTIVE_PREFIX)?.trim_start(); let revision; let raw_directive; @@ -722,7 +722,7 @@ fn line_directive<'line>( // A comment like `//@[foo]` only applies to revision `foo`. let Some((line_revision, after_close_bracket)) = after_open_bracket.split_once(']') else { panic!( - "malformed condition directive: expected `{comment}[foo]`, found `{original_line}`" + "malformed condition directive: expected `{COMPILETEST_DIRECTIVE_PREFIX}[foo]`, found `{original_line}`" ) }; @@ -836,6 +836,8 @@ pub(crate) fn check_directive<'a>( CheckDirectiveResult { is_known_directive: is_known(&directive_name), trailing_directive } } +const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@"; + fn iter_header( mode: Mode, _suite: &str, @@ -849,8 +851,7 @@ fn iter_header( } // Coverage tests in coverage-run mode always have these extra directives, without needing to - // specify them manually in every test file. (Some of the comments below have been copied over - // from the old `tests/run-make/coverage-reports/Makefile`, which no longer exists.) + // specify them manually in every test file. // // FIXME(jieyouxu): I feel like there's a better way to do this, leaving for later. if mode == Mode::CoverageRun { @@ -867,9 +868,6 @@ fn iter_header( } } - // NOTE(jieyouxu): once we get rid of `Makefile`s we can unconditionally check for `//@`. - let comment = if testfile.extension().is_some_and(|e| e == "rs") { "//@" } else { "#" }; - let mut rdr = BufReader::with_capacity(1024, rdr); let mut ln = String::new(); let mut line_number = 0; @@ -882,7 +880,7 @@ fn iter_header( } let ln = ln.trim(); - let Some(directive_line) = line_directive(line_number, comment, ln) else { + let Some(directive_line) = line_directive(line_number, ln) else { continue; }; diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs index 72a3b9d85c8..c369fff97f4 100644 --- a/src/tools/compiletest/src/header/cfg.rs +++ b/src/tools/compiletest/src/header/cfg.rs @@ -167,6 +167,16 @@ fn parse_cfg_name_directive<'a>( } condition! { + name: "elf", + condition: !config.target.contains("windows") + && !config.target.contains("wasm") + && !config.target.contains("apple") + && !config.target.contains("aix") + && !config.target.contains("uefi"), + message: "when the target binary format is ELF" + } + + condition! { name: "enzyme", condition: config.has_enzyme, message: "when rustc is built with LLVM Enzyme" diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index d7079fdeee6..007318be7cc 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -239,11 +239,6 @@ fn check_ignore(config: &Config, contents: &str) -> bool { d.ignore } -fn parse_makefile(config: &Config, contents: &str) -> EarlyProps { - let bytes = contents.as_bytes(); - EarlyProps::from_reader(config, Path::new("Makefile"), bytes) -} - #[test] fn should_fail() { let config: Config = cfg().build(); @@ -261,10 +256,6 @@ fn revisions() { let config: Config = cfg().build(); assert_eq!(parse_rs(&config, "//@ revisions: a b c").revisions, vec!["a", "b", "c"],); - assert_eq!( - parse_makefile(&config, "# revisions: hello there").revisions, - vec!["hello", "there"], - ); } #[test] diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 9dff7047bc4..dd611b19a8d 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -21,7 +21,7 @@ pub mod util; use core::panic; use std::collections::HashSet; -use std::ffi::{OsStr, OsString}; +use std::ffi::OsString; use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; @@ -54,6 +54,12 @@ pub fn parse_config(args: Vec<String>) -> Config { .reqopt("", "run-lib-path", "path to target shared libraries", "PATH") .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH") .optopt("", "cargo-path", "path to cargo to use for compiling", "PATH") + .optopt( + "", + "stage0-rustc-path", + "path to rustc to use for compiling run-make recipes", + "PATH", + ) .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH") .optopt("", "coverage-dump-path", "path to coverage-dump to use in tests", "PATH") .reqopt("", "python", "path to python to use for doc tests", "PATH") @@ -268,12 +274,8 @@ pub fn parse_config(args: Vec<String>) -> Config { let path = Path::new(f); let mut iter = path.iter().skip(1); - // We skip the test folder and check if the user passed `rmake.rs` or `Makefile`. - if iter - .next() - .is_some_and(|s| s == OsStr::new("rmake.rs") || s == OsStr::new("Makefile")) - && iter.next().is_none() - { + // We skip the test folder and check if the user passed `rmake.rs`. + if iter.next().is_some_and(|s| s == "rmake.rs") && iter.next().is_none() { path.parent().unwrap().to_str().unwrap().to_string() } else { f.to_string() @@ -320,6 +322,7 @@ pub fn parse_config(args: Vec<String>) -> Config { run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), rustc_path: opt_path(matches, "rustc-path"), cargo_path: matches.opt_str("cargo-path").map(PathBuf::from), + stage0_rustc_path: matches.opt_str("stage0-rustc-path").map(PathBuf::from), rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from), coverage_dump_path: matches.opt_str("coverage-dump-path").map(PathBuf::from), python: matches.opt_str("python").unwrap(), @@ -776,16 +779,9 @@ fn collect_tests_from_dir( return Ok(()); } - // For run-make tests, a "test file" is actually a directory that contains - // an `rmake.rs` or `Makefile`" + // For run-make tests, a "test file" is actually a directory that contains an `rmake.rs`. if cx.config.mode == Mode::RunMake { - if dir.join("Makefile").exists() && dir.join("rmake.rs").exists() { - return Err(io::Error::other( - "run-make tests cannot have both `Makefile` and `rmake.rs`", - )); - } - - if dir.join("Makefile").exists() || dir.join("rmake.rs").exists() { + if dir.join("rmake.rs").exists() { let paths = TestPaths { file: dir.to_path_buf(), relative_dir: relative_dir_path.parent().unwrap().to_path_buf(), @@ -854,24 +850,14 @@ pub fn is_test(file_name: &OsString) -> bool { !invalid_prefixes.iter().any(|p| file_name.starts_with(p)) } -/// For a single test file, creates one or more test structures (one per revision) -/// that can be handed over to libtest to run, possibly in parallel. +/// For a single test file, creates one or more test structures (one per revision) that can be +/// handed over to libtest to run, possibly in parallel. fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &TestPaths) { - // For run-make tests, each "test file" is actually a _directory_ containing - // an `rmake.rs` or `Makefile`. But for the purposes of directive parsing, - // we want to look at that recipe file, not the directory itself. + // For run-make tests, each "test file" is actually a _directory_ containing an `rmake.rs`. But + // for the purposes of directive parsing, we want to look at that recipe file, not the directory + // itself. let test_path = if cx.config.mode == Mode::RunMake { - if testpaths.file.join("rmake.rs").exists() && testpaths.file.join("Makefile").exists() { - panic!("run-make tests cannot have both `rmake.rs` and `Makefile`"); - } - - if testpaths.file.join("rmake.rs").exists() { - // Parse directives in rmake.rs. - testpaths.file.join("rmake.rs") - } else { - // Parse directives in the Makefile. - testpaths.file.join("Makefile") - } + testpaths.file.join("rmake.rs") } else { PathBuf::from(&testpaths.file) }; diff --git a/src/tools/compiletest/src/raise_fd_limit.rs b/src/tools/compiletest/src/raise_fd_limit.rs index 4445ecb7ce8..7b12ba946b9 100644 --- a/src/tools/compiletest/src/raise_fd_limit.rs +++ b/src/tools/compiletest/src/raise_fd_limit.rs @@ -7,7 +7,6 @@ #[cfg(target_vendor = "apple")] #[allow(non_camel_case_types)] pub unsafe fn raise_fd_limit() { - use std::mem::size_of_val; use std::ptr::null_mut; use std::{cmp, io}; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index f36d43b211f..6e250ca12c9 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2412,8 +2412,9 @@ impl<'test> TestCx<'test> { let rust_src_dir = rust_src_dir.read_link().unwrap_or(rust_src_dir.to_path_buf()); normalize_path(&rust_src_dir.join("library"), "$SRC_DIR_REAL"); - // eg. /home/user/rust/build/x86_64-unknown-linux-gnu/test/ui - normalize_path(&self.config.build_test_suite_root, "$TEST_BUILD_DIR"); + // eg. + // /home/user/rust/build/x86_64-unknown-linux-gnu/test/ui/<test_dir>/$name.$revision.$mode/ + normalize_path(&self.output_base_dir(), "$TEST_BUILD_DIR"); // eg. /home/user/rust/build normalize_path(&self.config.build_root, "$BUILD_DIR"); @@ -2434,6 +2435,18 @@ impl<'test> TestCx<'test> { .into_owned(); normalized = Self::normalize_platform_differences(&normalized); + + // Normalize long type name hash. + normalized = + static_regex!(r"\$TEST_BUILD_DIR/(?P<filename>[^\.]+).long-type-(?P<hash>\d+).txt") + .replace_all(&normalized, |caps: &Captures<'_>| { + format!( + "$TEST_BUILD_DIR/{filename}.long-type-$LONG_TYPE_HASH.txt", + filename = &caps["filename"] + ) + }) + .into_owned(); + normalized = normalized.replace("\t", "\\t"); // makes tabs visible // Remove test annotations like `//~ ERROR text` from the output, diff --git a/src/tools/compiletest/src/runtest/crashes.rs b/src/tools/compiletest/src/runtest/crashes.rs index 885ed3b08fa..da1e74b4a56 100644 --- a/src/tools/compiletest/src/runtest/crashes.rs +++ b/src/tools/compiletest/src/runtest/crashes.rs @@ -15,7 +15,7 @@ impl TestCx<'_> { // if a test does not crash, consider it an error if proc_res.status.success() || matches!(proc_res.status.code(), Some(1 | 0)) { self.fatal(&format!( - "crashtest no longer crashes/triggers ICE, horray! Please give it a meaningful \ + "crashtest no longer crashes/triggers ICE, hooray! Please give it a meaningful \ name, add a doc-comment to the start of the test explaining why it exists and \ move it to tests/ui or wherever you see fit. Adding 'Fixes #<issueNr>' to your PR \ description ensures that the corresponding ticket is auto-closed upon merge. \ diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index 9bb3993223e..073116933bd 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -9,171 +9,10 @@ use crate::util::{copy_dir_all, dylib_env_var}; impl TestCx<'_> { pub(super) fn run_rmake_test(&self) { - let test_dir = &self.testpaths.file; - if test_dir.join("rmake.rs").exists() { - self.run_rmake_v2_test(); - } else if test_dir.join("Makefile").exists() { - self.run_rmake_legacy_test(); - } else { - self.fatal("failed to find either `rmake.rs` or `Makefile`") - } - } - - fn run_rmake_legacy_test(&self) { - let cwd = env::current_dir().unwrap(); - - // FIXME(Zalathar): This should probably be `output_base_dir` to avoid - // an unnecessary extra subdirectory, but since legacy Makefile tests - // are hopefully going away, it seems safer to leave this perilous code - // as-is until it can all be deleted. - let tmpdir = cwd.join(self.output_base_name()); - ignore_not_found(|| recursive_remove(&tmpdir)).unwrap(); - - fs::create_dir_all(&tmpdir).unwrap(); - - let host = &self.config.host; - let make = if host.contains("dragonfly") - || host.contains("freebsd") - || host.contains("netbsd") - || host.contains("openbsd") - || host.contains("aix") - { - "gmake" - } else { - "make" - }; - - let mut cmd = Command::new(make); - cmd.current_dir(&self.testpaths.file) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .env("TARGET", &self.config.target) - .env("PYTHON", &self.config.python) - .env("S", &self.config.src_root) - .env("RUST_BUILD_STAGE", &self.config.stage_id) - .env("RUSTC", cwd.join(&self.config.rustc_path)) - .env("TMPDIR", &tmpdir) - .env("LD_LIB_PATH_ENVVAR", dylib_env_var()) - .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path)) - .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path)) - .env("LLVM_COMPONENTS", &self.config.llvm_components) - // We for sure don't want these tests to run in parallel, so make - // sure they don't have access to these vars if we run via `make` - // at the top level - .env_remove("MAKEFLAGS") - .env_remove("MFLAGS") - .env_remove("CARGO_MAKEFLAGS"); - - if let Some(ref cargo) = self.config.cargo_path { - cmd.env("CARGO", cwd.join(cargo)); - } - - if let Some(ref rustdoc) = self.config.rustdoc_path { - cmd.env("RUSTDOC", cwd.join(rustdoc)); - } - - if let Some(ref node) = self.config.nodejs { - cmd.env("NODE", node); - } - - if let Some(ref linker) = self.config.target_linker { - cmd.env("RUSTC_LINKER", linker); - } - - if let Some(ref clang) = self.config.run_clang_based_tests_with { - cmd.env("CLANG", clang); - } - - if let Some(ref filecheck) = self.config.llvm_filecheck { - cmd.env("LLVM_FILECHECK", filecheck); - } - - if let Some(ref llvm_bin_dir) = self.config.llvm_bin_dir { - cmd.env("LLVM_BIN_DIR", llvm_bin_dir); - } - - if let Some(ref remote_test_client) = self.config.remote_test_client { - cmd.env("REMOTE_TEST_CLIENT", remote_test_client); - } - - // We don't want RUSTFLAGS set from the outside to interfere with - // compiler flags set in the test cases: - cmd.env_remove("RUSTFLAGS"); - - // Use dynamic musl for tests because static doesn't allow creating dylibs - if self.config.host.contains("musl") { - cmd.env("RUSTFLAGS", "-Ctarget-feature=-crt-static").env("IS_MUSL_HOST", "1"); - } - - if self.config.bless { - cmd.env("RUSTC_BLESS_TEST", "--bless"); - // Assume this option is active if the environment variable is "defined", with _any_ value. - // As an example, a `Makefile` can use this option by: - // - // ifdef RUSTC_BLESS_TEST - // cp "$(TMPDIR)"/actual_something.ext expected_something.ext - // else - // $(DIFF) expected_something.ext "$(TMPDIR)"/actual_something.ext - // endif - } - - if self.config.target.contains("msvc") && !self.config.cc.is_empty() { - // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` - // and that `lib.exe` lives next to it. - let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe"); - - // MSYS doesn't like passing flags of the form `/foo` as it thinks it's - // a path and instead passes `C:\msys64\foo`, so convert all - // `/`-arguments to MSVC here to `-` arguments. - let cflags = self - .config - .cflags - .split(' ') - .map(|s| s.replace("/", "-")) - .collect::<Vec<_>>() - .join(" "); - let cxxflags = self - .config - .cxxflags - .split(' ') - .map(|s| s.replace("/", "-")) - .collect::<Vec<_>>() - .join(" "); - - cmd.env("IS_MSVC", "1") - .env("IS_WINDOWS", "1") - .env("MSVC_LIB", format!("'{}' -nologo", lib.display())) - .env("MSVC_LIB_PATH", format!("{}", lib.display())) - .env("CC", format!("'{}' {}", self.config.cc, cflags)) - .env("CXX", format!("'{}' {}", &self.config.cxx, cxxflags)); - } else { - cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags)) - .env("CXX", format!("{} {}", self.config.cxx, self.config.cxxflags)) - .env("AR", &self.config.ar); - - if self.config.target.contains("windows") { - cmd.env("IS_WINDOWS", "1"); - } - } - - let (output, truncated) = - self.read2_abbreviated(cmd.spawn().expect("failed to spawn `make`")); - if !output.status.success() { - let res = ProcRes { - status: output.status, - stdout: String::from_utf8_lossy(&output.stdout).into_owned(), - stderr: String::from_utf8_lossy(&output.stderr).into_owned(), - truncated, - cmdline: format!("{:?}", cmd), - }; - self.fatal_proc_rec("make failed", &res); - } - } - - fn run_rmake_v2_test(&self) { // For `run-make` V2, we need to perform 2 steps to build and run a `run-make` V2 recipe // (`rmake.rs`) to run the actual tests. The support library is already built as a tool rust - // library and is available under `build/$TARGET/stageN-tools-bin/librun_make_support.rlib`. + // library and is available under + // `build/$HOST/stage0-bootstrap-tools/$TARGET/release/librun_make_support.rlib`. // // 1. We need to build the recipe `rmake.rs` as a binary and link in the `run_make_support` // library. @@ -191,8 +30,6 @@ impl TestCx<'_> { // recipes to `remove_dir_all($TMPDIR)` without running into issues related trying to remove // a currently running executable because the recipe executable is not under the // `rmake_out/` directory. - // - // This setup intentionally diverges from legacy Makefile run-make tests. let base_dir = self.output_base_dir(); ignore_not_found(|| recursive_remove(&base_dir)).unwrap(); @@ -224,25 +61,21 @@ impl TestCx<'_> { // // ``` // build/<target_triple>/ - // ├── stageN-tools-bin/ - // │ └── librun_make_support.rlib // <- support rlib itself - // ├── stageN-tools/ - // │ ├── release/deps/ // <- deps of deps - // │ └── <host_triple>/release/deps/ // <- deps + // ├── stage0-bootstrap-tools/ + // │ ├── <host_triple>/release/librun_make_support.rlib // <- support rlib itself + // │ ├── <host_triple>/release/deps/ // <- deps + // │ └── release/deps/ // <- deps of deps // ``` // // FIXME(jieyouxu): there almost certainly is a better way to do this (specifically how the - // support lib and its deps are organized, can't we copy them to the tools-bin dir as - // well?), but this seems to work for now. + // support lib and its deps are organized), but this seems to work for now. - let stage_number = self.config.stage; + let tools_bin = host_build_root.join("stage0-bootstrap-tools"); + let support_host_path = tools_bin.join(&self.config.host).join("release"); + let support_lib_path = support_host_path.join("librun_make_support.rlib"); - let stage_tools_bin = host_build_root.join(format!("stage{stage_number}-tools-bin")); - let support_lib_path = stage_tools_bin.join("librun_make_support.rlib"); - - let stage_tools = host_build_root.join(format!("stage{stage_number}-tools")); - let support_lib_deps = stage_tools.join(&self.config.host).join("release").join("deps"); - let support_lib_deps_deps = stage_tools.join("release").join("deps"); + let support_lib_deps = support_host_path.join("deps"); + let support_lib_deps_deps = tools_bin.join("release").join("deps"); // To compile the recipe with rustc, we need to provide suitable dynamic library search // paths to rustc. This includes both: @@ -253,12 +86,6 @@ impl TestCx<'_> { let base_dylib_search_paths = Vec::from_iter(env::split_paths(&env::var(dylib_env_var()).unwrap())); - let host_dylib_search_paths = { - let mut paths = vec![self.config.compile_lib_path.clone()]; - paths.extend(base_dylib_search_paths.iter().cloned()); - paths - }; - // Calculate the paths of the recipe binary. As previously discussed, this is placed at // `<base_dir>/<bin_name>` with `bin_name` being `rmake` or `rmake.exe` depending on // platform. @@ -268,8 +95,21 @@ impl TestCx<'_> { p }; - let mut rustc = Command::new(&self.config.rustc_path); + // run-make-support and run-make tests are compiled using the stage0 compiler + // If the stage is 0, then the compiler that we test (either bootstrap or an explicitly + // set compiler) is the one that actually compiled run-make-support. + let stage0_rustc = self + .config + .stage0_rustc_path + .as_ref() + .expect("stage0 rustc is required to run run-make tests"); + let mut rustc = Command::new(&stage0_rustc); rustc + // `rmake.rs` **must** be buildable by a stable compiler, it may not use *any* unstable + // library or compiler features. Here, we force the stage 0 rustc to consider itself as + // a stable-channel compiler via `RUSTC_BOOTSTRAP=-1` to prevent *any* unstable + // library/compiler usages, even if stage 0 rustc is *actually* a nightly rustc. + .env("RUSTC_BOOTSTRAP", "-1") .arg("-o") .arg(&recipe_bin) // Specify library search paths for `run_make_support`. @@ -282,35 +122,12 @@ impl TestCx<'_> { .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy())) .arg("--edition=2021") .arg(&self.testpaths.file.join("rmake.rs")) - .arg("-Cprefer-dynamic") - // Provide necessary library search paths for rustc. - .env(dylib_env_var(), &env::join_paths(host_dylib_search_paths).unwrap()); + .arg("-Cprefer-dynamic"); // In test code we want to be very pedantic about values being silently discarded that are // annotated with `#[must_use]`. rustc.arg("-Dunused_must_use"); - // > `cg_clif` uses `COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0` for running the rustc - // > test suite. With the introduction of rmake.rs this broke. `librun_make_support.rlib` is - // > compiled using the bootstrap rustc wrapper which sets `--sysroot - // > build/aarch64-unknown-linux-gnu/stage0-sysroot`, but then compiletest will compile - // > `rmake.rs` using the sysroot of the bootstrap compiler causing it to not find the - // > `libstd.rlib` against which `librun_make_support.rlib` is compiled. - // - // The gist here is that we have to pass the proper stage0 sysroot if we want - // - // ``` - // $ COMPILETEST_FORCE_STAGE0=1 ./x test run-make --stage 0 - // ``` - // - // to work correctly. - // - // See <https://github.com/rust-lang/rust/pull/122248> for more background. - let stage0_sysroot = host_build_root.join("stage0-sysroot"); - if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() { - rustc.arg("--sysroot").arg(&stage0_sysroot); - } - // Now run rustc to build the recipe. let res = self.run_command_to_procres(&mut rustc); if !res.status.success() { @@ -320,35 +137,24 @@ impl TestCx<'_> { // To actually run the recipe, we have to provide the recipe with a bunch of information // provided through env vars. - // Compute stage-specific standard library paths. - let stage_std_path = host_build_root.join(format!("stage{stage_number}")).join("lib"); - // Compute dynamic library search paths for recipes. + // These dylib directories are needed to **execute the recipe**. let recipe_dylib_search_paths = { let mut paths = base_dylib_search_paths.clone(); - - // For stage 0, we need to explicitly include the stage0-sysroot libstd dylib. - // See <https://github.com/rust-lang/rust/issues/135373>. - if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() { - paths.push( - stage0_sysroot.join("lib").join("rustlib").join(&self.config.host).join("lib"), - ); - } - - paths.push(support_lib_path.parent().unwrap().to_path_buf()); - paths.push(stage_std_path.join("rustlib").join(&self.config.host).join("lib")); - paths - }; - - // Compute runtime library search paths for recipes. This is target-specific. - let target_runtime_dylib_search_paths = { - let mut paths = vec![rmake_out_dir.clone()]; - paths.extend(base_dylib_search_paths.iter().cloned()); + paths.push( + stage0_rustc + .parent() + .unwrap() + .parent() + .unwrap() + .join("lib") + .join("rustlib") + .join(&self.config.host) + .join("lib"), + ); paths }; - // FIXME(jieyouxu): please rename `TARGET_RPATH_ENV`, `HOST_RPATH_DIR` and - // `TARGET_RPATH_DIR`, it is **extremely** confusing! let mut cmd = Command::new(&recipe_bin); cmd.current_dir(&rmake_out_dir) .stdout(Stdio::piped()) @@ -357,9 +163,14 @@ impl TestCx<'_> { // example, this could be `LD_LIBRARY_PATH` on some linux distros but `PATH` on Windows. .env("LD_LIB_PATH_ENVVAR", dylib_env_var()) // Provide the dylib search paths. + // This is required to run the **recipe** itself. .env(dylib_env_var(), &env::join_paths(recipe_dylib_search_paths).unwrap()) - // Provide runtime dylib search paths. - .env("TARGET_RPATH_ENV", &env::join_paths(target_runtime_dylib_search_paths).unwrap()) + // Provide the directory to libraries that are needed to run the *compiler* invoked + // by the recipe. + .env("HOST_RUSTC_DYLIB_PATH", &self.config.compile_lib_path) + // Provide the directory to libraries that might be needed to run binaries created + // by a compiler invoked by the recipe. + .env("TARGET_EXE_DYLIB_PATH", &self.config.run_lib_path) // Provide the target. .env("TARGET", &self.config.target) // Some tests unfortunately still need Python, so provide path to a Python interpreter. @@ -370,13 +181,6 @@ impl TestCx<'_> { .env("BUILD_ROOT", &host_build_root) // Provide path to stage-corresponding rustc. .env("RUSTC", &self.config.rustc_path) - // Provide the directory to libraries that are needed to run the *compiler*. This is not - // to be confused with `TARGET_RPATH_ENV` or `TARGET_RPATH_DIR`. This is needed if the - // recipe wants to invoke rustc. - .env("HOST_RPATH_DIR", &self.config.compile_lib_path) - // Provide the directory to libraries that might be needed to run compiled binaries - // (further compiled by the recipe!). - .env("TARGET_RPATH_DIR", &self.config.run_lib_path) // Provide which LLVM components are available (e.g. which LLVM components are provided // through a specific CI runner). .env("LLVM_COMPONENTS", &self.config.llvm_components); diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 7bfa7e3355d..54249fbd9ae 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; use std::process::ExitCode; -use std::sync::OnceLock; +use std::sync::LazyLock; use std::{env, fs}; use regex::{Regex, RegexBuilder}; @@ -151,8 +151,7 @@ impl CommandKind { } } -static LINE_PATTERN: OnceLock<Regex> = OnceLock::new(); -fn line_pattern() -> Regex { +static LINE_PATTERN: LazyLock<Regex> = LazyLock::new(|| { RegexBuilder::new( r#" //@\s+ @@ -165,7 +164,19 @@ fn line_pattern() -> Regex { .unicode(true) .build() .unwrap() -} +}); + +static DEPRECATED_LINE_PATTERN: LazyLock<Regex> = LazyLock::new(|| { + RegexBuilder::new( + r#" + //\s+@ + "#, + ) + .ignore_whitespace(true) + .unicode(true) + .build() + .unwrap() +}); fn print_err(msg: &str, lineno: usize) { eprintln!("Invalid command: {} on line {}", msg, lineno) @@ -184,21 +195,23 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> { for (lineno, line) in file.split('\n').enumerate() { let lineno = lineno + 1; - let cap = match LINE_PATTERN.get_or_init(line_pattern).captures(line) { - Some(c) => c, - None => continue, + if DEPRECATED_LINE_PATTERN.is_match(line) { + print_err("Deprecated command syntax, replace `// @` with `//@ `", lineno); + errors = true; + continue; + } + + let Some(cap) = LINE_PATTERN.captures(line) else { + continue; }; - let negated = cap.name("negated").unwrap().as_str() == "!"; + let negated = &cap["negated"] == "!"; let args_str = &cap["args"]; - let args = match shlex::split(args_str) { - Some(args) => args, - None => { - print_err(&format!("Invalid arguments to shlex::split: `{args_str}`",), lineno); - errors = true; - continue; - } + let Some(args) = shlex::split(args_str) else { + print_err(&format!("Invalid arguments to shlex::split: `{args_str}`",), lineno); + errors = true; + continue; }; if let Some((kind, path)) = CommandKind::parse(&cap["cmd"], negated, &args) { diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index a4f2a117b18..ff3a25e94bd 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -285,9 +285,19 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { - fn expose_ptr(&self, alloc_id: AllocId, tag: BorTag) -> InterpResult<'tcx> { + fn expose_provenance(&self, provenance: Provenance) -> InterpResult<'tcx> { let this = self.eval_context_ref(); let mut global_state = this.machine.alloc_addresses.borrow_mut(); + + let (alloc_id, tag) = match provenance { + Provenance::Concrete { alloc_id, tag } => (alloc_id, tag), + Provenance::Wildcard => { + // No need to do anything for wildcard pointers as + // their provenances have already been previously exposed. + return interp_ok(()); + } + }; + // In strict mode, we don't need this, so we can save some cycles by not tracking it. if global_state.provenance_mode == ProvenanceMode::Strict { return interp_ok(()); @@ -422,6 +432,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let rel_offset = this.truncate_to_target_usize(addr.bytes().wrapping_sub(base_addr)); Some((alloc_id, Size::from_bytes(rel_offset))) } + + /// Prepare all exposed memory for a native call. + /// This overapproximates the modifications which external code might make to memory: + /// We set all reachable allocations as initialized, mark all reachable provenances as exposed + /// and overwrite them with `Provenance::WILDCARD`. + fn prepare_exposed_for_native_call(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + // We need to make a deep copy of this list, but it's fine; it also serves as scratch space + // for the search within `prepare_for_native_call`. + let exposed: Vec<AllocId> = + this.machine.alloc_addresses.get_mut().exposed.iter().copied().collect(); + this.prepare_for_native_call(exposed) + } } impl<'tcx> MiriMachine<'tcx> { diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 4ece8f7895d..dbb092f6728 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1291,18 +1291,12 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { /// Called on `ptr as usize` casts. /// (Actually computing the resulting `usize` doesn't need machine help, /// that's just `Scalar::try_to_int`.) + #[inline(always)] fn expose_provenance( ecx: &InterpCx<'tcx, Self>, provenance: Self::Provenance, ) -> InterpResult<'tcx> { - match provenance { - Provenance::Concrete { alloc_id, tag } => ecx.expose_ptr(alloc_id, tag), - Provenance::Wildcard => { - // No need to do anything for wildcard pointers as - // their provenances have already been previously exposed. - interp_ok(()) - } - } + ecx.expose_provenance(provenance) } /// Convert a pointer with provenance into an allocation-offset pair and extra provenance info. diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs index 8c9e1860f31..c6fcb0355eb 100644 --- a/src/tools/miri/src/shims/native_lib.rs +++ b/src/tools/miri/src/shims/native_lib.rs @@ -160,16 +160,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } let imm = this.read_immediate(arg)?; libffi_args.push(imm_to_carg(&imm, this)?); - // If we are passing a pointer, prepare the memory it points to. + // If we are passing a pointer, expose its provenance. Below, all exposed memory + // (previously exposed and new exposed) will then be properly prepared. if matches!(arg.layout.ty.kind(), ty::RawPtr(..)) { let ptr = imm.to_scalar().to_pointer(this)?; let Some(prov) = ptr.provenance else { - // Pointer without provenance may not access any memory. - continue; - }; - // We use `get_alloc_id` for its best-effort behaviour with Wildcard provenance. - let Some(alloc_id) = prov.get_alloc_id() else { - // Wildcard pointer, whatever it points to must be already exposed. + // Pointer without provenance may not access any memory anyway, skip. continue; }; // The first time this happens, print a warning. @@ -178,12 +174,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.emit_diagnostic(NonHaltingDiagnostic::NativeCallSharedMem); } - this.prepare_for_native_call(alloc_id, prov)?; + this.expose_provenance(prov)?; } } - // FIXME: In the future, we should also call `prepare_for_native_call` on all previously - // exposed allocations, since C may access any of them. + // Prepare all exposed memory. + this.prepare_exposed_for_native_call()?; // Convert them to `libffi::high::Arg` type. let libffi_args = libffi_args diff --git a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr index e611d6e28f8..75167ab5b38 100644 --- a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr +++ b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr @@ -1,5 +1,5 @@ error: unsupported operation: `open` not available when isolation is enabled - --> RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC + --> RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC | LL | let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `open` not available when isolation is enabled @@ -7,14 +7,14 @@ LL | let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode a = help: set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation; = help: or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning = note: BACKTRACE: - = note: inside closure at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::cvt_r::<i32, {closure@std::sys::pal::PLATFORM::fs::File::open_c::{closure#0}}>` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::fs::File::open_c` at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack::<std::sys::pal::PLATFORM::fs::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::<std::sys::pal::PLATFORM::fs::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::small_c_string::run_path_with_cstr::<std::sys::pal::PLATFORM::fs::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::fs::File::open` at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + = note: inside `std::sys::pal::PLATFORM::cvt_r::<i32, {closure@std::sys::fs::PLATFORM::File::open_c::{closure#0}}>` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + = note: inside `std::sys::fs::PLATFORM::File::open_c` at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack::<std::sys::fs::PLATFORM::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC + = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::<std::sys::fs::PLATFORM::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC + = note: inside `std::sys::pal::PLATFORM::small_c_string::run_path_with_cstr::<std::sys::fs::PLATFORM::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC + = note: inside `std::sys::fs::PLATFORM::File::open` at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC = note: inside `std::fs::OpenOptions::_open` at RUSTLIB/std/src/fs.rs:LL:CC = note: inside `std::fs::OpenOptions::open::<&std::path::Path>` at RUSTLIB/std/src/fs.rs:LL:CC = note: inside `std::fs::File::open::<&str>` at RUSTLIB/std/src/fs.rs:LL:CC diff --git a/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs b/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs index a92e63a4da6..bd4e0b23601 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs +++ b/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs @@ -6,7 +6,7 @@ #![feature(box_as_ptr)] use std::mem::MaybeUninit; -use std::ptr::null; +use std::ptr; fn main() { test_increment_int(); @@ -20,6 +20,8 @@ fn main() { test_pass_dangling(); test_swap_ptr_triple_dangling(); test_return_ptr(); + test_pass_ptr_as_int(); + test_pass_ptr_via_previously_shared_mem(); } /// Test function that modifies an int. @@ -112,7 +114,7 @@ fn test_swap_ptr() { } let x = 61; - let (mut ptr0, mut ptr1) = (&raw const x, null()); + let (mut ptr0, mut ptr1) = (&raw const x, ptr::null()); unsafe { swap_ptr(&mut ptr0, &mut ptr1) }; assert_eq!(unsafe { *ptr1 }, x); @@ -131,7 +133,7 @@ fn test_swap_ptr_tuple() { } let x = 71; - let mut tuple = Tuple { ptr0: &raw const x, ptr1: null() }; + let mut tuple = Tuple { ptr0: &raw const x, ptr1: ptr::null() }; unsafe { swap_ptr_tuple(&mut tuple) } assert_eq!(unsafe { *tuple.ptr1 }, x); @@ -148,7 +150,7 @@ fn test_overwrite_dangling() { drop(b); unsafe { overwrite_ptr(&mut ptr) }; - assert_eq!(ptr, null()); + assert_eq!(ptr, ptr::null()); } /// Test function that passes a dangling pointer. @@ -200,3 +202,33 @@ fn test_return_ptr() { let ptr = unsafe { return_ptr(ptr) }; assert_eq!(unsafe { *ptr }, x); } + +/// Test casting a pointer to an integer and passing that to C. +fn test_pass_ptr_as_int() { + extern "C" { + fn pass_ptr_as_int(ptr: usize, set_to_val: i32); + } + + let mut m: MaybeUninit<i32> = MaybeUninit::uninit(); + unsafe { pass_ptr_as_int(m.as_mut_ptr() as usize, 42) }; + assert_eq!(unsafe { m.assume_init() }, 42); +} + +fn test_pass_ptr_via_previously_shared_mem() { + extern "C" { + fn set_shared_mem(ptr: *mut *mut i32); + fn init_ptr_stored_in_shared_mem(val: i32); + } + + let mut m: *mut i32 = ptr::null_mut(); + let ptr_to_m = &raw mut m; + unsafe { set_shared_mem(&raw mut m) }; + + let mut m2: MaybeUninit<i32> = MaybeUninit::uninit(); + // Store a pointer to m2 somewhere that C code can access it. + unsafe { ptr_to_m.write(m2.as_mut_ptr()) }; + // Have C code write there. + unsafe { init_ptr_stored_in_shared_mem(42) }; + // Ensure this memory is now considered initialized. + assert_eq!(unsafe { m2.assume_init() }, 42); +} diff --git a/src/tools/miri/tests/native-lib/ptr_read_access.c b/src/tools/miri/tests/native-lib/ptr_read_access.c index 3b427d6033e..b89126d3d7c 100644 --- a/src/tools/miri/tests/native-lib/ptr_read_access.c +++ b/src/tools/miri/tests/native-lib/ptr_read_access.c @@ -1,33 +1,34 @@ #include <stdio.h> +#include <stdint.h> // See comments in build_native_lib() #define EXPORT __attribute__((visibility("default"))) /* Test: test_access_pointer */ -EXPORT void print_pointer(const int *ptr) { +EXPORT void print_pointer(const int32_t *ptr) { printf("printing pointer dereference from C: %d\n", *ptr); } /* Test: test_access_simple */ typedef struct Simple { - int field; + int32_t field; } Simple; -EXPORT int access_simple(const Simple *s_ptr) { +EXPORT int32_t access_simple(const Simple *s_ptr) { return s_ptr->field; } /* Test: test_access_nested */ typedef struct Nested { - int value; + int32_t value; struct Nested *next; } Nested; // Returns the innermost/last value of a Nested pointer chain. -EXPORT int access_nested(const Nested *n_ptr) { +EXPORT int32_t access_nested(const Nested *n_ptr) { // Edge case: `n_ptr == NULL` (i.e. first Nested is None). if (!n_ptr) { return 0; } @@ -41,10 +42,10 @@ EXPORT int access_nested(const Nested *n_ptr) { /* Test: test_access_static */ typedef struct Static { - int value; + int32_t value; struct Static *recurse; } Static; -EXPORT int access_static(const Static *s_ptr) { +EXPORT int32_t access_static(const Static *s_ptr) { return s_ptr->recurse->recurse->value; } diff --git a/src/tools/miri/tests/native-lib/ptr_write_access.c b/src/tools/miri/tests/native-lib/ptr_write_access.c index b54c5d86b21..fd8b005499c 100644 --- a/src/tools/miri/tests/native-lib/ptr_write_access.c +++ b/src/tools/miri/tests/native-lib/ptr_write_access.c @@ -1,23 +1,24 @@ #include <stddef.h> +#include <stdint.h> // See comments in build_native_lib() #define EXPORT __attribute__((visibility("default"))) /* Test: test_increment_int */ -EXPORT void increment_int(int *ptr) { +EXPORT void increment_int(int32_t *ptr) { *ptr += 1; } /* Test: test_init_int */ -EXPORT void init_int(int *ptr, int val) { +EXPORT void init_int(int32_t *ptr, int32_t val) { *ptr = val; } /* Test: test_init_array */ -EXPORT void init_array(int *array, size_t len, int val) { +EXPORT void init_array(int32_t *array, size_t len, int32_t val) { for (size_t i = 0; i < len; i++) { array[i] = val; } @@ -26,28 +27,28 @@ EXPORT void init_array(int *array, size_t len, int val) { /* Test: test_init_static_inner */ typedef struct SyncPtr { - int *ptr; + int32_t *ptr; } SyncPtr; -EXPORT void init_static_inner(const SyncPtr *s_ptr, int val) { +EXPORT void init_static_inner(const SyncPtr *s_ptr, int32_t val) { *(s_ptr->ptr) = val; } /* Tests: test_exposed, test_pass_dangling */ -EXPORT void ignore_ptr(__attribute__((unused)) const int *ptr) { +EXPORT void ignore_ptr(__attribute__((unused)) const int32_t *ptr) { return; } /* Test: test_expose_int */ -EXPORT void expose_int(const int *int_ptr, const int **pptr) { +EXPORT void expose_int(const int32_t *int_ptr, const int32_t **pptr) { *pptr = int_ptr; } /* Test: test_swap_ptr */ -EXPORT void swap_ptr(const int **pptr0, const int **pptr1) { - const int *tmp = *pptr0; +EXPORT void swap_ptr(const int32_t **pptr0, const int32_t **pptr1) { + const int32_t *tmp = *pptr0; *pptr0 = *pptr1; *pptr1 = tmp; } @@ -55,36 +56,54 @@ EXPORT void swap_ptr(const int **pptr0, const int **pptr1) { /* Test: test_swap_ptr_tuple */ typedef struct Tuple { - int *ptr0; - int *ptr1; + int32_t *ptr0; + int32_t *ptr1; } Tuple; EXPORT void swap_ptr_tuple(Tuple *t_ptr) { - int *tmp = t_ptr->ptr0; + int32_t *tmp = t_ptr->ptr0; t_ptr->ptr0 = t_ptr->ptr1; t_ptr->ptr1 = tmp; } /* Test: test_overwrite_dangling */ -EXPORT void overwrite_ptr(const int **pptr) { +EXPORT void overwrite_ptr(const int32_t **pptr) { *pptr = NULL; } /* Test: test_swap_ptr_triple_dangling */ typedef struct Triple { - int *ptr0; - int *ptr1; - int *ptr2; + int32_t *ptr0; + int32_t *ptr1; + int32_t *ptr2; } Triple; EXPORT void swap_ptr_triple_dangling(Triple *t_ptr) { - int *tmp = t_ptr->ptr0; + int32_t *tmp = t_ptr->ptr0; t_ptr->ptr0 = t_ptr->ptr2; t_ptr->ptr2 = tmp; } -EXPORT const int *return_ptr(const int *ptr) { +EXPORT const int32_t *return_ptr(const int32_t *ptr) { return ptr; } + +/* Test: test_pass_ptr_as_int */ + +EXPORT void pass_ptr_as_int(uintptr_t ptr, int32_t set_to_val) { + *(int32_t*)ptr = set_to_val; +} + +/* Test: test_pass_ptr_via_previously_shared_mem */ + +int32_t** shared_place; + +EXPORT void set_shared_mem(int32_t** ptr) { + shared_place = ptr; +} + +EXPORT void init_ptr_stored_in_shared_mem(int32_t val) { + **shared_place = val; +} diff --git a/src/tools/miri/tests/native-lib/scalar_arguments.c b/src/tools/miri/tests/native-lib/scalar_arguments.c index 6da730a4987..acccf06f3df 100644 --- a/src/tools/miri/tests/native-lib/scalar_arguments.c +++ b/src/tools/miri/tests/native-lib/scalar_arguments.c @@ -1,9 +1,10 @@ #include <stdio.h> +#include <stdint.h> // See comments in build_native_lib() #define EXPORT __attribute__((visibility("default"))) -EXPORT int add_one_int(int x) { +EXPORT int32_t add_one_int(int32_t x) { return 2 + x; } @@ -13,23 +14,23 @@ EXPORT void printer(void) { // function with many arguments, to test functionality when some args are stored // on the stack -EXPORT int test_stack_spill(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l) { +EXPORT int32_t test_stack_spill(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, int32_t f, int32_t g, int32_t h, int32_t i, int32_t j, int32_t k, int32_t l) { return a+b+c+d+e+f+g+h+i+j+k+l; } -EXPORT unsigned int get_unsigned_int(void) { +EXPORT uint32_t get_unsigned_int(void) { return -10; } -EXPORT short add_int16(short x) { +EXPORT short add_int16(int16_t x) { return x + 3; } -EXPORT long add_short_to_long(short x, long y) { +EXPORT long add_short_to_long(int16_t x, int64_t y) { return x + y; } // To test that functions not marked with EXPORT cannot be called by Miri. -int not_exported(void) { +int32_t not_exported(void) { return 0; } diff --git a/src/tools/miri/tests/pass/unsized.rs b/src/tools/miri/tests/pass/unsized.rs index 5c6929882f6..6ad06354302 100644 --- a/src/tools/miri/tests/pass/unsized.rs +++ b/src/tools/miri/tests/pass/unsized.rs @@ -1,22 +1,8 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows -#![feature(unsized_tuple_coercion)] #![feature(unsized_fn_params)] #![feature(custom_mir, core_intrinsics)] -use std::mem; - -fn unsized_tuple() { - let x: &(i32, i32, [i32]) = &(0, 1, [2, 3]); - let y: &(i32, i32, [i32]) = &(0, 1, [2, 3, 4]); - let mut a = [y, x]; - a.sort(); - assert_eq!(a, [x, y]); - - assert_eq!(&format!("{:?}", a), "[(0, 1, [2, 3]), (0, 1, [2, 3, 4])]"); - assert_eq!(mem::size_of_val(x), 16); -} - fn unsized_params() { pub fn f0(_f: dyn FnOnce()) {} pub fn f1(_s: str) {} @@ -56,7 +42,6 @@ fn unsized_field_projection() { } fn main() { - unsized_tuple(); unsized_params(); unsized_field_projection(); } diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs index 85ce38f57d6..c37cf15d40a 100644 --- a/src/tools/miri/tests/ui.rs +++ b/src/tools/miri/tests/ui.rs @@ -270,13 +270,13 @@ regexes! { // erase thread caller ids r"call [0-9]+" => "call ID", // erase platform module paths - "sys::pal::[a-z]+::" => "sys::pal::PLATFORM::", + r"\bsys::([a-z_]+)::[a-z]+::" => "sys::$1::PLATFORM::", // Windows file paths r"\\" => "/", // erase Rust stdlib path "[^ \n`]*/(rust[^/]*|checkout)/library/" => "RUSTLIB/", // erase platform file paths - "sys/pal/[a-z]+/" => "sys/pal/PLATFORM/", + r"\bsys/([a-z_]+)/[a-z]+\b" => "sys/$1/PLATFORM", // erase paths into the crate registry r"[^ ]*/\.?cargo/registry/.*/(.*\.rs)" => "CARGO_REGISTRY/.../$1", } diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index 565721a9093..3111149f2ae 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -389,6 +389,7 @@ fn main() -> anyhow::Result<()> { "clippy", "miri", "rustfmt", + "gcc", ] { build_args.extend(["--skip".to_string(), target.to_string()]); } diff --git a/src/tools/opt-dist/src/metrics.rs b/src/tools/opt-dist/src/metrics.rs index 89c4cb12d4c..0a745566eb5 100644 --- a/src/tools/opt-dist/src/metrics.rs +++ b/src/tools/opt-dist/src/metrics.rs @@ -1,33 +1,10 @@ use std::time::Duration; -use build_helper::metrics::{JsonNode, JsonRoot}; +use build_helper::metrics::{BuildStep, JsonRoot, format_build_steps}; use camino::Utf8Path; use crate::timer::TimerSection; -#[derive(Clone, Debug)] -pub struct BuildStep { - r#type: String, - children: Vec<BuildStep>, - duration: Duration, -} - -impl BuildStep { - pub fn find_all_by_type(&self, r#type: &str) -> Vec<&BuildStep> { - let mut result = Vec::new(); - self.find_by_type(r#type, &mut result); - result - } - fn find_by_type<'a>(&'a self, r#type: &str, result: &mut Vec<&'a BuildStep>) { - if self.r#type == r#type { - result.push(self); - } - for child in &self.children { - child.find_by_type(r#type, result); - } - } -} - /// Loads the metrics of the most recent bootstrap execution from a metrics.json file. pub fn load_metrics(path: &Utf8Path) -> anyhow::Result<BuildStep> { let content = std::fs::read(path.as_std_path())?; @@ -37,30 +14,7 @@ pub fn load_metrics(path: &Utf8Path) -> anyhow::Result<BuildStep> { .pop() .ok_or_else(|| anyhow::anyhow!("No bootstrap invocation found in metrics file"))?; - fn parse(node: JsonNode) -> Option<BuildStep> { - match node { - JsonNode::RustbuildStep { - type_: kind, - children, - duration_excluding_children_sec, - .. - } => { - let children: Vec<_> = children.into_iter().filter_map(parse).collect(); - let children_duration = children.iter().map(|c| c.duration).sum::<Duration>(); - Some(BuildStep { - r#type: kind.to_string(), - children, - duration: children_duration - + Duration::from_secs_f64(duration_excluding_children_sec), - }) - } - JsonNode::TestSuite(_) => None, - } - } - - let duration = Duration::from_secs_f64(invocation.duration_including_children_sec); - let children: Vec<_> = invocation.children.into_iter().filter_map(parse).collect(); - Ok(BuildStep { r#type: "root".to_string(), children, duration }) + Ok(BuildStep::from_invocation(&invocation)) } /// Logs the individual metrics in a table and add Rustc and LLVM durations to the passed @@ -82,27 +36,6 @@ pub fn record_metrics(metrics: &BuildStep, timer: &mut TimerSection) { timer.add_duration("Rustc", rustc_duration); } - log_metrics(metrics); -} - -fn log_metrics(metrics: &BuildStep) { - use std::fmt::Write; - - let mut substeps: Vec<(u32, &BuildStep)> = Vec::new(); - - fn visit<'a>(step: &'a BuildStep, level: u32, substeps: &mut Vec<(u32, &'a BuildStep)>) { - substeps.push((level, step)); - for child in &step.children { - visit(child, level + 1, substeps); - } - } - - visit(metrics, 0, &mut substeps); - - let mut output = String::new(); - for (level, step) in substeps { - let label = format!("{}{}", ".".repeat(level as usize), step.r#type); - writeln!(output, "{label:<65}{:>8.2}s", step.duration.as_secs_f64()).unwrap(); - } + let output = format_build_steps(metrics); log::info!("Build step durations\n{output}"); } diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 15ed03ad5c2..f9beffec750 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -14,5 +14,9 @@ build_helper = { path = "../../build_helper" } serde_json = "1.0" libc = "0.2" +# FIXME(#137532): replace `os_pipe` with `anonymous_pipe` once it stabilizes and +# reaches beta. +os_pipe = "1.2.1" + [lib] crate-type = ["lib", "dylib"] diff --git a/src/tools/run-make-support/src/artifact_names.rs b/src/tools/run-make-support/src/artifact_names.rs index 0d7b5cb9838..8968f831542 100644 --- a/src/tools/run-make-support/src/artifact_names.rs +++ b/src/tools/run-make-support/src/artifact_names.rs @@ -8,23 +8,6 @@ use crate::targets::is_msvc; /// Construct the static library name based on the target. #[must_use] pub fn static_lib_name(name: &str) -> String { - // See tools.mk (irrelevant lines omitted): - // - // ```makefile - // ifeq ($(UNAME),Darwin) - // STATICLIB = $(TMPDIR)/lib$(1).a - // else - // ifdef IS_WINDOWS - // ifdef IS_MSVC - // STATICLIB = $(TMPDIR)/$(1).lib - // else - // STATICLIB = $(TMPDIR)/lib$(1).a - // endif - // else - // STATICLIB = $(TMPDIR)/lib$(1).a - // endif - // endif - // ``` assert!(!name.contains(char::is_whitespace), "static library name cannot contain whitespace"); if is_msvc() { format!("{name}.lib") } else { format!("lib{name}.a") } diff --git a/src/tools/run-make-support/src/external_deps/c_cxx_compiler/cc.rs b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/cc.rs index becb91ae989..0e6d6ea6075 100644 --- a/src/tools/run-make-support/src/external_deps/c_cxx_compiler/cc.rs +++ b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/cc.rs @@ -80,17 +80,6 @@ impl Cc { /// Specify `-o` or `-Fe`/`-Fo` depending on platform/compiler. pub fn out_exe(&mut self, name: &str) -> &mut Self { - // Ref: tools.mk (irrelevant lines omitted): - // - // ```makefile - // ifdef IS_MSVC - // OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \ - // -Fo:`cygpath -w $(TMPDIR)/$(1).obj` - // else - // OUT_EXE=-o $(TMPDIR)/$(1) - // endif - // ``` - let mut path = std::path::PathBuf::from(name); if is_msvc() { diff --git a/src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs index 49210d75e06..c0317633873 100644 --- a/src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs +++ b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs @@ -1,47 +1,15 @@ -use crate::{is_msvc, is_windows, uname}; +use crate::{is_msvc, is_win7, is_windows, uname}; /// `EXTRACFLAGS` pub fn extra_c_flags() -> Vec<&'static str> { - // Adapted from tools.mk (trimmed): - // - // ```makefile - // ifdef IS_WINDOWS - // ifdef IS_MSVC - // EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib synchronization.lib - // else - // EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll -lsynchronization - // endif - // else - // ifeq ($(UNAME),Darwin) - // EXTRACFLAGS := -lresolv - // else - // ifeq ($(UNAME),FreeBSD) - // EXTRACFLAGS := -lm -lpthread -lgcc_s - // else - // ifeq ($(UNAME),SunOS) - // EXTRACFLAGS := -lm -lpthread -lposix4 -lsocket -lresolv - // else - // ifeq ($(UNAME),OpenBSD) - // EXTRACFLAGS := -lm -lpthread -lc++abi - // else - // EXTRACFLAGS := -lm -lrt -ldl -lpthread - // endif - // endif - // endif - // endif - // endif - // ``` - if is_windows() { if is_msvc() { - vec![ - "ws2_32.lib", - "userenv.lib", - "advapi32.lib", - "bcrypt.lib", - "ntdll.lib", - "synchronization.lib", - ] + let mut libs = + vec!["ws2_32.lib", "userenv.lib", "bcrypt.lib", "ntdll.lib", "synchronization.lib"]; + if is_win7() { + libs.push("advapi32.lib"); + } + libs } else { vec!["-lws2_32", "-luserenv", "-lbcrypt", "-lntdll", "-lsynchronization"] } @@ -60,31 +28,6 @@ pub fn extra_c_flags() -> Vec<&'static str> { /// `EXTRACXXFLAGS` pub fn extra_cxx_flags() -> Vec<&'static str> { - // Adapted from tools.mk (trimmed): - // - // ```makefile - // ifdef IS_WINDOWS - // ifdef IS_MSVC - // else - // EXTRACXXFLAGS := -lstdc++ - // endif - // else - // ifeq ($(UNAME),Darwin) - // EXTRACXXFLAGS := -lc++ - // else - // ifeq ($(UNAME),FreeBSD) - // else - // ifeq ($(UNAME),SunOS) - // else - // ifeq ($(UNAME),OpenBSD) - // else - // EXTRACXXFLAGS := -lstdc++ - // endif - // endif - // endif - // endif - // endif - // ``` if is_windows() { if is_msvc() { vec![] } else { vec!["-lstdc++"] } } else { diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index 710ba025830..0e2239147f1 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -5,7 +5,7 @@ use std::str::FromStr as _; use crate::command::Command; use crate::env::env_var; use crate::path_helpers::cwd; -use crate::util::set_host_rpath; +use crate::util::set_host_compiler_dylib_path; use crate::{is_aix, is_darwin, is_msvc, is_windows, uname}; /// Construct a new `rustc` invocation. This will automatically set the library @@ -15,8 +15,8 @@ pub fn rustc() -> Rustc { Rustc::new() } -/// Construct a plain `rustc` invocation with no flags set. Note that [`set_host_rpath`] -/// still presets the environment variable `HOST_RPATH_DIR` by default. +/// Construct a plain `rustc` invocation with no flags set. Note that [`set_host_compiler_dylib_path`] +/// still presets the environment variable `HOST_RUSTC_DYLIB_PATH` by default. #[track_caller] pub fn bare_rustc() -> Rustc { Rustc::bare() @@ -44,7 +44,7 @@ pub fn rustc_path() -> String { #[track_caller] fn setup_common() -> Command { let mut cmd = Command::new(rustc_path()); - set_host_rpath(&mut cmd); + set_host_compiler_dylib_path(&mut cmd); cmd } @@ -365,31 +365,6 @@ impl Rustc { /// `EXTRARSCXXFLAGS` pub fn extra_rs_cxx_flags(&mut self) -> &mut Self { - // Adapted from tools.mk (trimmed): - // - // ```makefile - // ifdef IS_WINDOWS - // ifdef IS_MSVC - // else - // EXTRARSCXXFLAGS := -lstatic:-bundle=stdc++ - // endif - // else - // ifeq ($(UNAME),Darwin) - // EXTRARSCXXFLAGS := -lc++ - // else - // ifeq ($(UNAME),FreeBSD) - // else - // ifeq ($(UNAME),SunOS) - // else - // ifeq ($(UNAME),OpenBSD) - // else - // EXTRARSCXXFLAGS := -lstdc++ - // endif - // endif - // endif - // endif - // endif - // ``` if is_windows() { // So this is a bit hacky: we can't use the DLL version of libstdc++ because // it pulls in the DLL version of libgcc, which means that we end up with 2 diff --git a/src/tools/run-make-support/src/external_deps/rustdoc.rs b/src/tools/run-make-support/src/external_deps/rustdoc.rs index 3c0e9c82f0b..433a57cd9fa 100644 --- a/src/tools/run-make-support/src/external_deps/rustdoc.rs +++ b/src/tools/run-make-support/src/external_deps/rustdoc.rs @@ -2,16 +2,10 @@ use std::ffi::OsStr; use std::path::Path; use crate::command::Command; -use crate::env::{env_var, env_var_os}; -use crate::util::set_host_rpath; +use crate::env::env_var; +use crate::util::set_host_compiler_dylib_path; -/// Construct a plain `rustdoc` invocation with no flags set. -#[track_caller] -pub fn bare_rustdoc() -> Rustdoc { - Rustdoc::bare() -} - -/// Construct a new `rustdoc` invocation with `-L $(TARGET_RPATH_DIR)` set. +/// Construct a new `rustdoc` invocation. #[track_caller] pub fn rustdoc() -> Rustdoc { Rustdoc::new() @@ -29,23 +23,15 @@ crate::macros::impl_common_helpers!(Rustdoc); fn setup_common() -> Command { let rustdoc = env_var("RUSTDOC"); let mut cmd = Command::new(rustdoc); - set_host_rpath(&mut cmd); + set_host_compiler_dylib_path(&mut cmd); cmd } impl Rustdoc { /// Construct a bare `rustdoc` invocation. #[track_caller] - pub fn bare() -> Self { - let cmd = setup_common(); - Self { cmd } - } - - /// Construct a `rustdoc` invocation with `-L $(TARGET_RPATH_DIR)` set. - #[track_caller] pub fn new() -> Self { - let mut cmd = setup_common(); - cmd.arg("-L").arg(env_var_os("TARGET_RPATH_DIR")); + let cmd = setup_common(); Self { cmd } } @@ -132,4 +118,11 @@ impl Rustdoc { self.cmd.arg(format); self } + + /// Specify type(s) of output files to generate. + pub fn emit<S: AsRef<str>>(&mut self, kinds: S) -> &mut Self { + let kinds = kinds.as_ref(); + self.cmd.arg(format!("--emit={kinds}")); + self + } } diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 7e63ab3159a..e0ad3ee9bed 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -40,6 +40,8 @@ pub use bstr; pub use gimli; pub use libc; pub use object; +// FIXME(#137532): replace with std `anonymous_pipe` once it stabilizes and reaches beta. +pub use os_pipe; pub use regex; pub use serde_json; pub use similar; @@ -67,7 +69,7 @@ pub use llvm::{ }; pub use python::python_command; pub use rustc::{aux_build, bare_rustc, rustc, rustc_path, Rustc}; -pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; +pub use rustdoc::{rustdoc, Rustdoc}; /// [`diff`][mod@diff] is implemented in terms of the [similar] library. /// @@ -82,7 +84,7 @@ pub use run::{cmd, run, run_fail, run_with_args}; /// Helpers for checking target information. pub use targets::{ - apple_os, is_aix, is_darwin, is_msvc, is_windows, is_windows_gnu, llvm_components_contain, + apple_os, is_aix, is_darwin, is_msvc, is_windows, is_windows_gnu, is_win7, llvm_components_contain, target, uname, }; diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs index 3eeba6fd526..7812863ccc2 100644 --- a/src/tools/run-make-support/src/run.rs +++ b/src/tools/run-make-support/src/run.rs @@ -1,10 +1,10 @@ use std::ffi::OsStr; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::{env, panic}; use crate::command::{Command, CompletedProcess}; -use crate::util::{handle_failed_output, set_host_rpath}; -use crate::{cwd, env_var, is_windows}; +use crate::util::handle_failed_output; +use crate::{cwd, env_var}; #[track_caller] fn run_common(name: &str, args: Option<&[&str]>) -> Command { @@ -18,10 +18,11 @@ fn run_common(name: &str, args: Option<&[&str]>) -> Command { cmd.arg(arg); } } + cmd.env(&ld_lib_path_envvar, { let mut paths = vec![]; paths.push(cwd()); - for p in env::split_paths(&env_var("TARGET_RPATH_ENV")) { + for p in env::split_paths(&env_var("TARGET_EXE_DYLIB_PATH")) { paths.push(p.to_path_buf()); } for p in env::split_paths(&env_var(&ld_lib_path_envvar)) { @@ -31,15 +32,6 @@ fn run_common(name: &str, args: Option<&[&str]>) -> Command { }); cmd.env("LC_ALL", "C"); // force english locale - if is_windows() { - let mut paths = vec![]; - for p in env::split_paths(&std::env::var("PATH").unwrap_or(String::new())) { - paths.push(p.to_path_buf()); - } - paths.push(Path::new(&env_var("TARGET_RPATH_DIR")).to_path_buf()); - cmd.env("PATH", env::join_paths(paths.iter()).unwrap()); - } - cmd } @@ -84,7 +76,6 @@ pub fn run_fail(name: &str) -> CompletedProcess { #[track_caller] pub fn cmd<S: AsRef<OsStr>>(program: S) -> Command { let mut command = Command::new(program); - set_host_rpath(&mut command); command.env("LC_ALL", "C"); // force english locale command } diff --git a/src/tools/run-make-support/src/targets.rs b/src/tools/run-make-support/src/targets.rs index a16fca71d2e..86edbdf750b 100644 --- a/src/tools/run-make-support/src/targets.rs +++ b/src/tools/run-make-support/src/targets.rs @@ -28,6 +28,12 @@ pub fn is_windows_gnu() -> bool { target().ends_with("windows-gnu") } +/// Check if target is win7. +#[must_use] +pub fn is_win7() -> bool { + target().contains("win7") +} + /// Check if target uses macOS. #[must_use] pub fn is_darwin() -> bool { diff --git a/src/tools/run-make-support/src/util.rs b/src/tools/run-make-support/src/util.rs index 703e3ad1c6c..af01758447b 100644 --- a/src/tools/run-make-support/src/util.rs +++ b/src/tools/run-make-support/src/util.rs @@ -24,13 +24,13 @@ pub(crate) fn handle_failed_output( std::process::exit(1) } -/// Set the runtime library path as needed for running the host rustc/rustdoc/etc. -pub(crate) fn set_host_rpath(cmd: &mut Command) { +/// Set the runtime library paths as needed for running the host compilers (rustc/rustdoc/etc). +pub(crate) fn set_host_compiler_dylib_path(cmd: &mut Command) { let ld_lib_path_envvar = env_var("LD_LIB_PATH_ENVVAR"); cmd.env(&ld_lib_path_envvar, { let mut paths = vec![]; paths.push(cwd()); - paths.push(PathBuf::from(env_var("HOST_RPATH_DIR"))); + paths.push(PathBuf::from(env_var("HOST_RUSTC_DYLIB_PATH"))); for p in std::env::split_paths(&env_var(&ld_lib_path_envvar)) { paths.push(p.to_path_buf()); } diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 30853cb799e..1e1d68f7782 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -626,7 +626,6 @@ dependencies = [ "oorandom", "project-model", "ra-ap-rustc_abi", - "ra-ap-rustc_hashes", "ra-ap-rustc_index", "ra-ap-rustc_pattern_analysis", "rustc-hash 2.0.0", @@ -1504,9 +1503,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b42cccfff8091a4c3397736518774dbad619e82f8def6f70d8e46dbbe396007" +checksum = "f1651b0f7e8c3eb7c27a88f39d277e69c32bfe58e3be174d286c1a24d6a7a4d8" dependencies = [ "bitflags 2.7.0", "ra-ap-rustc_hashes", @@ -1516,18 +1515,18 @@ dependencies = [ [[package]] name = "ra-ap-rustc_hashes" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46d8bd34ed6552c8cac1764106ef5adbeef3e5c7700e0ceb4c83a47a631894fe" +checksum = "2bcd85e93dc0ea850bcfe7957a115957df799ccbc9eea488bdee5ec6780d212b" dependencies = [ "rustc-stable-hash", ] [[package]] name = "ra-ap-rustc_index" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93799e4dccbbd47f8b66bc0aa42effc1b7077aaee09d8a40b86b8d659b80c7b7" +checksum = "62b295fc0640cd9fe0ecab872ee4a17a96f90a3998ec9f0c4765e9b8415c12cc" dependencies = [ "ra-ap-rustc_index_macros", "smallvec", @@ -1535,9 +1534,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index_macros" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30baa5d00f94ba437a9dcaf7ae074ebe4f367bb05a4c2835e0aa2e7af3463aac" +checksum = "c675f4257023aa933882906f13802cae287e88cc39ab13cbb96809083db0c801" dependencies = [ "proc-macro2", "quote", @@ -1546,9 +1545,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3004d1d1b50afe3e1f9cdd428a282da7ffbf5f26dd8bf04af0d651d44e4873d8" +checksum = "c8358702c2a510ea84ba5801ddc047d9ad9520902cfb0e6173277610cdce2c9c" dependencies = [ "memchr", "unicode-properties", @@ -1557,9 +1556,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb57e5124a64aaaf92c06130fbc1b8e1d547b5a2a96081f1f848e31c211df5d2" +checksum = "b98f402011d46732c35c47bfd111dec0495747fef2ec900ddee7fe15d78449a7" dependencies = [ "ra-ap-rustc_index", "ra-ap-rustc_lexer", @@ -1567,9 +1566,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.98.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e427c3d30e4bdff28abd6b0ef3e6f4dfab44acd9468a4954eeff8717d8df8819" +checksum = "bef3ff73fa4653252ffe1d1e9177a446f49ef46d97140e4816b7ff2dad59ed53" dependencies = [ "ra-ap-rustc_index", "rustc-hash 2.0.0", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 33a9a5695a0..ce2d66000e3 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -85,12 +85,12 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } edition = { path = "./crates/edition", version = "0.0.0" } -ra-ap-rustc_hashes = { version = "0.98", default-features = false } -ra-ap-rustc_lexer = { version = "0.98", default-features = false } -ra-ap-rustc_parse_format = { version = "0.98", default-features = false } -ra-ap-rustc_index = { version = "0.98", default-features = false } -ra-ap-rustc_abi = { version = "0.98", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.98", default-features = false } +ra-ap-rustc_hashes = { version = "0.100", default-features = false } +ra-ap-rustc_lexer = { version = "0.100", default-features = false } +ra-ap-rustc_parse_format = { version = "0.100", default-features = false } +ra-ap-rustc_index = { version = "0.100", default-features = false } +ra-ap-rustc_abi = { version = "0.100", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.100", default-features = false } # local crates that aren't published to crates.io. These should not have versions. diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index 27849f3b449..1d12bee646c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -35,7 +35,6 @@ indexmap.workspace = true rustc_apfloat = "0.2.0" ra-ap-rustc_abi.workspace = true -ra-ap-rustc_hashes.workspace = true ra-ap-rustc_index.workspace = true ra-ap-rustc_pattern_analysis.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index 6b5c712159a..bbd419d9659 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -6,16 +6,14 @@ use base_db::ra_salsa::Cycle; use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy}; use hir_def::{ layout::{ - BackendRepr, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, - LayoutData, Primitive, ReprOptions, Scalar, Size, StructKind, TargetDataLayout, - WrappingRange, + Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutData, Primitive, + ReprOptions, Scalar, StructKind, TargetDataLayout, WrappingRange, }, LocalFieldId, StructId, }; use la_arena::{Idx, RawIdx}; use rustc_abi::AddressSpace; -use rustc_hashes::Hash64; -use rustc_index::{IndexSlice, IndexVec}; +use rustc_index::IndexVec; use triomphe::Arc; @@ -23,7 +21,6 @@ use crate::{ consteval::try_const_usize, db::{HirDatabase, InternedClosure}, infer::normalize, - layout::adt::struct_variant_idx, utils::ClosureSubst, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, }; @@ -125,82 +122,34 @@ impl<'a> LayoutCx<'a> { } } -// FIXME: move this to the `rustc_abi`. fn layout_of_simd_ty( db: &dyn HirDatabase, id: StructId, + repr_packed: bool, subst: &Substitution, env: Arc<TraitEnvironment>, dl: &TargetDataLayout, ) -> Result<Arc<Layout>, LayoutError> { - let fields = db.field_types(id.into()); - - // Supported SIMD vectors are homogeneous ADTs with at least one field: + // Supported SIMD vectors are homogeneous ADTs with exactly one array field: // - // * #[repr(simd)] struct S(T, T, T, T); - // * #[repr(simd)] struct S { it: T, y: T, z: T, w: T } // * #[repr(simd)] struct S([T; 4]) // // where T is a primitive scalar (integer/float/pointer). - - let f0_ty = match fields.iter().next() { - Some(it) => it.1.clone().substitute(Interner, subst), - None => return Err(LayoutError::InvalidSimdType), - }; - - // The element type and number of elements of the SIMD vector - // are obtained from: - // - // * the element type and length of the single array field, if - // the first field is of array type, or - // - // * the homogeneous field type and the number of fields. - let (e_ty, e_len, is_array) = if let TyKind::Array(e_ty, _) = f0_ty.kind(Interner) { - // Extract the number of elements from the layout of the array field: - let FieldsShape::Array { count, .. } = db.layout_of_ty(f0_ty.clone(), env.clone())?.fields - else { - return Err(LayoutError::Unknown); - }; - - (e_ty.clone(), count, true) - } else { - // First ADT field is not an array: - (f0_ty, fields.iter().count() as u64, false) + let fields = db.field_types(id.into()); + let mut fields = fields.iter(); + let Some(TyKind::Array(e_ty, e_len)) = fields + .next() + .filter(|_| fields.next().is_none()) + .map(|f| f.1.clone().substitute(Interner, subst).kind(Interner).clone()) + else { + return Err(LayoutError::InvalidSimdType); }; - // Compute the ABI of the element type: + let e_len = try_const_usize(db, &e_len).ok_or(LayoutError::HasErrorConst)? as u64; let e_ly = db.layout_of_ty(e_ty, env)?; - let BackendRepr::Scalar(e_abi) = e_ly.backend_repr else { - return Err(LayoutError::Unknown); - }; - - // Compute the size and alignment of the vector: - let size = e_ly - .size - .checked_mul(e_len, dl) - .ok_or(LayoutError::BadCalc(LayoutCalculatorError::SizeOverflow))?; - let align = dl.llvmlike_vector_align(size); - let size = size.align_to(align.abi); - - // Compute the placement of the vector fields: - let fields = if is_array { - FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), memory_index: [0].into() } - } else { - FieldsShape::Array { stride: e_ly.size, count: e_len } - }; - Ok(Arc::new(Layout { - variants: Variants::Single { index: struct_variant_idx() }, - fields, - backend_repr: BackendRepr::SimdVector { element: e_abi, count: e_len }, - largest_niche: e_ly.largest_niche, - uninhabited: false, - size, - align, - max_repr_align: None, - unadjusted_abi_align: align.abi, - randomization_seed: Hash64::ZERO, - })) + let cx = LayoutCx::new(dl); + Ok(Arc::new(cx.calc.simd_type(e_ly, e_len, repr_packed)?)) } pub fn layout_of_ty_query( @@ -215,13 +164,14 @@ pub fn layout_of_ty_query( let dl = &*target; let cx = LayoutCx::new(dl); let ty = normalize(db, trait_env.clone(), ty); - let result = match ty.kind(Interner) { + let kind = ty.kind(Interner); + let result = match kind { TyKind::Adt(AdtId(def), subst) => { if let hir_def::AdtId::StructId(s) = def { let data = db.struct_data(*s); let repr = data.repr.unwrap_or_default(); if repr.simd() { - return layout_of_simd_ty(db, *s, subst, trait_env, &target); + return layout_of_simd_ty(db, *s, repr.packed(), subst, trait_env, &target); } }; return db.layout_of_adt(*def, subst.clone(), trait_env); @@ -241,42 +191,51 @@ pub fn layout_of_ty_query( valid_range: WrappingRange { start: 0, end: 0x10FFFF }, }, ), - chalk_ir::Scalar::Int(i) => scalar( + chalk_ir::Scalar::Int(i) => Layout::scalar( dl, - Primitive::Int( - match i { - IntTy::Isize => dl.ptr_sized_integer(), - IntTy::I8 => Integer::I8, - IntTy::I16 => Integer::I16, - IntTy::I32 => Integer::I32, - IntTy::I64 => Integer::I64, - IntTy::I128 => Integer::I128, - }, - true, + scalar_unit( + dl, + Primitive::Int( + match i { + IntTy::Isize => dl.ptr_sized_integer(), + IntTy::I8 => Integer::I8, + IntTy::I16 => Integer::I16, + IntTy::I32 => Integer::I32, + IntTy::I64 => Integer::I64, + IntTy::I128 => Integer::I128, + }, + true, + ), ), ), - chalk_ir::Scalar::Uint(i) => scalar( + chalk_ir::Scalar::Uint(i) => Layout::scalar( dl, - Primitive::Int( - match i { - UintTy::Usize => dl.ptr_sized_integer(), - UintTy::U8 => Integer::I8, - UintTy::U16 => Integer::I16, - UintTy::U32 => Integer::I32, - UintTy::U64 => Integer::I64, - UintTy::U128 => Integer::I128, - }, - false, + scalar_unit( + dl, + Primitive::Int( + match i { + UintTy::Usize => dl.ptr_sized_integer(), + UintTy::U8 => Integer::I8, + UintTy::U16 => Integer::I16, + UintTy::U32 => Integer::I32, + UintTy::U64 => Integer::I64, + UintTy::U128 => Integer::I128, + }, + false, + ), ), ), - chalk_ir::Scalar::Float(f) => scalar( + chalk_ir::Scalar::Float(f) => Layout::scalar( dl, - Primitive::Float(match f { - FloatTy::F16 => Float::F16, - FloatTy::F32 => Float::F32, - FloatTy::F64 => Float::F64, - FloatTy::F128 => Float::F128, - }), + scalar_unit( + dl, + Primitive::Float(match f { + FloatTy::F16 => Float::F16, + FloatTy::F32 => Float::F32, + FloatTy::F64 => Float::F64, + FloatTy::F128 => Float::F128, + }), + ), ), }, TyKind::Tuple(len, tys) => { @@ -293,56 +252,16 @@ pub fn layout_of_ty_query( TyKind::Array(element, count) => { let count = try_const_usize(db, count).ok_or(LayoutError::HasErrorConst)? as u64; let element = db.layout_of_ty(element.clone(), trait_env)?; - let size = element - .size - .checked_mul(count, dl) - .ok_or(LayoutError::BadCalc(LayoutCalculatorError::SizeOverflow))?; - - let backend_repr = BackendRepr::Memory { sized: true }; - - let largest_niche = if count != 0 { element.largest_niche } else { None }; - let uninhabited = if count != 0 { element.uninhabited } else { false }; - - Layout { - variants: Variants::Single { index: struct_variant_idx() }, - fields: FieldsShape::Array { stride: element.size, count }, - backend_repr, - largest_niche, - uninhabited, - align: element.align, - size, - max_repr_align: None, - unadjusted_abi_align: element.align.abi, - randomization_seed: Hash64::ZERO, - } + cx.calc.array_like::<_, _, ()>(&element, Some(count))? } TyKind::Slice(element) => { let element = db.layout_of_ty(element.clone(), trait_env)?; - Layout { - variants: Variants::Single { index: struct_variant_idx() }, - fields: FieldsShape::Array { stride: element.size, count: 0 }, - backend_repr: BackendRepr::Memory { sized: false }, - largest_niche: None, - uninhabited: false, - align: element.align, - size: Size::ZERO, - max_repr_align: None, - unadjusted_abi_align: element.align.abi, - randomization_seed: Hash64::ZERO, - } + cx.calc.array_like::<_, _, ()>(&element, None)? + } + TyKind::Str => { + let element = scalar_unit(dl, Primitive::Int(Integer::I8, false)); + cx.calc.array_like::<_, _, ()>(&Layout::scalar(dl, element), None)? } - TyKind::Str => Layout { - variants: Variants::Single { index: struct_variant_idx() }, - fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 }, - backend_repr: BackendRepr::Memory { sized: false }, - largest_niche: None, - uninhabited: false, - align: dl.i8_align, - size: Size::ZERO, - max_repr_align: None, - unadjusted_abi_align: dl.i8_align.abi, - randomization_seed: Hash64::ZERO, - }, // Potentially-wide pointers. TyKind::Ref(_, _, pointee) | TyKind::Raw(_, pointee) => { let mut data_ptr = scalar_unit(dl, Primitive::Pointer(AddressSpace::DATA)); @@ -380,17 +299,12 @@ pub fn layout_of_ty_query( }; // Effectively a (ptr, meta) tuple. - cx.calc.scalar_pair(data_ptr, metadata) + LayoutData::scalar_pair(dl, data_ptr, metadata) } - TyKind::FnDef(_, _) => layout_of_unit(&cx)?, - TyKind::Never => cx.calc.layout_of_never_type(), - TyKind::Dyn(_) | TyKind::Foreign(_) => { - let mut unit = layout_of_unit(&cx)?; - match &mut unit.backend_repr { - BackendRepr::Memory { sized } => *sized = false, - _ => return Err(LayoutError::Unknown), - } - unit + TyKind::Never => LayoutData::never_type(dl), + TyKind::FnDef(..) | TyKind::Dyn(_) | TyKind::Foreign(_) => { + let sized = matches!(kind, TyKind::FnDef(..)); + LayoutData::unit(dl, sized) } TyKind::Function(_) => { let mut ptr = scalar_unit(dl, Primitive::Pointer(dl.instruction_address_space)); @@ -462,16 +376,6 @@ pub fn layout_of_ty_recover( Err(LayoutError::RecursiveTypeWithoutIndirection) } -fn layout_of_unit(cx: &LayoutCx<'_>) -> Result<Layout, LayoutError> { - cx.calc - .univariant::<RustcFieldIdx, RustcEnumVariantIdx, &&Layout>( - IndexSlice::empty(), - &ReprOptions::default(), - StructKind::AlwaysSized, - ) - .map_err(Into::into) -} - fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty { match pointee.kind(Interner) { TyKind::Adt(AdtId(hir_def::AdtId::StructId(i)), subst) => { @@ -502,9 +406,5 @@ fn scalar_unit(dl: &TargetDataLayout, value: Primitive) -> Scalar { Scalar::Initialized { value, valid_range: WrappingRange::full(value.size(dl)) } } -fn scalar(dl: &TargetDataLayout, value: Primitive) -> Layout { - Layout::scalar(dl, scalar_unit(dl, value)) -} - #[cfg(test)] mod tests; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs index 0ba765bd75e..eb4729fab84 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs @@ -16,16 +16,12 @@ use triomphe::Arc; use crate::{ db::HirDatabase, lang_items::is_unsafe_cell, - layout::{field_ty, Layout, LayoutError, RustcEnumVariantIdx}, + layout::{field_ty, Layout, LayoutError}, Substitution, TraitEnvironment, }; use super::LayoutCx; -pub(crate) fn struct_variant_idx() -> RustcEnumVariantIdx { - RustcEnumVariantIdx(0) -} - pub fn layout_of_adt_query( db: &dyn HirDatabase, def: AdtId, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs index 4d3896660b4..8b74b7328bd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs @@ -342,7 +342,7 @@ fn simd_types() { check_size_and_align( r#" #[repr(simd)] - struct SimdType(i64, i64); + struct SimdType([i64; 2]); struct Goal(SimdType); "#, "", diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 2f9245a3326..624767cedf8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -12,9 +12,6 @@ extern crate ra_ap_rustc_index as rustc_index; #[cfg(feature = "in-rust-tree")] extern crate rustc_abi; -#[cfg(feature = "in-rust-tree")] -extern crate rustc_hashes; - #[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_abi as rustc_abi; @@ -24,9 +21,6 @@ extern crate rustc_pattern_analysis; #[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis; -#[cfg(not(feature = "in-rust-tree"))] -extern crate ra_ap_rustc_hashes as rustc_hashes; - mod builder; mod chalk_db; mod chalk_ext; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index 333dbe33059..0a7a7d1fb24 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -12317,40 +12317,6 @@ will unnecessarily extend the stack frame. deny_since: None, }, Lint { - label: "unsized_tuple_coercion", - description: r##"# `unsized_tuple_coercion` - -The tracking issue for this feature is: [#42877] - -[#42877]: https://github.com/rust-lang/rust/issues/42877 - ------------------------- - -This is a part of [RFC0401]. According to the RFC, there should be an implementation like this: - -```rust,ignore (partial-example) -impl<..., T, U: ?Sized> Unsized<(..., U)> for (..., T) where T: Unsized<U> {} -``` - -This implementation is currently gated behind `#[feature(unsized_tuple_coercion)]` to avoid insta-stability. Therefore you can use it like this: - -```rust -#![feature(unsized_tuple_coercion)] - -fn main() { - let x : ([i32; 3], [i32; 3]) = ([1, 2, 3], [4, 5, 6]); - let y : &([i32; 3], [i32]) = &x; - assert_eq!(y.1[0], 4); -} -``` - -[RFC0401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md -"##, - default_severity: Severity::Allow, - warn_since: None, - deny_since: None, - }, - Lint { label: "unwrap_infallible", description: r##"# `unwrap_infallible` diff --git a/src/tools/rust-analyzer/lib/line-index/src/lib.rs b/src/tools/rust-analyzer/lib/line-index/src/lib.rs index bc87ada3eb5..905da330e64 100644 --- a/src/tools/rust-analyzer/lib/line-index/src/lib.rs +++ b/src/tools/rust-analyzer/lib/line-index/src/lib.rs @@ -257,6 +257,8 @@ fn analyze_source_file_dispatch( /// SSE2 intrinsics to quickly find all newlines. #[target_feature(enable = "sse2")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +// This can be removed once 1.87 is stable due to some intrinsics switching to safe. +#[allow(unsafe_op_in_unsafe_fn)] unsafe fn analyze_source_file_sse2( src: &str, lines: &mut Vec<TextSize>, @@ -287,17 +289,17 @@ unsafe fn analyze_source_file_sse2( // For character in the chunk, see if its byte value is < 0, which // indicates that it's part of a UTF-8 char. - let multibyte_test = unsafe { _mm_cmplt_epi8(chunk, _mm_set1_epi8(0)) }; + let multibyte_test = _mm_cmplt_epi8(chunk, _mm_set1_epi8(0)); // Create a bit mask from the comparison results. - let multibyte_mask = unsafe { _mm_movemask_epi8(multibyte_test) }; + let multibyte_mask = _mm_movemask_epi8(multibyte_test); // If the bit mask is all zero, we only have ASCII chars here: if multibyte_mask == 0 { assert!(intra_chunk_offset == 0); // Check for newlines in the chunk - let newlines_test = unsafe { _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\n' as i8)) }; - let newlines_mask = unsafe { _mm_movemask_epi8(newlines_test) }; + let newlines_test = _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\n' as i8)); + let newlines_mask = _mm_movemask_epi8(newlines_test); if newlines_mask != 0 { // All control characters are newlines, record them @@ -354,15 +356,19 @@ unsafe fn analyze_source_file_sse2( // The mask is a 64-bit integer, where each 4-bit corresponds to a u8 in the // input vector. The least significant 4 bits correspond to the first byte in // the vector. +// This can be removed once 1.87 is stable due to some intrinsics switching to safe. +#[allow(unsafe_op_in_unsafe_fn)] unsafe fn move_mask(v: std::arch::aarch64::uint8x16_t) -> u64 { use std::arch::aarch64::*; - let nibble_mask = unsafe { vshrn_n_u16(vreinterpretq_u16_u8(v), 4) }; - unsafe { vget_lane_u64(vreinterpret_u64_u8(nibble_mask), 0) } + let nibble_mask = vshrn_n_u16(vreinterpretq_u16_u8(v), 4); + vget_lane_u64(vreinterpret_u64_u8(nibble_mask), 0) } #[target_feature(enable = "neon")] #[cfg(all(target_arch = "aarch64", target_endian = "little"))] +// This can be removed once 1.87 is stable due to some intrinsics switching to safe. +#[allow(unsafe_op_in_unsafe_fn)] unsafe fn analyze_source_file_neon( src: &str, lines: &mut Vec<TextSize>, @@ -376,7 +382,7 @@ unsafe fn analyze_source_file_neon( let chunk_count = src.len() / CHUNK_SIZE; - let newline = unsafe { vdupq_n_s8(b'\n' as i8) }; + let newline = vdupq_n_s8(b'\n' as i8); // This variable keeps track of where we should start decoding a // chunk. If a multi-byte character spans across chunk boundaries, @@ -390,7 +396,7 @@ unsafe fn analyze_source_file_neon( // For character in the chunk, see if its byte value is < 0, which // indicates that it's part of a UTF-8 char. - let multibyte_test = unsafe { vcltzq_s8(chunk) }; + let multibyte_test = vcltzq_s8(chunk); // Create a bit mask from the comparison results. let multibyte_mask = unsafe { move_mask(multibyte_test) }; @@ -399,7 +405,7 @@ unsafe fn analyze_source_file_neon( assert!(intra_chunk_offset == 0); // Check for newlines in the chunk - let newlines_test = unsafe { vceqq_s8(chunk, newline) }; + let newlines_test = vceqq_s8(chunk, newline); let mut newlines_mask = unsafe { move_mask(newlines_test) }; // If the bit mask is not all zero, there are newlines in this chunk. diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index e24e08d0687..0db4be8ff63 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -daf59857d6d2b87af4b846316bf1561a6083ed51 +2c6a12ec44d0426c8939123c2f2cf27d2217de13 diff --git a/src/tools/rustdoc/Cargo.toml b/src/tools/rustdoc/Cargo.toml index c4101f72cc2..d1682758d36 100644 --- a/src/tools/rustdoc/Cargo.toml +++ b/src/tools/rustdoc/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustdoc-tool" version = "0.0.0" -edition = "2021" +edition = "2024" # Cargo adds a number of paths to the dylib search path on windows, which results in # the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 16b7e7aa709..eff2d2e3ff4 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -137,6 +137,10 @@ pub(crate) fn format_expr( ast::ExprKind::Tup(ref items) => { rewrite_tuple(context, items.iter(), expr.span, shape, items.len() == 1) } + ast::ExprKind::Use(_, _) => { + // FIXME: properly implement this + Ok(context.snippet(expr.span()).to_owned()) + } ast::ExprKind::Let(ref pat, ref expr, _span, _) => rewrite_let(context, shape, pat, expr), ast::ExprKind::If(..) | ast::ExprKind::ForLoop { .. } diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 457d0afe3b5..3fb3284e3d7 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -2359,6 +2359,21 @@ impl Rewrite for ast::Param { } } +fn rewrite_opt_lifetime( + context: &RewriteContext<'_>, + lifetime: Option<ast::Lifetime>, +) -> RewriteResult { + let Some(l) = lifetime else { + return Ok(String::new()); + }; + let mut result = l.rewrite_result( + context, + Shape::legacy(context.config.max_width(), Indent::empty()), + )?; + result.push(' '); + Ok(result) +} + fn rewrite_explicit_self( context: &RewriteContext<'_>, explicit_self: &ast::ExplicitSelf, @@ -2367,58 +2382,34 @@ fn rewrite_explicit_self( shape: Shape, has_multiple_attr_lines: bool, ) -> RewriteResult { - match explicit_self.node { + let self_str = match explicit_self.node { ast::SelfKind::Region(lt, m) => { let mut_str = format_mutability(m); - match lt { - Some(ref l) => { - let lifetime_str = l.rewrite_result( - context, - Shape::legacy(context.config.max_width(), Indent::empty()), - )?; - Ok(combine_strs_with_missing_comments( - context, - param_attrs, - &format!("&{lifetime_str} {mut_str}self"), - span, - shape, - !has_multiple_attr_lines, - )?) - } - None => Ok(combine_strs_with_missing_comments( - context, - param_attrs, - &format!("&{mut_str}self"), - span, - shape, - !has_multiple_attr_lines, - )?), - } + let lifetime_str = rewrite_opt_lifetime(context, lt)?; + format!("&{lifetime_str}{mut_str}self") + } + ast::SelfKind::Pinned(lt, m) => { + let mut_str = m.ptr_str(); + let lifetime_str = rewrite_opt_lifetime(context, lt)?; + format!("&{lifetime_str}pin {mut_str} self") } ast::SelfKind::Explicit(ref ty, mutability) => { let type_str = ty.rewrite_result( context, Shape::legacy(context.config.max_width(), Indent::empty()), )?; - - Ok(combine_strs_with_missing_comments( - context, - param_attrs, - &format!("{}self: {}", format_mutability(mutability), type_str), - span, - shape, - !has_multiple_attr_lines, - )?) + format!("{}self: {}", format_mutability(mutability), type_str) } - ast::SelfKind::Value(mutability) => Ok(combine_strs_with_missing_comments( - context, - param_attrs, - &format!("{}self", format_mutability(mutability)), - span, - shape, - !has_multiple_attr_lines, - )?), - } + ast::SelfKind::Value(mutability) => format!("{}self", format_mutability(mutability)), + }; + Ok(combine_strs_with_missing_comments( + context, + param_attrs, + &self_str, + span, + shape, + !has_multiple_attr_lines, + )?) } pub(crate) fn span_lo_for_param(param: &ast::Param) -> BytePos { diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs index ea8ca38cb77..664c90b991a 100644 --- a/src/tools/rustfmt/src/macros.rs +++ b/src/tools/rustfmt/src/macros.rs @@ -12,7 +12,7 @@ use std::collections::HashMap; use std::panic::{AssertUnwindSafe, catch_unwind}; -use rustc_ast::token::{BinOpToken, Delimiter, Token, TokenKind}; +use rustc_ast::token::{Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenStreamIter, TokenTree}; use rustc_ast::{ast, ptr}; use rustc_ast_pretty::pprust; @@ -841,7 +841,7 @@ impl MacroArgParser { match tok { TokenTree::Token( Token { - kind: TokenKind::BinOp(BinOpToken::Plus), + kind: TokenKind::Plus, .. }, _, @@ -855,7 +855,7 @@ impl MacroArgParser { ) | TokenTree::Token( Token { - kind: TokenKind::BinOp(BinOpToken::Star), + kind: TokenKind::Star, .. }, _, @@ -1088,14 +1088,32 @@ fn force_space_before(tok: &TokenKind) -> bool { | TokenKind::Gt | TokenKind::AndAnd | TokenKind::OrOr - | TokenKind::Not + | TokenKind::Bang | TokenKind::Tilde - | TokenKind::BinOpEq(_) + | TokenKind::PlusEq + | TokenKind::MinusEq + | TokenKind::StarEq + | TokenKind::SlashEq + | TokenKind::PercentEq + | TokenKind::CaretEq + | TokenKind::AndEq + | TokenKind::OrEq + | TokenKind::ShlEq + | TokenKind::ShrEq | TokenKind::At | TokenKind::RArrow | TokenKind::LArrow | TokenKind::FatArrow - | TokenKind::BinOp(_) + | TokenKind::Plus + | TokenKind::Minus + | TokenKind::Star + | TokenKind::Slash + | TokenKind::Percent + | TokenKind::Caret + | TokenKind::And + | TokenKind::Or + | TokenKind::Shl + | TokenKind::Shr | TokenKind::Pound | TokenKind::Dollar => true, _ => false, @@ -1113,8 +1131,8 @@ fn next_space(tok: &TokenKind) -> SpaceState { debug!("next_space: {:?}", tok); match tok { - TokenKind::Not - | TokenKind::BinOp(BinOpToken::And) + TokenKind::Bang + | TokenKind::And | TokenKind::Tilde | TokenKind::At | TokenKind::Comma diff --git a/src/tools/rustfmt/src/spanned.rs b/src/tools/rustfmt/src/spanned.rs index e93eb53cd87..507647566d4 100644 --- a/src/tools/rustfmt/src/spanned.rs +++ b/src/tools/rustfmt/src/spanned.rs @@ -58,6 +58,7 @@ implement_spanned!(ast::ExprField); implement_spanned!(ast::ForeignItem); implement_spanned!(ast::Item); implement_spanned!(ast::Local); +implement_spanned!(ast::WherePredicate); impl Spanned for ast::Stmt { fn span(&self) -> Span { @@ -149,12 +150,6 @@ impl Spanned for ast::FieldDef { } } -impl Spanned for ast::WherePredicate { - fn span(&self) -> Span { - self.span - } -} - impl Spanned for ast::FnRetTy { fn span(&self) -> Span { match *self { diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 7b44b47c719..06a67334086 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -463,8 +463,9 @@ impl Rewrite for ast::WherePredicate { } fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { + let attrs_str = self.attrs.rewrite_result(context, shape)?; // FIXME: dead spans? - let result = match self.kind { + let pred_str = &match self.kind { ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate { ref bound_generic_params, ref bounded_ty, @@ -499,6 +500,38 @@ impl Rewrite for ast::WherePredicate { } }; + let mut result = String::with_capacity(attrs_str.len() + pred_str.len() + 1); + result.push_str(&attrs_str); + let pred_start = self.span.lo(); + let line_len = last_line_width(&attrs_str) + 1 + first_line_width(&pred_str); + if let Some(last_attr) = self.attrs.last().filter(|last_attr| { + contains_comment(context.snippet(mk_sp(last_attr.span.hi(), pred_start))) + }) { + result = combine_strs_with_missing_comments( + context, + &result, + &pred_str, + mk_sp(last_attr.span.hi(), pred_start), + Shape { + width: shape.width.min(context.config.inline_attribute_width()), + ..shape + }, + !last_attr.is_doc_comment(), + )?; + } else { + if !self.attrs.is_empty() { + if context.config.inline_attribute_width() < line_len + || self.attrs.len() > 1 + || self.attrs.last().is_some_and(|a| a.is_doc_comment()) + { + result.push_str(&shape.indent.to_string_with_newline(context.config)); + } else { + result.push(' '); + } + } + result.push_str(&pred_str); + } + Ok(result) } } diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index ba4a4c045f1..fe716c18638 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -513,6 +513,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Become(..) | ast::ExprKind::Yeet(..) | ast::ExprKind::Tup(..) + | ast::ExprKind::Use(..) | ast::ExprKind::Type(..) | ast::ExprKind::Yield(None) | ast::ExprKind::Underscore => false, diff --git a/src/tools/rustfmt/tests/source/pin_sugar.rs b/src/tools/rustfmt/tests/source/pin_sugar.rs index 0eb3c0770c4..370dfbc196a 100644 --- a/src/tools/rustfmt/tests/source/pin_sugar.rs +++ b/src/tools/rustfmt/tests/source/pin_sugar.rs @@ -8,3 +8,13 @@ fn g<'a>(x: & 'a pin const i32) {} fn h<'a>(x: & 'a pin mut i32) {} fn i(x: &pin mut i32) {} + +struct Foo; + +impl Foo { + fn f(&pin const self) {} + fn g<'a>(& 'a pin const self) {} + fn h<'a>(& 'a pin +mut self) {} + fn i(&pin mut self) {} +} diff --git a/src/tools/rustfmt/tests/target/cfg_attribute_in_where.rs b/src/tools/rustfmt/tests/target/cfg_attribute_in_where.rs new file mode 100644 index 00000000000..11f495b1629 --- /dev/null +++ b/src/tools/rustfmt/tests/target/cfg_attribute_in_where.rs @@ -0,0 +1,116 @@ +// rustfmt-inline_attribute_width: 40 + +#![crate_type = "lib"] +#![feature(cfg_attribute_in_where)] +use std::marker::PhantomData; + +#[cfg(a)] +trait TraitA {} + +#[cfg(b)] +trait TraitB {} + +trait A<T> +where + #[cfg = a_very_long_attribute_name] + T: TraitA, + #[cfg = another_very_long_attribute_name] + T: TraitB, +{ + type B<U> + where + #[cfg = a] + // line comment after the attribute + U: TraitA, + #[cfg = b] + /* block comment after the attribute */ + U: TraitB, + #[cfg = a] // short + U: TraitA, + #[cfg = b] /* short */ U: TraitB; + + fn foo<U>(&self) + where + /// line doc comment before the attribute + U: TraitA, + /** line doc block comment before the attribute */ + U: TraitB; +} + +impl<T> A<T> for T +where + #[doc = "line doc before the attribute"] + T: TraitA, + /** short doc */ + T: TraitB, +{ + type B<U> + = () + where + #[doc = "short"] U: TraitA, + #[doc = "short"] + #[cfg = a] + U: TraitB; + + fn foo<U>(&self) + where + #[cfg = a] + #[cfg = b] + U: TraitA, + /// line doc + #[cfg = c] + U: TraitB, + { + } +} + +struct C<T> +where + #[cfg = a] T: TraitA, + #[cfg = b] T: TraitB, +{ + _t: PhantomData<T>, +} + +union D<T> +where + #[cfg = a] T: TraitA, + #[cfg = b] T: TraitB, +{ + _t: PhantomData<T>, +} + +enum E<T> +where + #[cfg = a] T: TraitA, + #[cfg = b] T: TraitB, +{ + E(PhantomData<T>), +} + +#[allow(type_alias_bounds)] +type F<T> +where + #[cfg = a] T: TraitA, + #[cfg = b] T: TraitB, += T; + +impl<T> C<T> +where + #[cfg = a] T: TraitA, + #[cfg = b] T: TraitB, +{ + fn new<U>() + where + #[cfg = a] U: TraitA, + #[cfg = b] U: TraitB, + { + } +} + +fn foo<T>() +where + #[cfg = a] T: TraitA, + #[cfg = b] T: TraitB, +{ +} diff --git a/src/tools/rustfmt/tests/target/pin_sugar.rs b/src/tools/rustfmt/tests/target/pin_sugar.rs index c9fa883e238..7d04efb1b32 100644 --- a/src/tools/rustfmt/tests/target/pin_sugar.rs +++ b/src/tools/rustfmt/tests/target/pin_sugar.rs @@ -7,3 +7,12 @@ fn f(x: &pin const i32) {} fn g<'a>(x: &'a pin const i32) {} fn h<'a>(x: &'a pin mut i32) {} fn i(x: &pin mut i32) {} + +struct Foo; + +impl Foo { + fn f(&pin const self) {} + fn g<'a>(&'a pin const self) {} + fn h<'a>(&'a pin mut self) {} + fn i(&pin mut self) {} +} diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 9a4d0891b4a..dfdbc0878f2 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -17,6 +17,7 @@ termcolor = "1.1.3" rustc-hash = "2.0.0" fluent-syntax = "0.11.1" similar = "2.5.0" +toml = "0.7.8" [features] build-metrics = ["dep:serde"] diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt deleted file mode 100644 index e69de29bb2d..00000000000 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ /dev/null diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 1e7eb82b83e..66856f5247b 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -79,7 +79,6 @@ pub(crate) mod iter_header; pub mod known_bug; pub mod mir_opt_tests; pub mod pal; -pub mod run_make_tests; pub mod rustdoc_css_themes; pub mod rustdoc_gui_tests; pub mod rustdoc_templates; @@ -88,6 +87,7 @@ pub mod target_policy; pub mod target_specific_tests; pub mod tests_placement; pub mod tests_revision_unpaired_stdout_stderr; +pub mod triagebot; pub mod ui_tests; pub mod unit_tests; pub mod unknown_revision; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 13a558fea48..bc3519142dd 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -103,8 +103,6 @@ fn main() { check!(tests_revision_unpaired_stdout_stderr, &tests_path); check!(debug_artifacts, &tests_path); check!(ui_tests, &root_path, bless); - // FIXME(jieyouxu): remove this check once all run-make tests are ported over to rmake.rs. - check!(run_make_tests, &tests_path, &src_path, bless); check!(mir_opt_tests, &tests_path, bless); check!(rustdoc_gui_tests, &tests_path); check!(rustdoc_css_themes, &librustdoc_path); @@ -146,6 +144,8 @@ fn main() { check!(x_version, &root_path, &cargo); + check!(triagebot, &root_path); + let collected = { drain_handles(&mut handles); diff --git a/src/tools/tidy/src/run_make_tests.rs b/src/tools/tidy/src/run_make_tests.rs deleted file mode 100644 index 8d176787837..00000000000 --- a/src/tools/tidy/src/run_make_tests.rs +++ /dev/null @@ -1,104 +0,0 @@ -//! Tidy check to ensure that no new Makefiles are added under `tests/run-make/`. - -use std::collections::BTreeSet; -use std::fs::File; -use std::io::Write; -use std::path::{Path, PathBuf}; - -pub fn check(tests_path: &Path, src_path: &Path, bless: bool, bad: &mut bool) { - let mut is_sorted = true; - - let allowed_makefiles = { - let mut total_lines = 0; - let mut prev_line = ""; - let allowed_makefiles: BTreeSet<&str> = include_str!("allowed_run_make_makefiles.txt") - .lines() - .map(|line| { - total_lines += 1; - - if prev_line > line { - is_sorted = false; - } - - prev_line = line; - - line - }) - .collect(); - - if !is_sorted && !bless { - tidy_error!( - bad, - "`src/tools/tidy/src/allowed_run_make_makefiles.txt` is not in order, likely \ - because you modified it manually, please only update it with command \ - `x test tidy --bless`" - ); - } - if allowed_makefiles.len() != total_lines { - tidy_error!( - bad, - "`src/tools/tidy/src/allowed_run_make_makefiles.txt` contains duplicate entries, \ - likely because you modified it manually, please only update it with command \ - `x test tidy --bless`" - ); - } - - allowed_makefiles - }; - - let mut remaining_makefiles = allowed_makefiles.clone(); - - crate::walk::walk_no_read( - &[tests_path.join("run-make").as_ref()], - |_, _| false, - &mut |entry| { - if entry.file_type().map_or(true, |t| t.is_dir()) { - return; - } - - if entry.file_name().to_str().map_or(true, |f| f != "Makefile") { - return; - } - - let makefile_path = entry.path().strip_prefix(&tests_path).unwrap(); - let makefile_path = makefile_path.to_str().unwrap().replace('\\', "/"); - - if !remaining_makefiles.remove(makefile_path.as_str()) { - tidy_error!( - bad, - "found run-make Makefile not permitted in \ - `src/tools/tidy/src/allowed_run_make_makefiles.txt`, please write new run-make \ - tests with `rmake.rs` instead: {}", - entry.path().display() - ); - } - }, - ); - - // If there are any expected Makefiles remaining, they were moved or deleted. - // Our data must remain up to date, so they must be removed from - // `src/tools/tidy/src/allowed_run_make_makefiles.txt`. - // This can be done automatically on --bless, or else a tidy error will be issued. - if bless && (!remaining_makefiles.is_empty() || !is_sorted) { - let tidy_src = src_path.join("tools").join("tidy").join("src"); - let org_file_path = tidy_src.join("allowed_run_make_makefiles.txt"); - let temp_file_path = tidy_src.join("blessed_allowed_run_make_makefiles.txt"); - let mut temp_file = t!(File::create_new(&temp_file_path)); - for file in allowed_makefiles.difference(&remaining_makefiles) { - t!(writeln!(temp_file, "{file}")); - } - t!(std::fs::rename(&temp_file_path, &org_file_path)); - } else { - for file in remaining_makefiles { - let mut p = PathBuf::from(tests_path); - p.push(file); - tidy_error!( - bad, - "Makefile `{}` no longer exists and should be removed from the exclusions in \ - `src/tools/tidy/src/allowed_run_make_makefiles.txt`, you can run `x test tidy --bless` to update \ - the allow list", - p.display() - ); - } - } -} diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 21b513629ed..2237eac200d 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -72,12 +72,14 @@ const ANNOTATIONS_TO_IGNORE: &[&str] = &[ "//@ normalize-stderr", ]; +const LINELENGTH_CHECK: &str = "linelength"; + // If you edit this, also edit where it gets used in `check` (calling `contains_ignore_directives`) const CONFIGURABLE_CHECKS: [&str; 11] = [ "cr", "undocumented-unsafe", "tab", - "linelength", + LINELENGTH_CHECK, "filelength", "end-whitespace", "trailing-newlines", @@ -250,14 +252,24 @@ enum Directive { // Use a fixed size array in the return type to catch mistakes with changing `CONFIGURABLE_CHECKS` // without changing the code in `check` easier. fn contains_ignore_directives<const N: usize>( + path_str: &str, can_contain: bool, contents: &str, checks: [&str; N], ) -> [Directive; N] { - if !can_contain { + // The rustdoc-json test syntax often requires very long lines, so the checks + // for long lines aren't really useful. + let always_ignore_linelength = path_str.contains("rustdoc-json"); + + if !can_contain && !always_ignore_linelength { return [Directive::Deny; N]; } + checks.map(|check| { + if check == LINELENGTH_CHECK && always_ignore_linelength { + return Directive::Ignore(false); + } + // Update `can_contain` when changing this if contents.contains(&format!("// ignore-tidy-{check}")) || contents.contains(&format!("# ignore-tidy-{check}")) @@ -367,6 +379,7 @@ pub fn check(path: &Path, bad: &mut bool) { walk(path, skip, &mut |entry, contents| { let file = entry.path(); + let path_str = file.to_string_lossy(); let filename = file.file_name().unwrap().to_string_lossy(); let is_css_file = filename.ends_with(".css"); @@ -422,7 +435,7 @@ pub fn check(path: &Path, bad: &mut bool) { mut skip_copyright, mut skip_dbg, mut skip_odd_backticks, - ] = contains_ignore_directives(can_contain, &contents, CONFIGURABLE_CHECKS); + ] = contains_ignore_directives(&path_str, can_contain, &contents, CONFIGURABLE_CHECKS); let mut leading_new_lines = false; let mut trailing_new_lines = 0; let mut lines = 0; @@ -462,7 +475,7 @@ pub fn check(path: &Path, bad: &mut bool) { && !trimmed.starts_with("//") && !file.ancestors().any(|a| { (a.ends_with("tests") && a.join("COMPILER_TESTS.md").exists()) - || a.ends_with("library/alloc/tests") + || a.ends_with("library/alloctests") }) && filename != "tests.rs" { @@ -502,7 +515,7 @@ pub fn check(path: &Path, bad: &mut bool) { let contains_potential_directive = possible_line_start && (line.contains("-tidy") || line.contains("tidy-")); let has_recognized_ignore_directive = - contains_ignore_directives(can_contain, line, CONFIGURABLE_CHECKS) + contains_ignore_directives(&path_str, can_contain, line, CONFIGURABLE_CHECKS) .into_iter() .any(|directive| matches!(directive, Directive::Ignore(_))); let has_alphabetical_directive = line.contains("tidy-alphabetical-start") diff --git a/src/tools/tidy/src/triagebot.rs b/src/tools/tidy/src/triagebot.rs new file mode 100644 index 00000000000..7131c16ec30 --- /dev/null +++ b/src/tools/tidy/src/triagebot.rs @@ -0,0 +1,93 @@ +//! Tidy check to ensure paths mentioned in triagebot.toml exist in the project. + +use std::path::Path; + +use toml::Value; + +pub fn check(path: &Path, bad: &mut bool) { + let triagebot_path = path.join("triagebot.toml"); + if !triagebot_path.exists() { + tidy_error!(bad, "triagebot.toml file not found"); + return; + } + + let contents = std::fs::read_to_string(&triagebot_path).unwrap(); + let config: Value = toml::from_str(&contents).unwrap(); + + // Check [mentions."*"] sections, i.e. [mentions."compiler/rustc_const_eval/src/"] + if let Some(Value::Table(mentions)) = config.get("mentions") { + for path_str in mentions.keys() { + // Remove quotes from the path + let clean_path = path_str.trim_matches('"'); + let full_path = path.join(clean_path); + + if !full_path.exists() { + tidy_error!( + bad, + "triagebot.toml [mentions.*] contains path '{}' which doesn't exist", + clean_path + ); + } + } + } else { + tidy_error!( + bad, + "triagebot.toml missing [mentions.*] section, this wrong for rust-lang/rust repo." + ); + } + + // Check [assign.owners] sections, i.e. + // [assign.owners] + // "/.github/workflows" = ["infra-ci"] + if let Some(Value::Table(assign)) = config.get("assign") { + if let Some(Value::Table(owners)) = assign.get("owners") { + for path_str in owners.keys() { + // Remove quotes and leading slash from the path + let clean_path = path_str.trim_matches('"').trim_start_matches('/'); + let full_path = path.join(clean_path); + + if !full_path.exists() { + tidy_error!( + bad, + "triagebot.toml [assign.owners] contains path '{}' which doesn't exist", + clean_path + ); + } + } + } else { + tidy_error!( + bad, + "triagebot.toml missing [assign.owners] section, this wrong for rust-lang/rust repo." + ); + } + } + + // Verify that trigger_files in [autolabel."*"] exist in the project, i.e. + // [autolabel."A-rustdoc-search"] + // trigger_files = [ + // "src/librustdoc/html/static/js/search.js", + // "tests/rustdoc-js", + // "tests/rustdoc-js-std", + // ] + if let Some(Value::Table(autolabels)) = config.get("autolabel") { + for (label, content) in autolabels { + if let Some(trigger_files) = content.get("trigger_files").and_then(|v| v.as_array()) { + for file in trigger_files { + if let Some(file_str) = file.as_str() { + let full_path = path.join(file_str); + + // Handle both file and directory paths + if !full_path.exists() { + tidy_error!( + bad, + "triagebot.toml [autolabel.{}] contains trigger_files path '{}' which doesn't exist", + label, + file_str + ); + } + } + } + } + } + } +} |
