diff options
248 files changed, 3989 insertions, 2261 deletions
diff --git a/Cargo.lock b/Cargo.lock index 8b9c243879c..a8df53f3a41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,11 +158,11 @@ checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "ar_archive_writer" -version = "0.4.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01667f6f40216b9a0b2945e05fed5f1ad0ab6470e69cb9378001e37b1c0668e4" +checksum = "7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340b" dependencies = [ - "object 0.36.7", + "object 0.37.3", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 2c5044f6a35..67c7a9d67ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,33 +59,6 @@ exclude = [ "obj", ] -[workspace.dependencies] -# tidy-alphabetical-start -bitflags = "2.9.3" -derive-where = "1.6.0" -either = "1.15.0" -indexmap = "2.10.0" -itertools = "0.12.1" -# FIXME: Remove this pin once this rustix issue is resolved -# https://github.com/bytecodealliance/rustix/issues/1496 -libc = "=0.2.174" -measureme = "12.0.3" -memchr = "2.7.5" -odht = { version = "0.3.1", features = ["nightly"] } -polonius-engine = "0.13.0" -proc-macro2 = "1.0.101" -quote = "1.0.40" -rustc-demangle = "0.1.26" -rustc-hash = "2.1.1" -rustc-literal-escaper = "0.0.5" -rustc_apfloat = "0.2.3" -scoped-tls = "1.0.1" -serde_json = "1.0.142" -tempfile = "3.20.0" -thin-vec = "0.2.14" -tracing = "0.1.37" -# tidy-alphabetical-end - [profile.release.package.rustc_thread_pool] # The rustc fork of Rayon has deadlock detection code which intermittently # causes overflows in the CI (see https://github.com/rust-lang/rust/issues/90227) diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml index 3de6d186b8a..83d96d8d04d 100644 --- a/compiler/rustc_abi/Cargo.toml +++ b/compiler/rustc_abi/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true +bitflags = "2.4.1" rand = { version = "0.9.0", default-features = false, optional = true } rand_xoshiro = { version = "0.7.0", optional = true } rustc_data_structures = { path = "../rustc_data_structures", optional = true } @@ -15,7 +15,7 @@ rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } rustc_serialize = { path = "../rustc_serialize", optional = true } rustc_span = { path = "../rustc_span", optional = true } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [features] diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 41d744e1946..e3b2b1eff72 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -6,6 +6,8 @@ use std::hash::{Hash, Hasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd}; #[cfg(feature = "nightly")] use rustc_macros::{Decodable, Encodable}; +#[cfg(feature = "nightly")] +use rustc_span::Symbol; use crate::AbiFromStrErr; @@ -226,6 +228,13 @@ impl StableOrd for ExternAbi { #[cfg(feature = "nightly")] rustc_error_messages::into_diag_arg_using_display!(ExternAbi); +#[cfg(feature = "nightly")] +pub enum CVariadicStatus { + NotSupported, + Stable, + Unstable { feature: Symbol }, +} + impl ExternAbi { /// An ABI "like Rust" /// @@ -238,23 +247,33 @@ impl ExternAbi { matches!(self, Rust | RustCall | RustCold) } - pub fn supports_varargs(self) -> bool { + /// Returns whether the ABI supports C variadics. This only controls whether we allow *imports* + /// of such functions via `extern` blocks; there's a separate check during AST construction + /// guarding *definitions* of variadic functions. + #[cfg(feature = "nightly")] + pub fn supports_c_variadic(self) -> CVariadicStatus { // * C and Cdecl obviously support varargs. // * C can be based on Aapcs, SysV64 or Win64, so they must support varargs. // * EfiApi is based on Win64 or C, so it also supports it. + // * System automatically falls back to C when used with variadics, therefore supports it. // // * Stdcall does not, because it would be impossible for the callee to clean // up the arguments. (callee doesn't know how many arguments are there) // * Same for Fastcall, Vectorcall and Thiscall. // * Other calling conventions are related to hardware or the compiler itself. + // + // All of the supported ones must have a test in `tests/codegen/cffi/c-variadic-ffi.rs`. match self { Self::C { .. } | Self::Cdecl { .. } | Self::Aapcs { .. } | Self::Win64 { .. } | Self::SysV64 { .. } - | Self::EfiApi => true, - _ => false, + | Self::EfiApi => CVariadicStatus::Stable, + Self::System { .. } => { + CVariadicStatus::Unstable { feature: rustc_span::sym::extern_system_varargs } + } + _ => CVariadicStatus::NotSupported, } } } diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index a1a0de5aaf8..369874521e5 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -63,6 +63,8 @@ mod tests; pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind}; pub use canon_abi::{ArmCall, CanonAbi, InterruptKind, X86Call}; +#[cfg(feature = "nightly")] +pub use extern_abi::CVariadicStatus; pub use extern_abi::{ExternAbi, all_names}; #[cfg(feature = "nightly")] pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx}; diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 7f948a65220..155e14a3796 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -5,9 +5,9 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true -memchr.workspace = true -rustc-literal-escaper.workspace = true +bitflags = "2.4.1" +memchr = "2.7.4" +rustc-literal-escaper = "0.0.5" rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } @@ -15,6 +15,6 @@ rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index de3e0e0c87f..802a6fa3249 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -937,7 +937,7 @@ pub enum PatKind { #[derive(Clone, Copy, Encodable, Decodable, Debug, PartialEq, Walkable)] pub enum PatFieldsRest { /// `module::StructName { field, ..}` - Rest, + Rest(Span), /// `module::StructName { field, syntax error }` Recovered(ErrorGuaranteed), /// `module::StructName { field }` @@ -4051,8 +4051,8 @@ mod size_asserts { static_assert_size!(Local, 96); static_assert_size!(MetaItemLit, 40); static_assert_size!(Param, 40); - static_assert_size!(Pat, 72); - static_assert_size!(PatKind, 48); + static_assert_size!(Pat, 80); + static_assert_size!(PatKind, 56); static_assert_size!(Path, 24); static_assert_size!(PathSegment, 24); static_assert_size!(Stmt, 32); diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index 317742a3bb8..6ac258155fe 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -24,6 +24,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index cbd17d66b75..3674814b796 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1434,10 +1434,10 @@ impl<'hir> LoweringContext<'_, 'hir> { self.dcx().emit_err(FunctionalRecordUpdateDestructuringAssignment { span: e.span, }); - true + Some(self.lower_span(e.span)) } - StructRest::Rest(_) => true, - StructRest::None => false, + StructRest::Rest(span) => Some(self.lower_span(*span)), + StructRest::None => None, }; let struct_pat = hir::PatKind::Struct(qpath, field_pats, fields_omitted); return self.pat_without_dbm(lhs.span, struct_pat); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 70595391b85..137207bde1f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2508,7 +2508,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fields: &'hir [hir::PatField<'hir>], ) -> &'hir hir::Pat<'hir> { let qpath = hir::QPath::LangItem(lang_item, self.lower_span(span)); - self.pat(span, hir::PatKind::Struct(qpath, fields, false)) + self.pat(span, hir::PatKind::Struct(qpath, fields, None)) } fn pat_ident(&mut self, span: Span, ident: Ident) -> (&'hir hir::Pat<'hir>, HirId) { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index b8f86247875..ed159f37051 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -106,10 +106,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { break hir::PatKind::Struct( qpath, fs, - matches!( - etc, - ast::PatFieldsRest::Rest | ast::PatFieldsRest::Recovered(_) - ), + match etc { + ast::PatFieldsRest::Rest(sp) => Some(self.lower_span(*sp)), + ast::PatFieldsRest::Recovered(_) => Some(Span::default()), + _ => None, + }, ); } PatKind::Tuple(pats) => { diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index 6d2bcbed22b..3e04f8b11ec 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools.workspace = true +itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } @@ -18,5 +18,5 @@ rustc_macros = { path = "../rustc_macros" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -thin-vec.workspace = true +thin-vec = "0.2.12" # tidy-alphabetical-end diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index a95f1443968..e5f1fcdc4b4 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -57,7 +57,7 @@ ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetim .label = {ast_passes_auto_super_lifetime} .suggestion = remove the super traits or lifetime bounds -ast_passes_bad_c_variadic = only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +ast_passes_bad_c_variadic = defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block .cannot_have = cannot have a body diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml index 0c7e55305b4..b704040be96 100644 --- a/compiler/rustc_ast_pretty/Cargo.toml +++ b/compiler/rustc_ast_pretty/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools.workspace = true +itertools = "0.12" rustc_ast = { path = "../rustc_ast" } rustc_lexer = { path = "../rustc_lexer" } rustc_span = { path = "../rustc_span" } @@ -13,5 +13,5 @@ rustc_span = { path = "../rustc_span" } [dev-dependencies] # tidy-alphabetical-start -thin-vec.workspace = true +thin-vec = "0.2.12" # tidy-alphabetical-end diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index a056ce3e29d..41b520b04c9 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1769,7 +1769,7 @@ impl<'a> State<'a> { }, |f| f.pat.span, ); - if let ast::PatFieldsRest::Rest | ast::PatFieldsRest::Recovered(_) = etc { + if let ast::PatFieldsRest::Rest(_) | ast::PatFieldsRest::Recovered(_) = etc { if !fields.is_empty() { self.word_space(","); } diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml index 8bfde43fd33..79193f394fe 100644 --- a/compiler/rustc_attr_parsing/Cargo.toml +++ b/compiler/rustc_attr_parsing/Cargo.toml @@ -18,5 +18,5 @@ rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -thin-vec.workspace = true +thin-vec = "0.2.12" # tidy-alphabetical-end diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml index 5f9dc41766b..9e7d55180a2 100644 --- a/compiler/rustc_borrowck/Cargo.toml +++ b/compiler/rustc_borrowck/Cargo.toml @@ -5,9 +5,9 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -either.workspace = true -itertools.workspace = true -polonius-engine.workspace = true +either = "1.5.0" +itertools = "0.12" +polonius-engine = "0.13.0" rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } @@ -25,5 +25,5 @@ rustc_span = { path = "../rustc_span" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_traits = { path = "../rustc_traits" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index 1c4ff5a6779..54897371410 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -17,7 +17,7 @@ pub use super::polonius::legacy::{ RichLocation, RustcFacts, }; pub use super::region_infer::RegionInferenceContext; -use crate::{BorrowCheckRootCtxt, do_mir_borrowck}; +use crate::BorrowCheckRootCtxt; /// Struct used during mir borrowck to collect bodies with facts for a typeck root and all /// its nested bodies. @@ -127,13 +127,6 @@ pub fn get_bodies_with_borrowck_facts( ) -> FxHashMap<LocalDefId, BodyWithBorrowckFacts<'_>> { let mut root_cx = BorrowCheckRootCtxt::new(tcx, root_def_id, Some(BorrowckConsumer::new(options))); - - // See comment in `rustc_borrowck::mir_borrowck` - let nested_bodies = tcx.nested_bodies_within(root_def_id); - for def_id in nested_bodies { - root_cx.get_or_insert_nested(def_id); - } - - do_mir_borrowck(&mut root_cx, root_def_id); + root_cx.do_mir_borrowck(); root_cx.consumer.unwrap().bodies } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index ce78ae203a4..5d2dda8b0e7 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -22,8 +22,10 @@ use std::ops::{ControlFlow, Deref}; use std::rc::Rc; use borrow_set::LocalsStateAtExit; +use polonius_engine::AllFacts; use root_cx::BorrowCheckRootCtxt; use rustc_abi::FieldIdx; +use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::dominators::Dominators; use rustc_errors::LintDiagnostic; @@ -32,6 +34,7 @@ use rustc_hir::CRATE_HIR_ID; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::MixedBitSet; use rustc_index::{IndexSlice, IndexVec}; +use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::{ InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, }; @@ -53,7 +56,7 @@ use smallvec::SmallVec; use tracing::{debug, instrument}; use crate::borrow_set::{BorrowData, BorrowSet}; -use crate::consumers::BodyWithBorrowckFacts; +use crate::consumers::{BodyWithBorrowckFacts, RustcFacts}; use crate::dataflow::{BorrowIndex, Borrowck, BorrowckDomain, Borrows}; use crate::diagnostics::{ AccessKind, BorrowckDiagnosticsBuffer, IllegalMoveOriginKind, MoveError, RegionName, @@ -61,15 +64,17 @@ use crate::diagnostics::{ use crate::path_utils::*; use crate::place_ext::PlaceExt; use crate::places_conflict::{PlaceConflictBias, places_conflict}; -use crate::polonius::PoloniusDiagnosticsContext; use crate::polonius::legacy::{ PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput, }; +use crate::polonius::{PoloniusContext, PoloniusDiagnosticsContext}; use crate::prefixes::PrefixSet; use crate::region_infer::RegionInferenceContext; +use crate::region_infer::opaque_types::DeferredOpaqueTypeError; use crate::renumber::RegionCtxt; use crate::session_diagnostics::VarNeedNotMut; -use crate::type_check::MirTypeckResults; +use crate::type_check::free_region_relations::UniversalRegionRelations; +use crate::type_check::{Locations, MirTypeckRegionConstraints, MirTypeckResults}; mod borrow_set; mod borrowck_errors; @@ -129,18 +134,7 @@ fn mir_borrowck( Ok(tcx.arena.alloc(opaque_types)) } else { let mut root_cx = BorrowCheckRootCtxt::new(tcx, def, None); - // We need to manually borrowck all nested bodies from the HIR as - // we do not generate MIR for dead code. Not doing so causes us to - // never check closures in dead code. - let nested_bodies = tcx.nested_bodies_within(def); - for def_id in nested_bodies { - root_cx.get_or_insert_nested(def_id); - } - - let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } = - do_mir_borrowck(&mut root_cx, def); - debug_assert!(closure_requirements.is_none()); - debug_assert!(used_mut_upvars.is_empty()); + root_cx.do_mir_borrowck(); root_cx.finalize() } } @@ -153,6 +147,8 @@ struct PropagatedBorrowCheckResults<'tcx> { used_mut_upvars: SmallVec<[FieldIdx; 8]>, } +type DeferredClosureRequirements<'tcx> = Vec<(LocalDefId, ty::GenericArgsRef<'tcx>, Locations)>; + /// After we borrow check a closure, we are left with various /// requirements that we have inferred between the free regions that /// appear in the closure's signature or on its field types. These @@ -291,14 +287,31 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> { } } -/// Perform the actual borrow checking. -/// -/// For nested bodies this should only be called through `root_cx.get_or_insert_nested`. -#[instrument(skip(root_cx), level = "debug")] -fn do_mir_borrowck<'tcx>( +struct CollectRegionConstraintsResult<'tcx> { + infcx: BorrowckInferCtxt<'tcx>, + body_owned: Body<'tcx>, + promoted: IndexVec<Promoted, Body<'tcx>>, + move_data: MoveData<'tcx>, + borrow_set: BorrowSet<'tcx>, + location_table: PoloniusLocationTable, + location_map: Rc<DenseLocationMap>, + universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, + region_bound_pairs: Frozen<RegionBoundPairs<'tcx>>, + known_type_outlives_obligations: Frozen<Vec<ty::PolyTypeOutlivesPredicate<'tcx>>>, + constraints: MirTypeckRegionConstraints<'tcx>, + deferred_closure_requirements: DeferredClosureRequirements<'tcx>, + deferred_opaque_type_errors: Vec<DeferredOpaqueTypeError<'tcx>>, + polonius_facts: Option<AllFacts<RustcFacts>>, + polonius_context: Option<PoloniusContext>, +} + +/// Start borrow checking by collecting the region constraints for +/// the current body. This initializes the relevant data structures +/// and then type checks the MIR body. +fn borrowck_collect_region_constraints<'tcx>( root_cx: &mut BorrowCheckRootCtxt<'tcx>, def: LocalDefId, -) -> PropagatedBorrowCheckResults<'tcx> { +) -> CollectRegionConstraintsResult<'tcx> { let tcx = root_cx.tcx; let infcx = BorrowckInferCtxt::new(tcx, def, root_cx.root_def_id()); let (input_body, promoted) = tcx.mir_promoted(def); @@ -334,10 +347,11 @@ fn do_mir_borrowck<'tcx>( // Run the MIR type-checker. let MirTypeckResults { - mut constraints, + constraints, universal_region_relations, region_bound_pairs, known_type_outlives_obligations, + deferred_closure_requirements, polonius_context, } = type_check::type_check( root_cx, @@ -352,16 +366,53 @@ fn do_mir_borrowck<'tcx>( Rc::clone(&location_map), ); - let opaque_type_errors = region_infer::opaque_types::handle_opaque_type_uses( - root_cx, - &infcx, - &body, - &universal_region_relations, - ®ion_bound_pairs, - &known_type_outlives_obligations, - &location_map, - &mut constraints, - ); + CollectRegionConstraintsResult { + infcx, + body_owned, + promoted, + move_data, + borrow_set, + location_table, + location_map, + universal_region_relations, + region_bound_pairs, + known_type_outlives_obligations, + constraints, + deferred_closure_requirements, + deferred_opaque_type_errors: Default::default(), + polonius_facts, + polonius_context, + } +} + +/// Using the region constraints computed by [borrowck_collect_region_constraints] +/// and the additional constraints from [BorrowCheckRootCtxt::handle_opaque_type_uses], +/// compute the region graph and actually check for any borrowck errors. +fn borrowck_check_region_constraints<'tcx>( + root_cx: &mut BorrowCheckRootCtxt<'tcx>, + CollectRegionConstraintsResult { + infcx, + body_owned, + promoted, + move_data, + borrow_set, + location_table, + location_map, + universal_region_relations, + region_bound_pairs: _, + known_type_outlives_obligations: _, + constraints, + deferred_closure_requirements, + deferred_opaque_type_errors, + polonius_facts, + polonius_context, + }: CollectRegionConstraintsResult<'tcx>, +) -> PropagatedBorrowCheckResults<'tcx> { + assert!(!infcx.has_opaque_types_in_storage()); + assert!(deferred_closure_requirements.is_empty()); + let tcx = root_cx.tcx; + let body = &body_owned; + let def = body.source.def_id().expect_local(); // Compute non-lexical lifetimes using the constraints computed // by typechecking the MIR body. @@ -481,7 +532,7 @@ fn do_mir_borrowck<'tcx>( // Compute and report region errors, if any. if nll_errors.is_empty() { - mbcx.report_opaque_type_errors(opaque_type_errors); + mbcx.report_opaque_type_errors(deferred_opaque_type_errors); } else { mbcx.report_region_errors(nll_errors); } diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 8608a8a3a66..5537d90e297 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -8,8 +8,8 @@ use std::str::FromStr; use polonius_engine::{Algorithm, AllFacts, Output}; use rustc_data_structures::frozen::Frozen; use rustc_index::IndexSlice; -use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options}; -use rustc_middle::mir::{Body, PassWhere, Promoted, create_dump_file, dump_enabled, dump_mir}; +use rustc_middle::mir::pretty::PrettyPrintMirOptions; +use rustc_middle::mir::{Body, MirDumper, PassWhere, Promoted}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, TyCtxt}; use rustc_mir_dataflow::move_paths::MoveData; @@ -68,11 +68,45 @@ pub(crate) fn replace_regions_in_mir<'tcx>( // Replace all remaining regions with fresh inference variables. renumber::renumber_mir(infcx, body, promoted); - dump_mir(infcx.tcx, false, "renumber", &0, body, |_, _| Ok(())); + if let Some(dumper) = MirDumper::new(infcx.tcx, "renumber", body) { + dumper.dump_mir(body); + } universal_regions } +/// Computes the closure requirements given the current inference state. +/// +/// This is intended to be used by before [BorrowCheckRootCtxt::handle_opaque_type_uses] +/// because applying member constraints may rely on closure requirements. +/// This is frequently the case of async functions where pretty much everything +/// happens inside of the inner async block but the opaque only gets constrained +/// in the parent function. +pub(crate) fn compute_closure_requirements_modulo_opaques<'tcx>( + infcx: &BorrowckInferCtxt<'tcx>, + body: &Body<'tcx>, + location_map: Rc<DenseLocationMap>, + universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>, + constraints: &MirTypeckRegionConstraints<'tcx>, +) -> Option<ClosureRegionRequirements<'tcx>> { + // FIXME(#146079): we shouldn't have to clone all this stuff here. + // Computing the region graph should take at least some of it by reference/`Rc`. + let lowered_constraints = compute_sccs_applying_placeholder_outlives_constraints( + constraints.clone(), + &universal_region_relations, + infcx, + ); + let mut regioncx = RegionInferenceContext::new( + &infcx, + lowered_constraints, + universal_region_relations.clone(), + location_map, + ); + + let (closure_region_requirements, _nll_errors) = regioncx.solve(infcx, body, None); + closure_region_requirements +} + /// Computes the (non-lexical) regions from the input MIR. /// /// This may result in errors being reported. @@ -175,9 +209,7 @@ pub(super) fn dump_nll_mir<'tcx>( borrow_set: &BorrowSet<'tcx>, ) { let tcx = infcx.tcx; - if !dump_enabled(tcx, "nll", body.source.def_id()) { - return; - } + let Some(dumper) = MirDumper::new(tcx, "nll", body) else { return }; // We want the NLL extra comments printed by default in NLL MIR dumps (they were removed in // #112346). Specifying `-Z mir-include-spans` on the CLI still has priority: for example, @@ -188,27 +220,24 @@ pub(super) fn dump_nll_mir<'tcx>( MirIncludeSpans::On | MirIncludeSpans::Nll ), }; - dump_mir_with_options( - tcx, - false, - "nll", - &0, - body, - |pass_where, out| { - emit_nll_mir(tcx, regioncx, closure_region_requirements, borrow_set, pass_where, out) - }, - options, - ); + + let extra_data = &|pass_where, out: &mut dyn std::io::Write| { + emit_nll_mir(tcx, regioncx, closure_region_requirements, borrow_set, pass_where, out) + }; + + let dumper = dumper.set_extra_data(extra_data).set_options(options); + + dumper.dump_mir(body); // Also dump the region constraint graph as a graphviz file. let _: io::Result<()> = try { - let mut file = create_dump_file(tcx, "regioncx.all.dot", false, "nll", &0, body)?; + let mut file = dumper.create_dump_file("regioncx.all.dot", body)?; regioncx.dump_graphviz_raw_constraints(tcx, &mut file)?; }; // Also dump the region constraint SCC graph as a graphviz file. let _: io::Result<()> = try { - let mut file = create_dump_file(tcx, "regioncx.scc.dot", false, "nll", &0, body)?; + let mut file = dumper.create_dump_file("regioncx.scc.dot", body)?; regioncx.dump_graphviz_scc_constraints(tcx, &mut file)?; }; } diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs index 6b13b5ad081..62f9ae17347 100644 --- a/compiler/rustc_borrowck/src/polonius/dump.rs +++ b/compiler/rustc_borrowck/src/polonius/dump.rs @@ -2,9 +2,7 @@ use std::io; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_index::IndexVec; -use rustc_middle::mir::pretty::{ - PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer, -}; +use rustc_middle::mir::pretty::{MirDumper, PassWhere, PrettyPrintMirOptions}; use rustc_middle::mir::{Body, Location}; use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::points::PointIndex; @@ -33,22 +31,41 @@ pub(crate) fn dump_polonius_mir<'tcx>( return; } - if !dump_enabled(tcx, "polonius", body.source.def_id()) { - return; - } + let Some(dumper) = MirDumper::new(tcx, "polonius", body) else { return }; let polonius_diagnostics = polonius_diagnostics.expect("missing diagnostics context with `-Zpolonius=next`"); + let extra_data = &|pass_where, out: &mut dyn io::Write| { + emit_polonius_mir( + tcx, + regioncx, + closure_region_requirements, + borrow_set, + &polonius_diagnostics.localized_outlives_constraints, + pass_where, + out, + ) + }; + // We want the NLL extra comments printed by default in NLL MIR dumps. Specifying `-Z + // mir-include-spans` on the CLI still has priority. + let options = PrettyPrintMirOptions { + include_extra_comments: matches!( + tcx.sess.opts.unstable_opts.mir_include_spans, + MirIncludeSpans::On | MirIncludeSpans::Nll + ), + }; + + let dumper = dumper.set_extra_data(extra_data).set_options(options); + let _: io::Result<()> = try { - let mut file = create_dump_file(tcx, "html", false, "polonius", &0, body)?; + let mut file = dumper.create_dump_file("html", body)?; emit_polonius_dump( - tcx, + &dumper, body, regioncx, borrow_set, &polonius_diagnostics.localized_outlives_constraints, - closure_region_requirements, &mut file, )?; }; @@ -61,12 +78,11 @@ pub(crate) fn dump_polonius_mir<'tcx>( /// - a mermaid graph of the NLL regions and the constraints between them /// - a mermaid graph of the NLL SCCs and the constraints between them fn emit_polonius_dump<'tcx>( - tcx: TyCtxt<'tcx>, + dumper: &MirDumper<'_, '_, 'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, borrow_set: &BorrowSet<'tcx>, localized_outlives_constraints: &LocalizedOutlivesConstraintSet, - closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>, out: &mut dyn io::Write, ) -> io::Result<()> { // Prepare the HTML dump file prologue. @@ -79,15 +95,7 @@ fn emit_polonius_dump<'tcx>( writeln!(out, "<div>")?; writeln!(out, "Raw MIR dump")?; writeln!(out, "<pre><code>")?; - emit_html_mir( - tcx, - body, - regioncx, - borrow_set, - &localized_outlives_constraints, - closure_region_requirements, - out, - )?; + emit_html_mir(dumper, body, out)?; writeln!(out, "</code></pre>")?; writeln!(out, "</div>")?; @@ -116,7 +124,7 @@ fn emit_polonius_dump<'tcx>( writeln!(out, "<div>")?; writeln!(out, "NLL regions")?; writeln!(out, "<pre class='mermaid'>")?; - emit_mermaid_nll_regions(tcx, regioncx, out)?; + emit_mermaid_nll_regions(dumper.tcx(), regioncx, out)?; writeln!(out, "</pre>")?; writeln!(out, "</div>")?; @@ -124,7 +132,7 @@ fn emit_polonius_dump<'tcx>( writeln!(out, "<div>")?; writeln!(out, "NLL SCCs")?; writeln!(out, "<pre class='mermaid'>")?; - emit_mermaid_nll_sccs(tcx, regioncx, out)?; + emit_mermaid_nll_sccs(dumper.tcx(), regioncx, out)?; writeln!(out, "</pre>")?; writeln!(out, "</div>")?; @@ -149,45 +157,14 @@ fn emit_polonius_dump<'tcx>( /// Emits the polonius MIR, as escaped HTML. fn emit_html_mir<'tcx>( - tcx: TyCtxt<'tcx>, + dumper: &MirDumper<'_, '_, 'tcx>, body: &Body<'tcx>, - regioncx: &RegionInferenceContext<'tcx>, - borrow_set: &BorrowSet<'tcx>, - localized_outlives_constraints: &LocalizedOutlivesConstraintSet, - closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>, out: &mut dyn io::Write, ) -> io::Result<()> { // Buffer the regular MIR dump to be able to escape it. let mut buffer = Vec::new(); - // We want the NLL extra comments printed by default in NLL MIR dumps. Specifying `-Z - // mir-include-spans` on the CLI still has priority. - let options = PrettyPrintMirOptions { - include_extra_comments: matches!( - tcx.sess.opts.unstable_opts.mir_include_spans, - MirIncludeSpans::On | MirIncludeSpans::Nll - ), - }; - - dump_mir_to_writer( - tcx, - "polonius", - &0, - body, - &mut buffer, - |pass_where, out| { - emit_polonius_mir( - tcx, - regioncx, - closure_region_requirements, - borrow_set, - localized_outlives_constraints, - pass_where, - out, - ) - }, - options, - )?; + dumper.dump_mir_to_writer(body, &mut buffer)?; // Escape the handful of characters that need it. We don't need to be particularly efficient: // we're actually writing into a buffered writer already. Note that MIR dumps are valid UTF-8. diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs index bee82e17835..72615cb33b3 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs @@ -3,16 +3,16 @@ use std::rc::Rc; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::FxIndexMap; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, OpaqueTypeStorageEntries}; use rustc_infer::traits::ObligationCause; use rustc_macros::extension; -use rustc_middle::mir::{Body, ConstraintCategory}; +use rustc_middle::mir::{Body, ConcreteOpaqueTypes, ConstraintCategory}; use rustc_middle::ty::{ - self, DefiningScopeKind, FallibleTypeFolder, GenericArg, GenericArgsRef, OpaqueHiddenType, - OpaqueTypeKey, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, - TypeVisitableExt, fold_regions, + self, DefiningScopeKind, EarlyBinder, FallibleTypeFolder, GenericArg, GenericArgsRef, + OpaqueHiddenType, OpaqueTypeKey, Region, RegionVid, Ty, TyCtxt, TypeFoldable, + TypeSuperFoldable, TypeVisitableExt, fold_regions, }; use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::Span; @@ -24,13 +24,13 @@ use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; use tracing::{debug, instrument}; use super::reverse_sccs::ReverseSccGraph; +use crate::BorrowckInferCtxt; use crate::consumers::RegionInferenceContext; use crate::session_diagnostics::LifetimeMismatchOpaqueParam; use crate::type_check::canonical::fully_perform_op_raw; use crate::type_check::free_region_relations::UniversalRegionRelations; use crate::type_check::{Locations, MirTypeckRegionConstraints}; use crate::universal_regions::{RegionClassification, UniversalRegions}; -use crate::{BorrowCheckRootCtxt, BorrowckInferCtxt}; mod member_constraints; mod region_ctxt; @@ -58,78 +58,32 @@ pub(crate) enum DeferredOpaqueTypeError<'tcx> { }, } -/// This looks at all uses of opaque types in their defining scope inside -/// of this function. +/// We eagerly map all regions to NLL vars here, as we need to make sure we've +/// introduced nll vars for all used placeholders. /// -/// It first uses all defining uses to compute the actual concrete type of each -/// opaque type definition. -/// -/// We then apply this inferred type to actually check all uses of the opaque. -pub(crate) fn handle_opaque_type_uses<'tcx>( - root_cx: &mut BorrowCheckRootCtxt<'tcx>, +/// We need to resolve inference vars as even though we're in MIR typeck, we may still +/// encounter inference variables, e.g. when checking user types. +pub(crate) fn clone_and_resolve_opaque_types<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, - body: &Body<'tcx>, universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>, - region_bound_pairs: &RegionBoundPairs<'tcx>, - known_type_outlives_obligations: &[ty::PolyTypeOutlivesPredicate<'tcx>], - location_map: &Rc<DenseLocationMap>, constraints: &mut MirTypeckRegionConstraints<'tcx>, -) -> Vec<DeferredOpaqueTypeError<'tcx>> { - let tcx = infcx.tcx; +) -> (OpaqueTypeStorageEntries, Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)>) { let opaque_types = infcx.clone_opaque_types(); - if opaque_types.is_empty() { - return Vec::new(); - } - - // We need to eagerly map all regions to NLL vars here, as we need to make sure we've - // introduced nll vars for all used placeholders. - // - // We need to resolve inference vars as even though we're in MIR typeck, we may still - // encounter inference variables, e.g. when checking user types. let opaque_types_storage_num_entries = infcx.inner.borrow_mut().opaque_types().num_entries(); let opaque_types = opaque_types .into_iter() .map(|entry| { - fold_regions(tcx, infcx.resolve_vars_if_possible(entry), |r, _| { + fold_regions(infcx.tcx, infcx.resolve_vars_if_possible(entry), |r, _| { let vid = if let ty::RePlaceholder(placeholder) = r.kind() { constraints.placeholder_region(infcx, placeholder).as_var() } else { universal_region_relations.universal_regions.to_region_vid(r) }; - Region::new_var(tcx, vid) + Region::new_var(infcx.tcx, vid) }) }) .collect::<Vec<_>>(); - - debug!(?opaque_types); - - let errors = compute_concrete_opaque_types( - root_cx, - infcx, - constraints, - universal_region_relations, - Rc::clone(location_map), - &opaque_types, - ); - - if !errors.is_empty() { - return errors; - } - - let errors = apply_computed_concrete_opaque_types( - root_cx, - infcx, - body, - &universal_region_relations.universal_regions, - region_bound_pairs, - known_type_outlives_obligations, - constraints, - &opaque_types, - ); - - detect_opaque_types_added_while_handling_opaque_types(infcx, opaque_types_storage_num_entries); - - errors + (opaque_types_storage_num_entries, opaque_types) } /// Maps an NLL var to a deterministically chosen equal universal region. @@ -172,6 +126,42 @@ fn nll_var_to_universal_region<'tcx>( } } +/// Collect all defining uses of opaque types inside of this typeck root. This +/// expects the hidden type to be mapped to the definition parameters of the opaque +/// and errors if we end up with distinct hidden types. +fn add_concrete_opaque_type<'tcx>( + tcx: TyCtxt<'tcx>, + concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, + def_id: LocalDefId, + hidden_ty: OpaqueHiddenType<'tcx>, +) { + // Sometimes two opaque types are the same only after we remap the generic parameters + // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to + // `(X, Y)` and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we + // only know that once we convert the generic parameters to those of the opaque type. + if let Some(prev) = concrete_opaque_types.0.get_mut(&def_id) { + if prev.ty != hidden_ty.ty { + let guar = hidden_ty.ty.error_reported().err().unwrap_or_else(|| { + let (Ok(e) | Err(e)) = prev.build_mismatch_error(&hidden_ty, tcx).map(|d| d.emit()); + e + }); + prev.ty = Ty::new_error(tcx, guar); + } + // Pick a better span if there is one. + // FIXME(oli-obk): collect multiple spans for better diagnostics down the road. + prev.span = prev.span.substitute_dummy(hidden_ty.span); + } else { + concrete_opaque_types.0.insert(def_id, hidden_ty); + } +} + +fn get_concrete_opaque_type<'tcx>( + concrete_opaque_types: &ConcreteOpaqueTypes<'tcx>, + def_id: LocalDefId, +) -> Option<EarlyBinder<'tcx, OpaqueHiddenType<'tcx>>> { + concrete_opaque_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty)) +} + #[derive(Debug)] struct DefiningUse<'tcx> { /// The opaque type using non NLL vars. This uses the actual @@ -193,12 +183,12 @@ struct DefiningUse<'tcx> { /// /// It also means that this whole function is not really soundness critical as we /// recheck all uses of the opaques regardless. -fn compute_concrete_opaque_types<'tcx>( - root_cx: &mut BorrowCheckRootCtxt<'tcx>, +pub(crate) fn compute_concrete_opaque_types<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, - constraints: &MirTypeckRegionConstraints<'tcx>, universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>, + constraints: &MirTypeckRegionConstraints<'tcx>, location_map: Rc<DenseLocationMap>, + concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], ) -> Vec<DeferredOpaqueTypeError<'tcx>> { let mut errors = Vec::new(); @@ -211,7 +201,8 @@ fn compute_concrete_opaque_types<'tcx>( // We start by checking each use of an opaque type during type check and // check whether the generic arguments of the opaque type are fully // universal, if so, it's a defining use. - let defining_uses = collect_defining_uses(root_cx, &mut rcx, opaque_types, &mut errors); + let defining_uses = + collect_defining_uses(&mut rcx, concrete_opaque_types, opaque_types, &mut errors); // We now compute and apply member constraints for all regions in the hidden // types of each defining use. This mutates the region values of the `rcx` which @@ -221,14 +212,19 @@ fn compute_concrete_opaque_types<'tcx>( // After applying member constraints, we now check whether all member regions ended // up equal to one of their choice regions and compute the actual concrete type of // the opaque type definition. This is stored in the `root_cx`. - compute_concrete_types_from_defining_uses(root_cx, &rcx, &defining_uses, &mut errors); + compute_concrete_types_from_defining_uses( + &rcx, + concrete_opaque_types, + &defining_uses, + &mut errors, + ); errors } #[instrument(level = "debug", skip_all, ret)] fn collect_defining_uses<'tcx>( - root_cx: &mut BorrowCheckRootCtxt<'tcx>, rcx: &mut RegionCtxt<'_, 'tcx>, + concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>, ) -> Vec<DefiningUse<'tcx>> { @@ -248,7 +244,9 @@ fn collect_defining_uses<'tcx>( // with `TypingMode::Borrowck`. if infcx.tcx.use_typing_mode_borrowck() { match err { - NonDefiningUseReason::Tainted(guar) => root_cx.add_concrete_opaque_type( + NonDefiningUseReason::Tainted(guar) => add_concrete_opaque_type( + infcx.tcx, + concrete_opaque_types, opaque_type_key.def_id, OpaqueHiddenType::new_error(infcx.tcx, guar), ), @@ -280,8 +278,8 @@ fn collect_defining_uses<'tcx>( } fn compute_concrete_types_from_defining_uses<'tcx>( - root_cx: &mut BorrowCheckRootCtxt<'tcx>, rcx: &RegionCtxt<'_, 'tcx>, + concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, defining_uses: &[DefiningUse<'tcx>], errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>, ) { @@ -360,7 +358,9 @@ fn compute_concrete_types_from_defining_uses<'tcx>( }, )); } - root_cx.add_concrete_opaque_type( + add_concrete_opaque_type( + tcx, + concrete_opaque_types, opaque_type_key.def_id, OpaqueHiddenType { span: hidden_type.span, ty }, ); @@ -489,20 +489,20 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for ToArgRegionsFolder<'_, 'tcx> { /// /// It does this by equating the hidden type of each use with the instantiated final /// hidden type of the opaque. -fn apply_computed_concrete_opaque_types<'tcx>( - root_cx: &mut BorrowCheckRootCtxt<'tcx>, +pub(crate) fn apply_computed_concrete_opaque_types<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, universal_regions: &UniversalRegions<'tcx>, region_bound_pairs: &RegionBoundPairs<'tcx>, known_type_outlives_obligations: &[ty::PolyTypeOutlivesPredicate<'tcx>], constraints: &mut MirTypeckRegionConstraints<'tcx>, + concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], ) -> Vec<DeferredOpaqueTypeError<'tcx>> { let tcx = infcx.tcx; let mut errors = Vec::new(); for &(key, hidden_type) in opaque_types { - let Some(expected) = root_cx.get_concrete_opaque_type(key.def_id) else { + let Some(expected) = get_concrete_opaque_type(concrete_opaque_types, key.def_id) else { assert!(tcx.use_typing_mode_borrowck(), "non-defining use in defining scope"); errors.push(DeferredOpaqueTypeError::NonDefiningUseInDefiningScope { span: hidden_type.span, @@ -512,7 +512,12 @@ fn apply_computed_concrete_opaque_types<'tcx>( hidden_type.span, "non-defining use in the defining scope with no defining uses", ); - root_cx.add_concrete_opaque_type(key.def_id, OpaqueHiddenType::new_error(tcx, guar)); + add_concrete_opaque_type( + tcx, + concrete_opaque_types, + key.def_id, + OpaqueHiddenType::new_error(tcx, guar), + ); continue; }; @@ -552,7 +557,12 @@ fn apply_computed_concrete_opaque_types<'tcx>( "equating opaque types", ), ) { - root_cx.add_concrete_opaque_type(key.def_id, OpaqueHiddenType::new_error(tcx, guar)); + add_concrete_opaque_type( + tcx, + concrete_opaque_types, + key.def_id, + OpaqueHiddenType::new_error(tcx, guar), + ); } } errors @@ -565,7 +575,7 @@ fn apply_computed_concrete_opaque_types<'tcx>( /// an ICE we can properly handle this, but we haven't encountered any such test yet. /// /// See the related comment in `FnCtxt::detect_opaque_types_added_during_writeback`. -fn detect_opaque_types_added_while_handling_opaque_types<'tcx>( +pub(crate) fn detect_opaque_types_added_while_handling_opaque_types<'tcx>( infcx: &InferCtxt<'tcx>, opaque_types_storage_num_entries: OpaqueTypeStorageEntries, ) { diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index f1427218cdb..eb611fa3475 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -37,6 +37,7 @@ pub(crate) enum RegionElement { /// Records the CFG locations where each region is live. When we initially compute liveness, we use /// an interval matrix storing liveness ranges for each region-vid. +#[derive(Clone)] // FIXME(#146079) pub(crate) struct LivenessValues { /// The map from locations to points. location_map: Rc<DenseLocationMap>, @@ -194,6 +195,7 @@ impl LivenessValues { /// rustc to the internal `PlaceholderIndex` values that are used in /// NLL. #[derive(Debug, Default)] +#[derive(Clone)] // FIXME(#146079) pub(crate) struct PlaceholderIndices { indices: FxIndexSet<ty::PlaceholderRegion>, } diff --git a/compiler/rustc_borrowck/src/root_cx.rs b/compiler/rustc_borrowck/src/root_cx.rs index 4e90ae391bb..cd4e9683f2d 100644 --- a/compiler/rustc_borrowck/src/root_cx.rs +++ b/compiler/rustc_borrowck/src/root_cx.rs @@ -1,13 +1,26 @@ +use std::mem; +use std::rc::Rc; + use rustc_abi::FieldIdx; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_hir::def_id::LocalDefId; -use rustc_middle::bug; -use rustc_middle::ty::{EarlyBinder, OpaqueHiddenType, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::mir::ConstraintCategory; +use rustc_middle::ty::{self, TyCtxt}; use rustc_span::ErrorGuaranteed; use smallvec::SmallVec; use crate::consumers::BorrowckConsumer; -use crate::{ClosureRegionRequirements, ConcreteOpaqueTypes, PropagatedBorrowCheckResults}; +use crate::nll::compute_closure_requirements_modulo_opaques; +use crate::region_infer::opaque_types::{ + apply_computed_concrete_opaque_types, clone_and_resolve_opaque_types, + compute_concrete_opaque_types, detect_opaque_types_added_while_handling_opaque_types, +}; +use crate::type_check::{Locations, constraint_conversion}; +use crate::{ + ClosureRegionRequirements, CollectRegionConstraintsResult, ConcreteOpaqueTypes, + PropagatedBorrowCheckResults, borrowck_check_region_constraints, + borrowck_collect_region_constraints, +}; /// The shared context used by both the root as well as all its nested /// items. @@ -15,7 +28,12 @@ pub(super) struct BorrowCheckRootCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, root_def_id: LocalDefId, concrete_opaque_types: ConcreteOpaqueTypes<'tcx>, - nested_bodies: FxHashMap<LocalDefId, PropagatedBorrowCheckResults<'tcx>>, + /// The region constraints computed by [borrowck_collect_region_constraints]. This uses + /// an [FxIndexMap] to guarantee that iterating over it visits nested bodies before + /// their parents. + collect_region_constraints_results: + FxIndexMap<LocalDefId, CollectRegionConstraintsResult<'tcx>>, + propagated_borrowck_results: FxHashMap<LocalDefId, PropagatedBorrowCheckResults<'tcx>>, tainted_by_errors: Option<ErrorGuaranteed>, /// This should be `None` during normal compilation. See [`crate::consumers`] for more /// information on how this is used. @@ -32,7 +50,8 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> { tcx, root_def_id, concrete_opaque_types: Default::default(), - nested_bodies: Default::default(), + collect_region_constraints_results: Default::default(), + propagated_borrowck_results: Default::default(), tainted_by_errors: None, consumer, } @@ -42,83 +61,232 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> { self.root_def_id } - /// Collect all defining uses of opaque types inside of this typeck root. This - /// expects the hidden type to be mapped to the definition parameters of the opaque - /// and errors if we end up with distinct hidden types. - pub(super) fn add_concrete_opaque_type( - &mut self, - def_id: LocalDefId, - hidden_ty: OpaqueHiddenType<'tcx>, - ) { - // Sometimes two opaque types are the same only after we remap the generic parameters - // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to - // `(X, Y)` and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we - // only know that once we convert the generic parameters to those of the opaque type. - if let Some(prev) = self.concrete_opaque_types.0.get_mut(&def_id) { - if prev.ty != hidden_ty.ty { - let guar = hidden_ty.ty.error_reported().err().unwrap_or_else(|| { - let (Ok(e) | Err(e)) = - prev.build_mismatch_error(&hidden_ty, self.tcx).map(|d| d.emit()); - e - }); - prev.ty = Ty::new_error(self.tcx, guar); - } - // Pick a better span if there is one. - // FIXME(oli-obk): collect multiple spans for better diagnostics down the road. - prev.span = prev.span.substitute_dummy(hidden_ty.span); - } else { - self.concrete_opaque_types.0.insert(def_id, hidden_ty); - } + pub(super) fn set_tainted_by_errors(&mut self, guar: ErrorGuaranteed) { + self.tainted_by_errors = Some(guar); } - pub(super) fn get_concrete_opaque_type( + pub(super) fn used_mut_upvars( &mut self, - def_id: LocalDefId, - ) -> Option<EarlyBinder<'tcx, OpaqueHiddenType<'tcx>>> { - self.concrete_opaque_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty)) + nested_body_def_id: LocalDefId, + ) -> &SmallVec<[FieldIdx; 8]> { + &self.propagated_borrowck_results[&nested_body_def_id].used_mut_upvars } - pub(super) fn set_tainted_by_errors(&mut self, guar: ErrorGuaranteed) { - self.tainted_by_errors = Some(guar); + pub(super) fn finalize(self) -> Result<&'tcx ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> { + if let Some(guar) = self.tainted_by_errors { + Err(guar) + } else { + Ok(self.tcx.arena.alloc(self.concrete_opaque_types)) + } } - pub(super) fn get_or_insert_nested( - &mut self, - def_id: LocalDefId, - ) -> &PropagatedBorrowCheckResults<'tcx> { - debug_assert_eq!( - self.tcx.typeck_root_def_id(def_id.to_def_id()), - self.root_def_id.to_def_id() - ); - if !self.nested_bodies.contains_key(&def_id) { - let result = super::do_mir_borrowck(self, def_id); - if let Some(prev) = self.nested_bodies.insert(def_id, result) { - bug!("unexpected previous nested body: {prev:?}"); + fn handle_opaque_type_uses(&mut self) { + let mut per_body_info = Vec::new(); + for input in self.collect_region_constraints_results.values_mut() { + let (num_entries, opaque_types) = clone_and_resolve_opaque_types( + &input.infcx, + &input.universal_region_relations, + &mut input.constraints, + ); + input.deferred_opaque_type_errors = compute_concrete_opaque_types( + &input.infcx, + &input.universal_region_relations, + &input.constraints, + Rc::clone(&input.location_map), + &mut self.concrete_opaque_types, + &opaque_types, + ); + per_body_info.push((num_entries, opaque_types)); + } + + for (input, (opaque_types_storage_num_entries, opaque_types)) in + self.collect_region_constraints_results.values_mut().zip(per_body_info) + { + if input.deferred_opaque_type_errors.is_empty() { + input.deferred_opaque_type_errors = apply_computed_concrete_opaque_types( + &input.infcx, + &input.body_owned, + &input.universal_region_relations.universal_regions, + &input.region_bound_pairs, + &input.known_type_outlives_obligations, + &mut input.constraints, + &mut self.concrete_opaque_types, + &opaque_types, + ); } + + detect_opaque_types_added_while_handling_opaque_types( + &input.infcx, + opaque_types_storage_num_entries, + ) } + } + + /// Computing defining uses of opaques may depend on the propagated region + /// requirements of nested bodies, while applying defining uses may introduce + /// additional region requirements we need to propagate. + /// + /// This results in cyclic dependency. To compute the defining uses in parent + /// bodies, we need the closure requirements of its nested bodies, but to check + /// non-defining uses in nested bodies, we may rely on the defining uses in the + /// parent. + /// + /// We handle this issue by applying closure requirements twice. Once using the + /// region constraints from before we've handled opaque types in the nested body + /// - which is used by the parent to handle its defining uses - and once after. + /// + /// As a performance optimization, we also eagerly finish borrowck for bodies + /// which don't depend on opaque types. In this case they get removed from + /// `collect_region_constraints_results` and the final result gets put into + /// `propagated_borrowck_results`. + fn apply_closure_requirements_modulo_opaques(&mut self) { + let mut closure_requirements_modulo_opaques = FxHashMap::default(); + // We need to `mem::take` both `self.collect_region_constraints_results` and + // `input.deferred_closure_requirements` as we otherwise can't iterate over + // them while mutably using the containing struct. + let collect_region_constraints_results = + mem::take(&mut self.collect_region_constraints_results); + // We iterate over all bodies here, visiting nested bodies before their parent. + for (def_id, mut input) in collect_region_constraints_results { + // A body depends on opaque types if it either has any opaque type uses itself, + // or it has a nested body which does. + // + // If the current body does not depend on any opaque types, we eagerly compute + // its final result and write it into `self.propagated_borrowck_results`. This + // avoids having to compute its closure requirements modulo regions, as they + // are just the same as its final closure requirements. + let mut depends_on_opaques = input.infcx.has_opaque_types_in_storage(); - self.nested_bodies.get(&def_id).unwrap() + // Iterate over all nested bodies of `input`. If that nested body depends on + // opaque types, we apply its closure requirements modulo opaques. Otherwise + // we use the closure requirements from its final borrowck result. + // + // In case we've only applied the closure requirements modulo opaques, we have + // to later apply its closure requirements considering opaques, so we put that + // nested body back into `deferred_closure_requirements`. + for (def_id, args, locations) in mem::take(&mut input.deferred_closure_requirements) { + let closure_requirements = match self.propagated_borrowck_results.get(&def_id) { + None => { + depends_on_opaques = true; + input.deferred_closure_requirements.push((def_id, args, locations)); + &closure_requirements_modulo_opaques[&def_id] + } + Some(result) => &result.closure_requirements, + }; + + Self::apply_closure_requirements( + &mut input, + closure_requirements, + def_id, + args, + locations, + ); + } + + // In case the current body does depend on opaques and is a nested body, + // we need to compute its closure requirements modulo opaques so that + // we're able to use it when visiting its parent later in this function. + // + // If the current body does not depend on opaque types, we finish borrowck + // and write its result into `propagated_borrowck_results`. + if depends_on_opaques { + if def_id != self.root_def_id { + let req = Self::compute_closure_requirements_modulo_opaques(&input); + closure_requirements_modulo_opaques.insert(def_id, req); + } + self.collect_region_constraints_results.insert(def_id, input); + } else { + assert!(input.deferred_closure_requirements.is_empty()); + let result = borrowck_check_region_constraints(self, input); + self.propagated_borrowck_results.insert(def_id, result); + } + } } - pub(super) fn closure_requirements( - &mut self, - nested_body_def_id: LocalDefId, - ) -> &Option<ClosureRegionRequirements<'tcx>> { - &self.get_or_insert_nested(nested_body_def_id).closure_requirements + fn compute_closure_requirements_modulo_opaques( + input: &CollectRegionConstraintsResult<'tcx>, + ) -> Option<ClosureRegionRequirements<'tcx>> { + compute_closure_requirements_modulo_opaques( + &input.infcx, + &input.body_owned, + Rc::clone(&input.location_map), + &input.universal_region_relations, + &input.constraints, + ) } - pub(super) fn used_mut_upvars( - &mut self, - nested_body_def_id: LocalDefId, - ) -> &SmallVec<[FieldIdx; 8]> { - &self.get_or_insert_nested(nested_body_def_id).used_mut_upvars + fn apply_closure_requirements( + input: &mut CollectRegionConstraintsResult<'tcx>, + closure_requirements: &Option<ClosureRegionRequirements<'tcx>>, + closure_def_id: LocalDefId, + args: ty::GenericArgsRef<'tcx>, + locations: Locations, + ) { + if let Some(closure_requirements) = closure_requirements { + constraint_conversion::ConstraintConversion::new( + &input.infcx, + &input.universal_region_relations.universal_regions, + &input.region_bound_pairs, + &input.known_type_outlives_obligations, + locations, + input.body_owned.span, // irrelevant; will be overridden. + ConstraintCategory::Boring, // same as above. + &mut input.constraints, + ) + .apply_closure_requirements(closure_requirements, closure_def_id, args); + } } - pub(super) fn finalize(self) -> Result<&'tcx ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> { - if let Some(guar) = self.tainted_by_errors { - Err(guar) - } else { - Ok(self.tcx.arena.alloc(self.concrete_opaque_types)) + pub(super) fn do_mir_borrowck(&mut self) { + // The list of all bodies we need to borrowck. This first looks at + // nested bodies, and then their parents. This means accessing e.g. + // `used_mut_upvars` for a closure can assume that we've already + // checked that closure. + let all_bodies = self + .tcx + .nested_bodies_within(self.root_def_id) + .iter() + .chain(std::iter::once(self.root_def_id)); + for def_id in all_bodies { + let result = borrowck_collect_region_constraints(self, def_id); + self.collect_region_constraints_results.insert(def_id, result); + } + + // We now apply the closure requirements of nested bodies modulo + // regions. In case a body does not depend on opaque types, we + // eagerly check its region constraints and use the final closure + // requirements. + // + // We eagerly finish borrowck for bodies which don't depend on + // opaques. + self.apply_closure_requirements_modulo_opaques(); + + // We handle opaque type uses for all bodies together. + self.handle_opaque_type_uses(); + + // Now walk over all bodies which depend on opaque types and finish borrowck. + // + // We first apply the final closure requirements from nested bodies which also + // depend on opaque types and then finish borrow checking the parent. Bodies + // which don't depend on opaques have already been fully borrowchecked in + // `apply_closure_requirements_modulo_opaques` as an optimization. + for (def_id, mut input) in mem::take(&mut self.collect_region_constraints_results) { + for (def_id, args, locations) in mem::take(&mut input.deferred_closure_requirements) { + // We visit nested bodies before their parent, so we're already + // done with nested bodies at this point. + let closure_requirements = + &self.propagated_borrowck_results[&def_id].closure_requirements; + Self::apply_closure_requirements( + &mut input, + closure_requirements, + def_id, + args, + locations, + ); + } + + let result = borrowck_check_region_constraints(self, input); + self.propagated_borrowck_results.insert(def_id, result); } } } diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 7bf2df91470..d27a73535ba 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -19,6 +19,7 @@ use crate::type_check::{Locations, MirTypeckRegionConstraints, constraint_conver use crate::universal_regions::UniversalRegions; #[derive(Debug)] +#[derive(Clone)] // FIXME(#146079) pub(crate) struct UniversalRegionRelations<'tcx> { pub(crate) universal_regions: UniversalRegions<'tcx>, diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 0d363935f14..02be78f90b0 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -49,7 +49,7 @@ use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderI use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst}; use crate::type_check::free_region_relations::{CreateResult, UniversalRegionRelations}; use crate::universal_regions::{DefiningTy, UniversalRegions}; -use crate::{BorrowCheckRootCtxt, BorrowckInferCtxt, path_utils}; +use crate::{BorrowCheckRootCtxt, BorrowckInferCtxt, DeferredClosureRequirements, path_utils}; macro_rules! span_mirbug { ($context:expr, $elem:expr, $($message:tt)*) => ({ @@ -67,7 +67,7 @@ macro_rules! span_mirbug { } pub(crate) mod canonical; -mod constraint_conversion; +pub(crate) mod constraint_conversion; pub(crate) mod free_region_relations; mod input_output; pub(crate) mod liveness; @@ -142,6 +142,7 @@ pub(crate) fn type_check<'tcx>( None }; + let mut deferred_closure_requirements = Default::default(); let mut typeck = TypeChecker { root_cx, infcx, @@ -157,6 +158,7 @@ pub(crate) fn type_check<'tcx>( polonius_facts, borrow_set, constraints: &mut constraints, + deferred_closure_requirements: &mut deferred_closure_requirements, polonius_liveness, }; @@ -191,6 +193,7 @@ pub(crate) fn type_check<'tcx>( universal_region_relations, region_bound_pairs, known_type_outlives_obligations, + deferred_closure_requirements, polonius_context, } } @@ -230,6 +233,7 @@ struct TypeChecker<'a, 'tcx> { polonius_facts: &'a mut Option<PoloniusFacts>, borrow_set: &'a BorrowSet<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, + deferred_closure_requirements: &'a mut DeferredClosureRequirements<'tcx>, /// When using `-Zpolonius=next`, the liveness helper data used to create polonius constraints. polonius_liveness: Option<PoloniusLivenessContext>, } @@ -241,11 +245,13 @@ pub(crate) struct MirTypeckResults<'tcx> { pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, pub(crate) region_bound_pairs: Frozen<RegionBoundPairs<'tcx>>, pub(crate) known_type_outlives_obligations: Frozen<Vec<ty::PolyTypeOutlivesPredicate<'tcx>>>, + pub(crate) deferred_closure_requirements: DeferredClosureRequirements<'tcx>, pub(crate) polonius_context: Option<PoloniusContext>, } /// A collection of region constraints that must be satisfied for the /// program to be considered well-typed. +#[derive(Clone)] // FIXME(#146079) pub(crate) struct MirTypeckRegionConstraints<'tcx> { /// Maps from a `ty::Placeholder` to the corresponding /// `PlaceholderIndex` bit that we will use for it. @@ -2470,21 +2476,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, ) -> ty::InstantiatedPredicates<'tcx> { let root_def_id = self.root_cx.root_def_id(); - if let Some(closure_requirements) = &self.root_cx.closure_requirements(def_id) { - constraint_conversion::ConstraintConversion::new( - self.infcx, - self.universal_regions, - self.region_bound_pairs, - self.known_type_outlives_obligations, - locations, - self.body.span, // irrelevant; will be overridden. - ConstraintCategory::Boring, // same as above. - self.constraints, - ) - .apply_closure_requirements(closure_requirements, def_id, args); - } + // We will have to handle propagated closure requirements for this closure, + // but need to defer this until the nested body has been fully borrow checked. + self.deferred_closure_requirements.push((def_id, args, locations)); - // Now equate closure args to regions inherited from `root_def_id`. Fixes #98589. + // Equate closure args to regions inherited from `root_def_id`. Fixes #98589. let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, root_def_id); let parent_args = match tcx.def_kind(def_id) { diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 296a2735533..64a7b408434 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -40,6 +40,7 @@ use crate::BorrowckInferCtxt; use crate::renumber::RegionCtxt; #[derive(Debug)] +#[derive(Clone)] // FIXME(#146079) pub(crate) struct UniversalRegions<'tcx> { indices: UniversalRegionIndices<'tcx>, @@ -200,6 +201,7 @@ impl<'tcx> DefiningTy<'tcx> { } #[derive(Debug)] +#[derive(Clone)] // FIXME(#146079) struct UniversalRegionIndices<'tcx> { /// For those regions that may appear in the parameter environment /// ('static and early-bound regions), we maintain a map from the diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml index 9ca44d67150..e56b9e641a1 100644 --- a/compiler/rustc_builtin_macros/Cargo.toml +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -30,6 +30,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index bc0a0f034b2..3a28dd7e73c 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -44,9 +44,8 @@ pub(crate) fn codegen_fn<'tcx>( let _mir_guard = crate::PrintOnPanic(|| { let mut buf = Vec::new(); with_no_trimmed_paths!({ - use rustc_middle::mir::pretty; - let options = pretty::PrettyPrintMirOptions::from_cli(tcx); - pretty::write_mir_fn(tcx, mir, &mut |_, _| Ok(()), &mut buf, options).unwrap(); + let writer = pretty::MirWriter::new(tcx); + writer.write_mir_fn(mir, &mut buf).unwrap(); }); String::from_utf8_lossy(&buf).into_owned() }); diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index b04310f3d54..2d11628250c 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -8,15 +8,15 @@ test = false [dependencies] # tidy-alphabetical-start -bitflags.workspace = true +bitflags = "2.4.1" # To avoid duplicate dependencies, this should match the version of gimli used # by `rustc_codegen_ssa` via its `thorin-dwp` dependency. gimli = "0.31" -itertools.workspace = true -libc.workspace = true -measureme.workspace = true +itertools = "0.12" +libc = "0.2" +measureme = "12.0.1" object = { version = "0.37.0", default-features = false, features = ["std", "read"] } -rustc-demangle.workspace = true +rustc-demangle = "0.1.21" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } @@ -38,9 +38,9 @@ rustc_span = { path = "../rustc_span" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_target = { path = "../rustc_target" } serde = { version = "1", features = ["derive"] } -serde_json.workspace = true +serde_json = "1" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [features] diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 7a340ae83f3..f9dc48e3aba 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -26,6 +26,7 @@ static LLVM_OBJECT_READER: ObjectReader = ObjectReader { get_symbols: get_llvm_object_symbols, is_64_bit_object_file: llvm_is_64_bit_object_file, is_ec_object_file: llvm_is_ec_object_file, + is_any_arm64_coff: llvm_is_any_arm64_coff, get_xcoff_member_alignment: DEFAULT_OBJECT_READER.get_xcoff_member_alignment, }; @@ -95,3 +96,7 @@ fn llvm_is_64_bit_object_file(buf: &[u8]) -> bool { fn llvm_is_ec_object_file(buf: &[u8]) -> bool { unsafe { llvm::LLVMRustIsECObject(buf.as_ptr(), buf.len()) } } + +fn llvm_is_any_arm64_coff(buf: &[u8]) -> bool { + unsafe { llvm::LLVMRustIsAnyArm64Coff(buf.as_ptr(), buf.len()) } +} diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index ba590851dbd..b66fc157b3c 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2686,6 +2686,8 @@ unsafe extern "C" { pub(crate) fn LLVMRustIsECObject(buf_ptr: *const u8, buf_len: usize) -> bool; + pub(crate) fn LLVMRustIsAnyArm64Coff(buf_ptr: *const u8, buf_len: usize) -> bool; + pub(crate) fn LLVMRustSetNoSanitizeAddress(Global: &Value); pub(crate) fn LLVMRustSetNoSanitizeHWAddress(Global: &Value); } diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index ce079f3cb0a..7eb5d302058 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -28,9 +28,12 @@ fn round_pointer_up_to_alignment<'ll>( align: Align, ptr_ty: &'ll Type, ) -> &'ll Value { - let mut ptr_as_int = bx.ptrtoint(addr, bx.cx().type_isize()); - ptr_as_int = round_up_to_alignment(bx, ptr_as_int, align); - bx.inttoptr(ptr_as_int, ptr_ty) + let ptr = bx.inbounds_ptradd(addr, bx.const_i32(align.bytes() as i32 - 1)); + bx.call_intrinsic( + "llvm.ptrmask", + &[ptr_ty, bx.type_i32()], + &[ptr, bx.const_int(bx.isize_ty, -(align.bytes() as isize) as i64)], + ) } fn emit_direct_ptr_va_arg<'ll, 'tcx>( diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 57e1fee2c0a..2dfbc581643 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -5,13 +5,13 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -ar_archive_writer = "0.4.2" -bitflags.workspace = true +ar_archive_writer = "0.5" +bitflags = "2.4.1" bstr = "1.11.3" # `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version # per crate", so if you change this, you need to also change it in `rustc_llvm`. cc = "=1.2.16" -itertools.workspace = true +itertools = "0.12" pathdiff = "0.2.0" regex = "1.4" rustc_abi = { path = "../rustc_abi" } @@ -37,18 +37,18 @@ rustc_span = { path = "../rustc_span" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -serde_json.workspace = true +serde_json = "1.0.59" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tempfile.workspace = true -thin-vec.workspace = true +tempfile = "3.2" +thin-vec = "0.2.12" thorin-dwp = "0.9" -tracing.workspace = true +tracing = "0.1" wasm-encoder = "0.219" # tidy-alphabetical-end [target.'cfg(unix)'.dependencies] # tidy-alphabetical-start -libc.workspace = true +libc = "0.2.50" # tidy-alphabetical-end [dependencies.object] diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 84a56f6b0b5..cfd8ceac3a6 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -40,16 +40,18 @@ pub struct ImportLibraryItem { pub is_data: bool, } -impl From<ImportLibraryItem> for COFFShortExport { - fn from(item: ImportLibraryItem) -> Self { +impl ImportLibraryItem { + fn into_coff_short_export(self, sess: &Session) -> COFFShortExport { + let import_name = (sess.target.arch == "arm64ec").then(|| self.name.clone()); COFFShortExport { - name: item.name, + name: self.name, ext_name: None, - symbol_name: item.symbol_name, - alias_target: None, - ordinal: item.ordinal.unwrap_or(0), - noname: item.ordinal.is_some(), - data: item.is_data, + symbol_name: self.symbol_name, + import_name, + export_as: None, + ordinal: self.ordinal.unwrap_or(0), + noname: self.ordinal.is_some(), + data: self.is_data, private: false, constant: false, } @@ -113,7 +115,8 @@ pub trait ArchiveBuilderBuilder { .emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() }), }; - let exports = items.into_iter().map(Into::into).collect::<Vec<_>>(); + let exports = + items.into_iter().map(|item| item.into_coff_short_export(sess)).collect::<Vec<_>>(); let machine = match &*sess.target.arch { "x86_64" => MachineTypes::AMD64, "x86" => MachineTypes::I386, @@ -134,6 +137,7 @@ pub trait ArchiveBuilderBuilder { // when linking a rust staticlib using `/WHOLEARCHIVE`. // See #129020 true, + &[], ) { sess.dcx() .emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() }); @@ -527,7 +531,7 @@ impl<'a> ArArchiveBuilder<'a> { &entries, archive_kind, false, - /* is_ec = */ self.sess.target.arch == "arm64ec", + /* is_ec = */ Some(self.sess.target.arch == "arm64ec"), )?; archive_tmpfile.flush()?; drop(archive_tmpfile); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index c3dc3e42b83..5f6976f5d00 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -519,6 +519,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match self.locals[mir::Local::from_usize(1 + va_list_arg_idx)] { LocalRef::Place(va_list) => { bx.va_end(va_list.val.llval); + + // Explicitly end the lifetime of the `va_list`, this matters for LLVM. + bx.lifetime_end(va_list.val.llval, va_list.layout.size); } _ => bug!("C-variadic function must have a `VaList` place"), } diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml index acf19b0f2fc..51dcee8d882 100644 --- a/compiler/rustc_const_eval/Cargo.toml +++ b/compiler/rustc_const_eval/Cargo.toml @@ -5,9 +5,9 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -either.workspace = true +either = "1" rustc_abi = { path = "../rustc_abi" } -rustc_apfloat.workspace = true +rustc_apfloat = "0.2.0" rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } @@ -22,5 +22,5 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 852fc11350b..c8296e05f6b 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -6,15 +6,15 @@ edition = "2024" [dependencies] # tidy-alphabetical-start arrayvec = { version = "0.7", default-features = false } -bitflags.workspace = true -either.workspace = true +bitflags = "2.4.1" +either = "1.0" elsa = "1.11.0" ena = "0.14.3" -indexmap.workspace = true +indexmap = "2.4.0" jobserver_crate = { version = "0.1.28", package = "jobserver" } -measureme.workspace = true +measureme = "12.0.1" parking_lot = "0.12" -rustc-hash.workspace = true +rustc-hash = "2.0.0" rustc-stable-hash = { version = "0.1.0", features = ["nightly"] } rustc_arena = { path = "../rustc_arena" } rustc_graphviz = { path = "../rustc_graphviz" } @@ -25,9 +25,9 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_thread_pool = { path = "../rustc_thread_pool" } smallvec = { version = "1.8.1", features = ["const_generics", "union", "may_dangle"] } stacker = "0.1.17" -tempfile.workspace = true -thin-vec.workspace = true -tracing.workspace = true +tempfile = "3.2" +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end [dependencies.hashbrown] @@ -47,7 +47,7 @@ features = [ [target.'cfg(unix)'.dependencies] # tidy-alphabetical-start -libc.workspace = true +libc = "0.2" # tidy-alphabetical-end [target.'cfg(not(target_arch = "wasm32"))'.dependencies] diff --git a/compiler/rustc_data_structures/src/frozen.rs b/compiler/rustc_data_structures/src/frozen.rs index 73190574667..4a60d17de2a 100644 --- a/compiler/rustc_data_structures/src/frozen.rs +++ b/compiler/rustc_data_structures/src/frozen.rs @@ -46,7 +46,7 @@ //! Frozen::freeze(new_bar)`). /// An owned immutable value. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Frozen<T>(T); impl<T> Frozen<T> { diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 196c8aa3547..ae1dbd2cf51 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -49,14 +49,14 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ty_utils = { path = "../rustc_ty_utils" } -serde_json.workspace = true +serde_json = "1.0.59" shlex = "1.0" -tracing.workspace = true +tracing = { version = "0.1.35" } # tidy-alphabetical-end [target.'cfg(all(unix, any(target_env = "gnu", target_os = "macos")))'.dependencies] # tidy-alphabetical-start -libc.workspace = true +libc = "0.2" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] diff --git a/compiler/rustc_error_messages/Cargo.toml b/compiler/rustc_error_messages/Cargo.toml index 7d2dc20e136..db22e065907 100644 --- a/compiler/rustc_error_messages/Cargo.toml +++ b/compiler/rustc_error_messages/Cargo.toml @@ -17,6 +17,6 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } -tracing.workspace = true +tracing = "0.1" unic-langid = { version = "0.9.0", features = ["macros"] } # tidy-alphabetical-end diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 67a17ce88fa..7912b8e6098 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -21,10 +21,10 @@ rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } serde = { version = "1.0.125", features = ["derive"] } -serde_json.workspace = true +serde_json = "1.0.59" termcolor = "1.2.0" termize = "0.2" -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index 9bb7143af51..f897833d85c 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -29,6 +29,6 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml index b58f2375852..a4746ac455c 100644 --- a/compiler/rustc_feature/Cargo.toml +++ b/compiler/rustc_feature/Cargo.toml @@ -9,5 +9,5 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } rustc_span = { path = "../rustc_span" } serde = { version = "1.0.125", features = ["derive"] } -serde_json.workspace = true +serde_json = "1.0.59" # tidy-alphabetical-end diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 9fe55216f93..6af4cfb0e56 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -203,6 +203,9 @@ declare_features! ( (accepted, expr_fragment_specifier_2024, "1.83.0", Some(123742)), /// Allows arbitrary expressions in key-value attributes at parse time. (accepted, extended_key_value_attributes, "1.54.0", Some(78835)), + /// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions + /// for functions with varargs. + (accepted, extended_varargs_abi_support, "CURRENT_RUSTC_VERSION", Some(100189)), /// Allows resolving absolute paths as paths from other crates. (accepted, extern_absolute_paths, "1.30.0", Some(44660)), /// Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 92b435b4b01..573e9aab055 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -492,9 +492,6 @@ declare_features! ( (incomplete, explicit_tail_calls, "1.72.0", Some(112788)), /// Allows using `#[export_stable]` which indicates that an item is exportable. (incomplete, export_stable, "1.88.0", Some(139939)), - /// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions - /// for functions with varargs. - (unstable, extended_varargs_abi_support, "1.65.0", Some(100189)), /// Allows using `system` as a calling convention with varargs. (unstable, extern_system_varargs, "1.86.0", Some(136946)), /// Allows defining `extern type`s. diff --git a/compiler/rustc_fluent_macro/Cargo.toml b/compiler/rustc_fluent_macro/Cargo.toml index 60afd9aca87..d7ef4280aef 100644 --- a/compiler/rustc_fluent_macro/Cargo.toml +++ b/compiler/rustc_fluent_macro/Cargo.toml @@ -11,8 +11,8 @@ proc-macro = true annotate-snippets = "0.11" fluent-bundle = "0.16" fluent-syntax = "0.12" -proc-macro2.workspace = true -quote.workspace = true +proc-macro2 = "1" +quote = "1" syn = { version = "2", features = ["full"] } unic-langid = { version = "0.9.0", features = ["macros"] } # tidy-alphabetical-end diff --git a/compiler/rustc_fs_util/Cargo.toml b/compiler/rustc_fs_util/Cargo.toml index 37970e81fea..90a6acade8b 100644 --- a/compiler/rustc_fs_util/Cargo.toml +++ b/compiler/rustc_fs_util/Cargo.toml @@ -5,5 +5,5 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -tempfile.workspace = true +tempfile = "3.7.1" # tidy-alphabetical-end diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index e74fcfe7455..1008a3e787d 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -5,8 +5,8 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true -odht.workspace = true +bitflags = "2.9.1" +odht = { version = "0.3.1", features = ["nightly"] } rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } @@ -21,6 +21,6 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e397c286de2..e3c27c73638 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1884,8 +1884,8 @@ pub enum PatKind<'hir> { Binding(BindingMode, HirId, Ident, Option<&'hir Pat<'hir>>), /// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`). - /// The `bool` is `true` in the presence of a `..`. - Struct(QPath<'hir>, &'hir [PatField<'hir>], bool), + /// The `Option` contains the span of a possible `..`. + Struct(QPath<'hir>, &'hir [PatField<'hir>], Option<Span>), /// A tuple struct/variant pattern `Variant(x, y, .., z)`. /// If the `..` pattern fragment is present, then `DotDotPos` denotes its position. @@ -4979,8 +4979,8 @@ mod size_asserts { static_assert_size!(ItemKind<'_>, 64); static_assert_size!(LetStmt<'_>, 72); static_assert_size!(Param<'_>, 32); - static_assert_size!(Pat<'_>, 72); - static_assert_size!(PatKind<'_>, 48); + static_assert_size!(Pat<'_>, 80); + static_assert_size!(PatKind<'_>, 56); static_assert_size!(Path<'_>, 40); static_assert_size!(PathSegment<'_>, 48); static_assert_size!(QPath<'_>, 24); diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index bb86beb2251..e5017794d8f 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -9,7 +9,7 @@ doctest = false [dependencies] # tidy-alphabetical-start -itertools.workspace = true +itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } @@ -29,5 +29,5 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index eccb88a938f..08b344638dd 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -978,7 +978,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), tcx.ensure_ok().fn_sig(def_id); let item = tcx.hir_foreign_item(item); let hir::ForeignItemKind::Fn(sig, ..) = item.kind else { bug!() }; - require_c_abi_if_c_variadic(tcx, sig.decl, abi, item.span); + check_c_variadic_abi(tcx, sig.decl, abi, item.span); } DefKind::Static { .. } => { tcx.ensure_ok().codegen_fn_attrs(def_id); diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 2e4b151d4dc..b5c0ca4727c 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -98,7 +98,7 @@ use tracing::debug; use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys; use self::region::region_scope_tree; -use crate::{errors, require_c_abi_if_c_variadic}; +use crate::{check_c_variadic_abi, errors}; /// Adds query implementations to the [Providers] vtable, see [`rustc_middle::query`] pub(super) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index c7b984d9b25..c5e079fe89a 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -52,11 +52,11 @@ use rustc_trait_selection::traits::{self, FulfillmentError}; use tracing::{debug, instrument}; use crate::check::check_abi; +use crate::check_c_variadic_abi; use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation}; use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::middle::resolve_bound_vars as rbv; -use crate::require_c_abi_if_c_variadic; /// A path segment that is semantically allowed to have generic arguments. #[derive(Debug)] @@ -2412,7 +2412,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ty::new_tup_from_iter(tcx, fields.iter().map(|t| self.lower_ty(t))) } hir::TyKind::FnPtr(bf) => { - require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, hir_ty.span); + check_c_variadic_abi(tcx, bf.decl, bf.abi, hir_ty.span); Ty::new_fn_ptr( tcx, diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 44a5ceed469..2562ab7542a 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -90,7 +90,7 @@ mod outlives; mod variance; pub use errors::NoVariantNamed; -use rustc_abi::ExternAbi; +use rustc_abi::{CVariadicStatus, ExternAbi}; use rustc_hir::def::DefKind; use rustc_hir::lints::DelayedLint; use rustc_hir::{self as hir}; @@ -99,7 +99,6 @@ use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_session::parse::feature_err; -use rustc_span::symbol::sym; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits; @@ -108,46 +107,34 @@ use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer}; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } -fn require_c_abi_if_c_variadic( - tcx: TyCtxt<'_>, - decl: &hir::FnDecl<'_>, - abi: ExternAbi, - span: Span, -) { - // ABIs which can stably use varargs - if !decl.c_variadic || matches!(abi, ExternAbi::C { .. } | ExternAbi::Cdecl { .. }) { +fn check_c_variadic_abi(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: ExternAbi, span: Span) { + if !decl.c_variadic { + // Not even a variadic function. return; } - // ABIs with feature-gated stability - let extended_abi_support = tcx.features().extended_varargs_abi_support(); - let extern_system_varargs = tcx.features().extern_system_varargs(); - - // If the feature gate has been enabled, we can stop here - if extern_system_varargs && let ExternAbi::System { .. } = abi { - return; - }; - if extended_abi_support && abi.supports_varargs() { - return; - }; - - // Looks like we need to pick an error to emit. - // Is there any feature which we could have enabled to make this work? - let unstable_explain = - format!("C-variadic functions with the {abi} calling convention are unstable"); - match abi { - ExternAbi::System { .. } => { - feature_err(&tcx.sess, sym::extern_system_varargs, span, unstable_explain) + match abi.supports_c_variadic() { + CVariadicStatus::Stable => {} + CVariadicStatus::NotSupported => { + tcx.dcx() + .create_err(errors::VariadicFunctionCompatibleConvention { + span, + convention: &format!("{abi}"), + }) + .emit(); } - abi if abi.supports_varargs() => { - feature_err(&tcx.sess, sym::extended_varargs_abi_support, span, unstable_explain) + CVariadicStatus::Unstable { feature } => { + if !tcx.features().enabled(feature) { + feature_err( + &tcx.sess, + feature, + span, + format!("C-variadic functions with the {abi} calling convention are unstable"), + ) + .emit(); + } } - _ => tcx.dcx().create_err(errors::VariadicFunctionCompatibleConvention { - span, - convention: &format!("{abi}"), - }), } - .emit(); } /// Adds query implementations to the [Providers] vtable, see [`rustc_middle::query`] diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index be5859b57c5..52b29e05dcb 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1958,12 +1958,12 @@ impl<'a> State<'a> { self.print_qpath(qpath, true); self.nbsp(); self.word("{"); - let empty = fields.is_empty() && !etc; + let empty = fields.is_empty() && etc.is_none(); if !empty { self.space(); } self.commasep_cmnt(Consistent, fields, |s, f| s.print_patfield(f), |f| f.pat.span); - if etc { + if etc.is_some() { if !fields.is_empty() { self.word_space(","); } diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml index 5af0c6134ca..f00125c3e09 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools.workspace = true +itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } @@ -25,5 +25,5 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index e37ea031672..652644ad78c 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -117,7 +117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(Ambiguity(..)) => true, Err(PrivateMatch(..)) => false, Err(IllegalSizedBound { .. }) => true, - Err(BadReturnType) => false, + Err(BadReturnType) => true, Err(ErrorReported(_)) => false, } } diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 87a7cd62ae5..11defc3aa03 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -962,13 +962,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (opt_rhs_expr, opt_rhs_ty) = opt_rhs.unzip(); let cause = self.cause( span, - ObligationCauseCode::BinOp { - lhs_hir_id: lhs_expr.hir_id, - rhs_hir_id: opt_rhs_expr.map(|expr| expr.hir_id), - rhs_span: opt_rhs_expr.map(|expr| expr.span), - rhs_is_lit: opt_rhs_expr - .is_some_and(|expr| matches!(expr.kind, hir::ExprKind::Lit(_))), - output_ty: expected.only_has_type(self), + match opt_rhs_expr { + Some(rhs) => ObligationCauseCode::BinOp { + lhs_hir_id: lhs_expr.hir_id, + rhs_hir_id: rhs.hir_id, + rhs_span: rhs.span, + rhs_is_lit: matches!(rhs.kind, hir::ExprKind::Lit(_)), + output_ty: expected.only_has_type(self), + }, + None => ObligationCauseCode::UnOp { hir_id: lhs_expr.hir_id }, }, ); diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 7dc736e5e6b..f735c0a4160 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -605,7 +605,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, PatKind::Struct(_, fields, has_rest_pat) => match opt_path_res.unwrap() { Ok(ResolvedPat { ty, kind: ResolvedPatKind::Struct { variant } }) => self - .check_pat_struct(pat, fields, has_rest_pat, ty, variant, expected, pat_info), + .check_pat_struct( + pat, + fields, + has_rest_pat.is_some(), + ty, + variant, + expected, + pat_info, + ), Err(guar) => { let ty_err = Ty::new_error(self.tcx, guar); for field in fields { @@ -2428,7 +2436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let len = unmentioned_fields.len(); let (prefix, postfix, sp) = match fields { [] => match &pat.kind { - PatKind::Struct(path, [], false) => { + PatKind::Struct(path, [], None) => { (" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi())) } _ => return err, diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml index 8d7f2eb8414..db0a5841887 100644 --- a/compiler/rustc_incremental/Cargo.toml +++ b/compiler/rustc_incremental/Cargo.toml @@ -19,6 +19,6 @@ rustc_middle = { path = "../rustc_middle" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_index_macros/Cargo.toml b/compiler/rustc_index_macros/Cargo.toml index 8593bde2615..34f3109a526 100644 --- a/compiler/rustc_index_macros/Cargo.toml +++ b/compiler/rustc_index_macros/Cargo.toml @@ -8,8 +8,8 @@ proc-macro = true [dependencies] # tidy-alphabetical-start -proc-macro2.workspace = true -quote.workspace = true +proc-macro2 = "1" +quote = "1" syn = { version = "2.0.9", features = ["full", "extra-traits"] } # tidy-alphabetical-end diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index 6d97fa6af1f..08c03614884 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -18,6 +18,6 @@ rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index d1507f08c06..d105d24bed7 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -989,6 +989,10 @@ impl<'tcx> InferCtxt<'tcx> { storage.var_infos.clone() } + pub fn has_opaque_types_in_storage(&self) -> bool { + !self.inner.borrow().opaque_type_storage.is_empty() + } + #[instrument(level = "debug", skip(self), ret)] pub fn take_opaque_types(&self) -> Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> { self.inner.borrow_mut().opaque_type_storage.take_opaque_types().collect() diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 40152e78f8a..473ac5e0cea 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -46,7 +46,7 @@ rustc_thread_pool = { path = "../rustc_thread_pool" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_traits = { path = "../rustc_traits" } rustc_ty_utils = { path = "../rustc_ty_utils" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [dev-dependencies] diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml index e0019fb1821..343b81bd171 100644 --- a/compiler/rustc_lexer/Cargo.toml +++ b/compiler/rustc_lexer/Cargo.toml @@ -14,7 +14,7 @@ Rust lexer used by rustc. No stability guarantees are provided. # Note that this crate purposefully does not depend on other rustc crates [dependencies] -memchr.workspace = true +memchr = "2.7.4" unicode-properties = { version = "0.1.0", default-features = false, features = ["emoji"] } unicode-xid = "0.2.0" diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 483cc3e93dc..d10b1920343 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -550,28 +550,20 @@ impl Cursor<'_> { self.eat_while(|ch| ch != '\n' && is_whitespace(ch)); let invalid_infostring = self.first() != '\n'; - let mut s = self.as_str(); let mut found = false; - let mut size = 0; - while let Some(closing) = s.find(&"-".repeat(length_opening as usize)) { - let preceding_chars_start = s[..closing].rfind("\n").map_or(0, |i| i + 1); - if s[preceding_chars_start..closing].chars().all(is_whitespace) { - // candidate found - self.bump_bytes(size + closing); - // in case like - // ---cargo - // --- blahblah - // or - // ---cargo - // ---- - // combine those stuff into this frontmatter token such that it gets detected later. - self.eat_until(b'\n'); - found = true; - break; - } else { - s = &s[closing + length_opening as usize..]; - size += closing + length_opening as usize; - } + let nl_fence_pattern = format!("\n{:-<1$}", "", length_opening as usize); + if let Some(closing) = self.as_str().find(&nl_fence_pattern) { + // candidate found + self.bump_bytes(closing + nl_fence_pattern.len()); + // in case like + // ---cargo + // --- blahblah + // or + // ---cargo + // ---- + // combine those stuff into this frontmatter token such that it gets detected later. + self.eat_until(b'\n'); + found = true; } if !found { diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index 7900e4b9ab2..7718f16984d 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -24,6 +24,6 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing.workspace = true +tracing = "0.1" unicode-security = "0.1.0" # tidy-alphabetical-end diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 97aa1065967..ce92263babd 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2309,10 +2309,10 @@ declare_lint! { /// ### Example /// /// ```rust - /// #![feature(sanitize)] + /// #![cfg_attr(not(bootstrap), feature(sanitize))] /// /// #[inline(always)] - /// #[sanitize(address = "off")] + /// #[cfg_attr(not(bootstrap), sanitize(address = "off"))] /// fn x() {} /// /// fn main() { @@ -4832,13 +4832,16 @@ declare_lint! { /// /// ### Example /// - /// ```rust,compile_fail + #[cfg_attr(not(bootstrap), doc = "```rust,compile_fail")] + #[cfg_attr(bootstrap, doc = "```rust")] /// #![doc = in_root!()] /// /// macro_rules! in_root { () => { "" } } /// /// fn main() {} - /// ``` + #[cfg_attr(not(bootstrap), doc = "```")] + #[cfg_attr(bootstrap, doc = "```")] + // ^ Needed to avoid tidy warning about odd number of backticks /// /// {{produces}} /// diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index e74de453be2..cd352ce3d0f 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -libc.workspace = true +libc = "0.2.73" # tidy-alphabetical-end [build-dependencies] diff --git a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp index a910e78d489..fccfff65cfc 100644 --- a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp @@ -103,14 +103,14 @@ LLVMRustGetSymbols(char *BufPtr, size_t BufLen, void *State, #define TRUE_PTR (void *)1 #define FALSE_PTR (void *)0 -extern "C" bool LLVMRustIs64BitSymbolicFile(char *BufPtr, size_t BufLen) { +bool withBufferAsSymbolicFile( + char *BufPtr, size_t BufLen, + std::function<bool(object::SymbolicFile &)> Callback) { std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer( StringRef(BufPtr, BufLen), StringRef("LLVMRustGetSymbolsObject"), false); SmallString<0> SymNameBuf; auto SymName = raw_svector_ostream(SymNameBuf); - // Code starting from this line is copied from s64BitSymbolicFile in - // ArchiveWriter.cpp. // In the scenario when LLVMContext is populated SymbolicFile will contain a // reference to it, thus SymbolicFile should be destroyed first. LLVMContext Context; @@ -120,48 +120,63 @@ extern "C" bool LLVMRustIs64BitSymbolicFile(char *BufPtr, size_t BufLen) { return false; } std::unique_ptr<object::SymbolicFile> Obj = std::move(*ObjOrErr); - - return Obj != nullptr ? Obj->is64Bit() : false; -} - -extern "C" bool LLVMRustIsECObject(char *BufPtr, size_t BufLen) { - std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer( - StringRef(BufPtr, BufLen), StringRef("LLVMRustGetSymbolsObject"), false); - SmallString<0> SymNameBuf; - auto SymName = raw_svector_ostream(SymNameBuf); - - // In the scenario when LLVMContext is populated SymbolicFile will contain a - // reference to it, thus SymbolicFile should be destroyed first. - LLVMContext Context; - Expected<std::unique_ptr<object::SymbolicFile>> ObjOrErr = - getSymbolicFile(Buf->getMemBufferRef(), Context); - if (!ObjOrErr) { - return false; - } - std::unique_ptr<object::SymbolicFile> Obj = std::move(*ObjOrErr); - if (Obj == nullptr) { return false; } + return Callback(*Obj); +} - // Code starting from this line is copied from isECObject in - // ArchiveWriter.cpp with an extra #if to work with LLVM 17. - if (Obj->isCOFF()) - return cast<llvm::object::COFFObjectFile>(&*Obj)->getMachine() != - COFF::IMAGE_FILE_MACHINE_ARM64; - - if (Obj->isCOFFImportFile()) - return cast<llvm::object::COFFImportFile>(&*Obj)->getMachine() != - COFF::IMAGE_FILE_MACHINE_ARM64; - - if (Obj->isIR()) { - Expected<std::string> TripleStr = - getBitcodeTargetTriple(Obj->getMemoryBufferRef()); - if (!TripleStr) - return false; - Triple T(*TripleStr); - return T.isWindowsArm64EC() || T.getArch() == Triple::x86_64; - } +extern "C" bool LLVMRustIs64BitSymbolicFile(char *BufPtr, size_t BufLen) { + return withBufferAsSymbolicFile( + BufPtr, BufLen, [](object::SymbolicFile &Obj) { return Obj.is64Bit(); }); +} + +extern "C" bool LLVMRustIsECObject(char *BufPtr, size_t BufLen) { + return withBufferAsSymbolicFile( + BufPtr, BufLen, [](object::SymbolicFile &Obj) { + // Code starting from this line is copied from isECObject in + // ArchiveWriter.cpp with an extra #if to work with LLVM 17. + if (Obj.isCOFF()) + return cast<llvm::object::COFFObjectFile>(&Obj)->getMachine() != + COFF::IMAGE_FILE_MACHINE_ARM64; + + if (Obj.isCOFFImportFile()) + return cast<llvm::object::COFFImportFile>(&Obj)->getMachine() != + COFF::IMAGE_FILE_MACHINE_ARM64; + + if (Obj.isIR()) { + Expected<std::string> TripleStr = + getBitcodeTargetTriple(Obj.getMemoryBufferRef()); + if (!TripleStr) + return false; + Triple T(*TripleStr); + return T.isWindowsArm64EC() || T.getArch() == Triple::x86_64; + } + + return false; + }); +} - return false; +extern "C" bool LLVMRustIsAnyArm64Coff(char *BufPtr, size_t BufLen) { + return withBufferAsSymbolicFile( + BufPtr, BufLen, [](object::SymbolicFile &Obj) { + // Code starting from this line is copied from isAnyArm64COFF in + // ArchiveWriter.cpp. + if (Obj.isCOFF()) + return COFF::isAnyArm64(cast<COFFObjectFile>(&Obj)->getMachine()); + + if (Obj.isCOFFImportFile()) + return COFF::isAnyArm64(cast<COFFImportFile>(&Obj)->getMachine()); + + if (Obj.isIR()) { + Expected<std::string> TripleStr = + getBitcodeTargetTriple(Obj.getMemoryBufferRef()); + if (!TripleStr) + return false; + Triple T(*TripleStr); + return T.isOSWindows() && T.getArch() == Triple::aarch64; + } + + return false; + }); } diff --git a/compiler/rustc_log/Cargo.toml b/compiler/rustc_log/Cargo.toml index e9d7b4723f8..c673d51a1d4 100644 --- a/compiler/rustc_log/Cargo.toml +++ b/compiler/rustc_log/Cargo.toml @@ -5,10 +5,10 @@ edition = "2024" [dependencies] # tidy-alphabetical-start +tracing = "0.1.28" tracing-core = "=0.1.30" # FIXME(Nilstrieb) tracing has a deadlock: https://github.com/tokio-rs/tracing/issues/2635 tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } tracing-tree = "0.3.1" -tracing.workspace = true # tidy-alphabetical-end [features] diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml index 5add2691b88..f9d3b758359 100644 --- a/compiler/rustc_macros/Cargo.toml +++ b/compiler/rustc_macros/Cargo.toml @@ -8,8 +8,8 @@ proc-macro = true [dependencies] # tidy-alphabetical-start -proc-macro2.workspace = true -quote.workspace = true +proc-macro2 = "1" +quote = "1" syn = { version = "2.0.9", features = ["full"] } synstructure = "0.13.0" # tidy-alphabetical-end diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index a8f3dd18353..1b40d9f684e 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -5,9 +5,9 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true +bitflags = "2.4.1" libloading = "0.8.0" -odht.workspace = true +odht = { version = "0.3.1", features = ["nightly"] } rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } @@ -30,11 +30,11 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -tempfile.workspace = true -tracing.workspace = true +tempfile = "3.7.1" +tracing = "0.1" # tidy-alphabetical-end [target.'cfg(target_os = "aix")'.dependencies] # tidy-alphabetical-start -libc.workspace = true +libc = "0.2" # tidy-alphabetical-end diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index f0832405567..fbcce16cedc 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -5,12 +5,12 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true -either.workspace = true +bitflags = "2.4.1" +either = "1.5.0" gsgdt = "0.1.2" -polonius-engine.workspace = true +polonius-engine = "0.13.0" rustc_abi = { path = "../rustc_abi" } -rustc_apfloat.workspace = true +rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_ast_ir = { path = "../rustc_ast_ir" } @@ -34,8 +34,8 @@ rustc_target = { path = "../rustc_target" } rustc_thread_pool = { path = "../rustc_thread_pool" } rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end [features] diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index c977e5329c2..da2245b12d2 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -62,9 +62,7 @@ pub use terminator::*; pub use self::generic_graph::graphviz_safe_def_name; pub use self::graphviz::write_mir_graphviz; -pub use self::pretty::{ - PassWhere, create_dump_file, display_allocation, dump_enabled, dump_mir, write_mir_pretty, -}; +pub use self::pretty::{MirDumper, PassWhere, display_allocation, write_mir_pretty}; /// Types for locals pub type LocalDecls<'tcx> = IndexSlice<Local, LocalDecl<'tcx>>; diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 128ae8549f7..a7d99f513a1 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -44,7 +44,7 @@ pub enum PassWhere { } /// Cosmetic options for pretty-printing the MIR contents, gathered from the CLI. Each pass can -/// override these when dumping its own specific MIR information with [`dump_mir_with_options`]. +/// override these when dumping its own specific MIR information with `dump_mir`. #[derive(Copy, Clone)] pub struct PrettyPrintMirOptions { /// Whether to include extra comments, like span info. From `-Z mir-include-spans`. @@ -58,277 +58,253 @@ impl PrettyPrintMirOptions { } } -/// If the session is properly configured, dumps a human-readable representation of the MIR (with -/// default pretty-printing options) into: -/// -/// ```text -/// rustc.node<node_id>.<pass_num>.<pass_name>.<disambiguator> -/// ``` -/// -/// Output from this function is controlled by passing `-Z dump-mir=<filter>`, -/// where `<filter>` takes the following forms: -/// -/// - `all` -- dump MIR for all fns, all passes, all everything -/// - a filter defined by a set of substrings combined with `&` and `|` -/// (`&` has higher precedence). At least one of the `|`-separated groups -/// must match; an `|`-separated group matches if all of its `&`-separated -/// substrings are matched. -/// -/// Example: -/// -/// - `nll` == match if `nll` appears in the name -/// - `foo & nll` == match if `foo` and `nll` both appear in the name -/// - `foo & nll | typeck` == match if `foo` and `nll` both appear in the name -/// or `typeck` appears in the name. -/// - `foo & nll | bar & typeck` == match if `foo` and `nll` both appear in the name -/// or `typeck` and `bar` both appear in the name. -#[inline] -pub fn dump_mir<'tcx, F>( - tcx: TyCtxt<'tcx>, - pass_num: bool, - pass_name: &str, - disambiguator: &dyn Display, - body: &Body<'tcx>, - extra_data: F, -) where - F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>, -{ - dump_mir_with_options( - tcx, - pass_num, - pass_name, - disambiguator, - body, - extra_data, - PrettyPrintMirOptions::from_cli(tcx), - ); +/// Manages MIR dumping, which is MIR writing done to a file with a specific name. In particular, +/// it makes it impossible to dump MIR to one of these files when it hasn't been requested from the +/// command line. Layered on top of `MirWriter`, which does the actual writing. +pub struct MirDumper<'dis, 'de, 'tcx> { + show_pass_num: bool, + pass_name: &'static str, + disambiguator: &'dis dyn Display, + writer: MirWriter<'de, 'tcx>, } -/// If the session is properly configured, dumps a human-readable representation of the MIR, with -/// the given [pretty-printing options][PrettyPrintMirOptions]. -/// -/// See [`dump_mir`] for more details. -/// -#[inline] -pub fn dump_mir_with_options<'tcx, F>( - tcx: TyCtxt<'tcx>, - pass_num: bool, - pass_name: &str, - disambiguator: &dyn Display, - body: &Body<'tcx>, - extra_data: F, - options: PrettyPrintMirOptions, -) where - F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>, -{ - if !dump_enabled(tcx, pass_name, body.source.def_id()) { - return; - } - - dump_matched_mir_node(tcx, pass_num, pass_name, disambiguator, body, extra_data, options); -} +impl<'dis, 'de, 'tcx> MirDumper<'dis, 'de, 'tcx> { + // If dumping should be performed (e.g. because it was requested on the + // CLI), returns a `MirDumper` with default values for the following fields: + // - `show_pass_num`: `false` + // - `disambiguator`: `&0` + // - `writer.extra_data`: a no-op + // - `writer.options`: default options derived from CLI flags + pub fn new(tcx: TyCtxt<'tcx>, pass_name: &'static str, body: &Body<'tcx>) -> Option<Self> { + let dump_enabled = if let Some(ref filters) = tcx.sess.opts.unstable_opts.dump_mir { + // see notes on #41697 below + let node_path = + ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id())); + filters.split('|').any(|or_filter| { + or_filter.split('&').all(|and_filter| { + let and_filter_trimmed = and_filter.trim(); + and_filter_trimmed == "all" + || pass_name.contains(and_filter_trimmed) + || node_path.contains(and_filter_trimmed) + }) + }) + } else { + false + }; -pub fn dump_enabled(tcx: TyCtxt<'_>, pass_name: &str, def_id: DefId) -> bool { - let Some(ref filters) = tcx.sess.opts.unstable_opts.dump_mir else { - return false; - }; - // see notes on #41697 below - let node_path = ty::print::with_forced_impl_filename_line!(tcx.def_path_str(def_id)); - filters.split('|').any(|or_filter| { - or_filter.split('&').all(|and_filter| { - let and_filter_trimmed = and_filter.trim(); - and_filter_trimmed == "all" - || pass_name.contains(and_filter_trimmed) - || node_path.contains(and_filter_trimmed) + dump_enabled.then_some(MirDumper { + show_pass_num: false, + pass_name, + disambiguator: &0, + writer: MirWriter::new(tcx), }) - }) -} + } -// #41697 -- we use `with_forced_impl_filename_line()` because -// `def_path_str()` would otherwise trigger `type_of`, and this can -// run while we are already attempting to evaluate `type_of`. + pub fn tcx(&self) -> TyCtxt<'tcx> { + self.writer.tcx + } -/// Most use-cases of dumping MIR should use the [dump_mir] entrypoint instead, which will also -/// check if dumping MIR is enabled, and if this body matches the filters passed on the CLI. -/// -/// That being said, if the above requirements have been validated already, this function is where -/// most of the MIR dumping occurs, if one needs to export it to a file they have created with -/// [create_dump_file], rather than to a new file created as part of [dump_mir], or to stdout/stderr -/// for debugging purposes. -pub fn dump_mir_to_writer<'tcx, F>( - tcx: TyCtxt<'tcx>, - pass_name: &str, - disambiguator: &dyn Display, - body: &Body<'tcx>, - w: &mut dyn io::Write, - mut extra_data: F, - options: PrettyPrintMirOptions, -) -> io::Result<()> -where - F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>, -{ - // see notes on #41697 above - let def_path = - ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id())); - // ignore-tidy-odd-backticks the literal below is fine - write!(w, "// MIR for `{def_path}")?; - match body.source.promoted { - None => write!(w, "`")?, - Some(promoted) => write!(w, "::{promoted:?}`")?, - } - writeln!(w, " {disambiguator} {pass_name}")?; - if let Some(ref layout) = body.coroutine_layout_raw() { - writeln!(w, "/* coroutine_layout = {layout:#?} */")?; + #[must_use] + pub fn set_show_pass_num(mut self) -> Self { + self.show_pass_num = true; + self } - writeln!(w)?; - extra_data(PassWhere::BeforeCFG, w)?; - write_user_type_annotations(tcx, body, w)?; - write_mir_fn(tcx, body, &mut extra_data, w, options)?; - extra_data(PassWhere::AfterCFG, w) -} -fn dump_matched_mir_node<'tcx, F>( - tcx: TyCtxt<'tcx>, - pass_num: bool, - pass_name: &str, - disambiguator: &dyn Display, - body: &Body<'tcx>, - extra_data: F, - options: PrettyPrintMirOptions, -) where - F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>, -{ - let _: io::Result<()> = try { - let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, body)?; - dump_mir_to_writer(tcx, pass_name, disambiguator, body, &mut file, extra_data, options)?; - }; + #[must_use] + pub fn set_disambiguator(mut self, disambiguator: &'dis dyn Display) -> Self { + self.disambiguator = disambiguator; + self + } - if tcx.sess.opts.unstable_opts.dump_mir_graphviz { - let _: io::Result<()> = try { - let mut file = create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, body)?; - write_mir_fn_graphviz(tcx, body, false, &mut file)?; - }; + #[must_use] + pub fn set_extra_data( + mut self, + extra_data: &'de dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, + ) -> Self { + self.writer.extra_data = extra_data; + self } -} -/// Returns the path to the filename where we should dump a given MIR. -/// Also used by other bits of code (e.g., NLL inference) that dump -/// graphviz data or other things. -fn dump_path<'tcx>( - tcx: TyCtxt<'tcx>, - extension: &str, - pass_num: bool, - pass_name: &str, - disambiguator: &dyn Display, - body: &Body<'tcx>, -) -> PathBuf { - let source = body.source; - let promotion_id = match source.promoted { - Some(id) => format!("-{id:?}"), - None => String::new(), - }; + #[must_use] + pub fn set_options(mut self, options: PrettyPrintMirOptions) -> Self { + self.writer.options = options; + self + } - let pass_num = if tcx.sess.opts.unstable_opts.dump_mir_exclude_pass_number { - String::new() - } else if pass_num { - let (dialect_index, phase_index) = body.phase.index(); - format!(".{}-{}-{:03}", dialect_index, phase_index, body.pass_count) - } else { - ".-------".to_string() - }; + /// If the session is properly configured, dumps a human-readable representation of the MIR + /// (with default pretty-printing options) into: + /// + /// ```text + /// rustc.node<node_id>.<pass_num>.<pass_name>.<disambiguator> + /// ``` + /// + /// Output from this function is controlled by passing `-Z dump-mir=<filter>`, + /// where `<filter>` takes the following forms: + /// + /// - `all` -- dump MIR for all fns, all passes, all everything + /// - a filter defined by a set of substrings combined with `&` and `|` + /// (`&` has higher precedence). At least one of the `|`-separated groups + /// must match; an `|`-separated group matches if all of its `&`-separated + /// substrings are matched. + /// + /// Example: + /// + /// - `nll` == match if `nll` appears in the name + /// - `foo & nll` == match if `foo` and `nll` both appear in the name + /// - `foo & nll | typeck` == match if `foo` and `nll` both appear in the name + /// or `typeck` appears in the name. + /// - `foo & nll | bar & typeck` == match if `foo` and `nll` both appear in the name + /// or `typeck` and `bar` both appear in the name. + pub fn dump_mir(&self, body: &Body<'tcx>) { + let _: io::Result<()> = try { + let mut file = self.create_dump_file("mir", body)?; + self.dump_mir_to_writer(body, &mut file)?; + }; - let crate_name = tcx.crate_name(source.def_id().krate); - let item_name = tcx.def_path(source.def_id()).to_filename_friendly_no_crate(); - // All drop shims have the same DefId, so we have to add the type - // to get unique file names. - let shim_disambiguator = match source.instance { - ty::InstanceKind::DropGlue(_, Some(ty)) => { - // Unfortunately, pretty-printed typed are not very filename-friendly. - // We dome some filtering. - let mut s = ".".to_owned(); - s.extend(ty.to_string().chars().filter_map(|c| match c { - ' ' => None, - ':' | '<' | '>' => Some('_'), - c => Some(c), - })); - s - } - ty::InstanceKind::AsyncDropGlueCtorShim(_, ty) => { - let mut s = ".".to_owned(); - s.extend(ty.to_string().chars().filter_map(|c| match c { - ' ' => None, - ':' | '<' | '>' => Some('_'), - c => Some(c), - })); - s - } - ty::InstanceKind::AsyncDropGlue(_, ty) => { - let ty::Coroutine(_, args) = ty.kind() else { - bug!(); + if self.tcx().sess.opts.unstable_opts.dump_mir_graphviz { + let _: io::Result<()> = try { + let mut file = self.create_dump_file("dot", body)?; + write_mir_fn_graphviz(self.tcx(), body, false, &mut file)?; }; - let ty = args.first().unwrap().expect_ty(); - let mut s = ".".to_owned(); - s.extend(ty.to_string().chars().filter_map(|c| match c { - ' ' => None, - ':' | '<' | '>' => Some('_'), - c => Some(c), - })); - s } - ty::InstanceKind::FutureDropPollShim(_, proxy_cor, impl_cor) => { - let mut s = ".".to_owned(); - s.extend(proxy_cor.to_string().chars().filter_map(|c| match c { - ' ' => None, - ':' | '<' | '>' => Some('_'), - c => Some(c), - })); - s.push('.'); - s.extend(impl_cor.to_string().chars().filter_map(|c| match c { - ' ' => None, - ':' | '<' | '>' => Some('_'), - c => Some(c), - })); - s + } + + // #41697 -- we use `with_forced_impl_filename_line()` because `def_path_str()` would otherwise + // trigger `type_of`, and this can run while we are already attempting to evaluate `type_of`. + pub fn dump_mir_to_writer(&self, body: &Body<'tcx>, w: &mut dyn io::Write) -> io::Result<()> { + // see notes on #41697 above + let def_path = ty::print::with_forced_impl_filename_line!( + self.tcx().def_path_str(body.source.def_id()) + ); + // ignore-tidy-odd-backticks the literal below is fine + write!(w, "// MIR for `{def_path}")?; + match body.source.promoted { + None => write!(w, "`")?, + Some(promoted) => write!(w, "::{promoted:?}`")?, + } + writeln!(w, " {} {}", self.disambiguator, self.pass_name)?; + if let Some(ref layout) = body.coroutine_layout_raw() { + writeln!(w, "/* coroutine_layout = {layout:#?} */")?; } - _ => String::new(), - }; + writeln!(w)?; + (self.writer.extra_data)(PassWhere::BeforeCFG, w)?; + write_user_type_annotations(self.tcx(), body, w)?; + self.writer.write_mir_fn(body, w)?; + (self.writer.extra_data)(PassWhere::AfterCFG, w) + } - let mut file_path = PathBuf::new(); - file_path.push(Path::new(&tcx.sess.opts.unstable_opts.dump_mir_dir)); + /// Returns the path to the filename where we should dump a given MIR. + /// Also used by other bits of code (e.g., NLL inference) that dump + /// graphviz data or other things. + fn dump_path(&self, extension: &str, body: &Body<'tcx>) -> PathBuf { + let tcx = self.tcx(); + let source = body.source; + let promotion_id = match source.promoted { + Some(id) => format!("-{id:?}"), + None => String::new(), + }; - let file_name = format!( - "{crate_name}.{item_name}{shim_disambiguator}{promotion_id}{pass_num}.{pass_name}.{disambiguator}.{extension}", - ); + let pass_num = if tcx.sess.opts.unstable_opts.dump_mir_exclude_pass_number { + String::new() + } else if self.show_pass_num { + let (dialect_index, phase_index) = body.phase.index(); + format!(".{}-{}-{:03}", dialect_index, phase_index, body.pass_count) + } else { + ".-------".to_string() + }; - file_path.push(&file_name); + let crate_name = tcx.crate_name(source.def_id().krate); + let item_name = tcx.def_path(source.def_id()).to_filename_friendly_no_crate(); + // All drop shims have the same DefId, so we have to add the type + // to get unique file names. + let shim_disambiguator = match source.instance { + ty::InstanceKind::DropGlue(_, Some(ty)) => { + // Unfortunately, pretty-printed types are not very filename-friendly. + // We do some filtering. + let mut s = ".".to_owned(); + s.extend(ty.to_string().chars().filter_map(|c| match c { + ' ' => None, + ':' | '<' | '>' => Some('_'), + c => Some(c), + })); + s + } + ty::InstanceKind::AsyncDropGlueCtorShim(_, ty) => { + let mut s = ".".to_owned(); + s.extend(ty.to_string().chars().filter_map(|c| match c { + ' ' => None, + ':' | '<' | '>' => Some('_'), + c => Some(c), + })); + s + } + ty::InstanceKind::AsyncDropGlue(_, ty) => { + let ty::Coroutine(_, args) = ty.kind() else { + bug!(); + }; + let ty = args.first().unwrap().expect_ty(); + let mut s = ".".to_owned(); + s.extend(ty.to_string().chars().filter_map(|c| match c { + ' ' => None, + ':' | '<' | '>' => Some('_'), + c => Some(c), + })); + s + } + ty::InstanceKind::FutureDropPollShim(_, proxy_cor, impl_cor) => { + let mut s = ".".to_owned(); + s.extend(proxy_cor.to_string().chars().filter_map(|c| match c { + ' ' => None, + ':' | '<' | '>' => Some('_'), + c => Some(c), + })); + s.push('.'); + s.extend(impl_cor.to_string().chars().filter_map(|c| match c { + ' ' => None, + ':' | '<' | '>' => Some('_'), + c => Some(c), + })); + s + } + _ => String::new(), + }; - file_path -} + let mut file_path = PathBuf::new(); + file_path.push(Path::new(&tcx.sess.opts.unstable_opts.dump_mir_dir)); -/// Attempts to open a file where we should dump a given MIR or other -/// bit of MIR-related data. Used by `mir-dump`, but also by other -/// bits of code (e.g., NLL inference) that dump graphviz data or -/// other things, and hence takes the extension as an argument. -pub fn create_dump_file<'tcx>( - tcx: TyCtxt<'tcx>, - extension: &str, - pass_num: bool, - pass_name: &str, - disambiguator: &dyn Display, - body: &Body<'tcx>, -) -> io::Result<io::BufWriter<fs::File>> { - let file_path = dump_path(tcx, extension, pass_num, pass_name, disambiguator, body); - if let Some(parent) = file_path.parent() { - fs::create_dir_all(parent).map_err(|e| { - io::Error::new( - e.kind(), - format!("IO error creating MIR dump directory: {parent:?}; {e}"), - ) - })?; + let pass_name = self.pass_name; + let disambiguator = self.disambiguator; + let file_name = format!( + "{crate_name}.{item_name}{shim_disambiguator}{promotion_id}{pass_num}.{pass_name}.{disambiguator}.{extension}", + ); + + file_path.push(&file_name); + + file_path + } + + /// Attempts to open a file where we should dump a given MIR or other + /// bit of MIR-related data. Used by `mir-dump`, but also by other + /// bits of code (e.g., NLL inference) that dump graphviz data or + /// other things, and hence takes the extension as an argument. + pub fn create_dump_file( + &self, + extension: &str, + body: &Body<'tcx>, + ) -> io::Result<io::BufWriter<fs::File>> { + let file_path = self.dump_path(extension, body); + if let Some(parent) = file_path.parent() { + fs::create_dir_all(parent).map_err(|e| { + io::Error::new( + e.kind(), + format!("IO error creating MIR dump directory: {parent:?}; {e}"), + ) + })?; + } + fs::File::create_buffered(&file_path).map_err(|e| { + io::Error::new(e.kind(), format!("IO error creating MIR dump file: {file_path:?}; {e}")) + }) } - fs::File::create_buffered(&file_path).map_err(|e| { - io::Error::new(e.kind(), format!("IO error creating MIR dump file: {file_path:?}; {e}")) - }) } /////////////////////////////////////////////////////////////////////////// @@ -341,7 +317,7 @@ pub fn write_mir_pretty<'tcx>( single: Option<DefId>, w: &mut dyn io::Write, ) -> io::Result<()> { - let options = PrettyPrintMirOptions::from_cli(tcx); + let writer = MirWriter::new(tcx); writeln!(w, "// WARNING: This output format is intended for human consumers only")?; writeln!(w, "// and is subject to change without notice. Knock yourself out.")?; @@ -357,11 +333,11 @@ pub fn write_mir_pretty<'tcx>( } let render_body = |w: &mut dyn io::Write, body| -> io::Result<()> { - write_mir_fn(tcx, body, &mut |_, _| Ok(()), w, options)?; + writer.write_mir_fn(body, w)?; for body in tcx.promoted_mir(def_id) { writeln!(w)?; - write_mir_fn(tcx, body, &mut |_, _| Ok(()), w, options)?; + writer.write_mir_fn(body, w)?; } Ok(()) }; @@ -373,7 +349,7 @@ pub fn write_mir_pretty<'tcx>( writeln!(w, "// MIR FOR CTFE")?; // Do not use `render_body`, as that would render the promoteds again, but these // are shared between mir_for_ctfe and optimized_mir - write_mir_fn(tcx, tcx.mir_for_ctfe(def_id), &mut |_, _| Ok(()), w, options)?; + writer.write_mir_fn(tcx.mir_for_ctfe(def_id), w)?; } else { let instance_mir = tcx.instance_mir(ty::InstanceKind::Item(def_id)); render_body(w, instance_mir)?; @@ -382,31 +358,35 @@ pub fn write_mir_pretty<'tcx>( Ok(()) } -/// Write out a human-readable textual representation for the given function. -pub fn write_mir_fn<'tcx, F>( +/// Does the writing of MIR to output, e.g. a file. +pub struct MirWriter<'de, 'tcx> { tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - extra_data: &mut F, - w: &mut dyn io::Write, + extra_data: &'de dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, options: PrettyPrintMirOptions, -) -> io::Result<()> -where - F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>, -{ - write_mir_intro(tcx, body, w, options)?; - for block in body.basic_blocks.indices() { - extra_data(PassWhere::BeforeBlock(block), w)?; - write_basic_block(tcx, block, body, extra_data, w, options)?; - if block.index() + 1 != body.basic_blocks.len() { - writeln!(w)?; - } +} + +impl<'de, 'tcx> MirWriter<'de, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>) -> Self { + MirWriter { tcx, extra_data: &|_, _| Ok(()), options: PrettyPrintMirOptions::from_cli(tcx) } } - writeln!(w, "}}")?; + /// Write out a human-readable textual representation for the given function. + pub fn write_mir_fn(&self, body: &Body<'tcx>, w: &mut dyn io::Write) -> io::Result<()> { + write_mir_intro(self.tcx, body, w, self.options)?; + for block in body.basic_blocks.indices() { + (self.extra_data)(PassWhere::BeforeBlock(block), w)?; + self.write_basic_block(block, body, w)?; + if block.index() + 1 != body.basic_blocks.len() { + writeln!(w)?; + } + } - write_allocations(tcx, body, w)?; + writeln!(w, "}}")?; - Ok(()) + write_allocations(self.tcx, body, w)?; + + Ok(()) + } } /// Prints local variables in a scope tree. @@ -719,95 +699,88 @@ pub fn dump_mir_def_ids(tcx: TyCtxt<'_>, single: Option<DefId>) -> Vec<DefId> { /////////////////////////////////////////////////////////////////////////// // Basic blocks and their parts (statements, terminators, ...) -/// Write out a human-readable textual representation for the given basic block. -fn write_basic_block<'tcx, F>( - tcx: TyCtxt<'tcx>, - block: BasicBlock, - body: &Body<'tcx>, - extra_data: &mut F, - w: &mut dyn io::Write, - options: PrettyPrintMirOptions, -) -> io::Result<()> -where - F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>, -{ - let data = &body[block]; - - // Basic block label at the top. - let cleanup_text = if data.is_cleanup { " (cleanup)" } else { "" }; - writeln!(w, "{INDENT}{block:?}{cleanup_text}: {{")?; +impl<'de, 'tcx> MirWriter<'de, 'tcx> { + /// Write out a human-readable textual representation for the given basic block. + fn write_basic_block( + &self, + block: BasicBlock, + body: &Body<'tcx>, + w: &mut dyn io::Write, + ) -> io::Result<()> { + let data = &body[block]; + + // Basic block label at the top. + let cleanup_text = if data.is_cleanup { " (cleanup)" } else { "" }; + writeln!(w, "{INDENT}{block:?}{cleanup_text}: {{")?; + + // List of statements in the middle. + let mut current_location = Location { block, statement_index: 0 }; + for statement in &data.statements { + (self.extra_data)(PassWhere::BeforeLocation(current_location), w)?; + let indented_body = format!("{INDENT}{INDENT}{statement:?};"); + if self.options.include_extra_comments { + writeln!( + w, + "{:A$} // {}{}", + indented_body, + if self.tcx.sess.verbose_internals() { + format!("{current_location:?}: ") + } else { + String::new() + }, + comment(self.tcx, statement.source_info), + A = ALIGN, + )?; + } else { + writeln!(w, "{indented_body}")?; + } - // List of statements in the middle. - let mut current_location = Location { block, statement_index: 0 }; - for statement in &data.statements { - extra_data(PassWhere::BeforeLocation(current_location), w)?; - let indented_body = format!("{INDENT}{INDENT}{statement:?};"); - if options.include_extra_comments { - writeln!( + write_extra( + self.tcx, w, - "{:A$} // {}{}", - indented_body, - if tcx.sess.verbose_internals() { - format!("{current_location:?}: ") - } else { - String::new() - }, - comment(tcx, statement.source_info), - A = ALIGN, + &|visitor| visitor.visit_statement(statement, current_location), + self.options, )?; - } else { - writeln!(w, "{indented_body}")?; - } - write_extra( - tcx, - w, - |visitor| { - visitor.visit_statement(statement, current_location); - }, - options, - )?; + (self.extra_data)(PassWhere::AfterLocation(current_location), w)?; - extra_data(PassWhere::AfterLocation(current_location), w)?; + current_location.statement_index += 1; + } - current_location.statement_index += 1; - } + // Terminator at the bottom. + (self.extra_data)(PassWhere::BeforeLocation(current_location), w)?; + if data.terminator.is_some() { + let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind); + if self.options.include_extra_comments { + writeln!( + w, + "{:A$} // {}{}", + indented_terminator, + if self.tcx.sess.verbose_internals() { + format!("{current_location:?}: ") + } else { + String::new() + }, + comment(self.tcx, data.terminator().source_info), + A = ALIGN, + )?; + } else { + writeln!(w, "{indented_terminator}")?; + } - // Terminator at the bottom. - extra_data(PassWhere::BeforeLocation(current_location), w)?; - if data.terminator.is_some() { - let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind); - if options.include_extra_comments { - writeln!( + write_extra( + self.tcx, w, - "{:A$} // {}{}", - indented_terminator, - if tcx.sess.verbose_internals() { - format!("{current_location:?}: ") - } else { - String::new() - }, - comment(tcx, data.terminator().source_info), - A = ALIGN, + &|visitor| visitor.visit_terminator(data.terminator(), current_location), + self.options, )?; - } else { - writeln!(w, "{indented_terminator}")?; } - write_extra( - tcx, - w, - |visitor| { - visitor.visit_terminator(data.terminator(), current_location); - }, - options, - )?; - } - - extra_data(PassWhere::AfterLocation(current_location), w)?; - extra_data(PassWhere::AfterTerminator(block), w)?; + (self.extra_data)(PassWhere::AfterLocation(current_location), w)?; + (self.extra_data)(PassWhere::AfterTerminator(block), w)?; - writeln!(w, "{INDENT}}}") + writeln!(w, "{INDENT}}}") + } } impl Debug for Statement<'_> { @@ -1374,15 +1347,12 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> /// After we print the main statement, we sometimes dump extra /// information. There's often a lot of little things "nuzzled up" in /// a statement. -fn write_extra<'tcx, F>( +fn write_extra<'tcx>( tcx: TyCtxt<'tcx>, write: &mut dyn io::Write, - mut visit_op: F, + visit_op: &dyn Fn(&mut ExtraComments<'tcx>), options: PrettyPrintMirOptions, -) -> io::Result<()> -where - F: FnMut(&mut ExtraComments<'tcx>), -{ +) -> io::Result<()> { if options.include_extra_comments { let mut extra_comments = ExtraComments { tcx, comments: vec![] }; visit_op(&mut extra_comments); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 7bd8a0525a2..8ce70f75c67 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -450,6 +450,8 @@ rustc_queries! { } } + /// A list of all bodies inside of `key`, nested bodies are always stored + /// before their parent. query nested_bodies_within( key: LocalDefId ) -> &'tcx ty::List<LocalDefId> { diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 32f91bfba6b..ab8a3142953 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -389,10 +389,14 @@ pub enum ObligationCauseCode<'tcx> { /// against. MatchImpl(ObligationCause<'tcx>, DefId), + UnOp { + hir_id: HirId, + }, + BinOp { lhs_hir_id: HirId, - rhs_hir_id: Option<HirId>, - rhs_span: Option<Span>, + rhs_hir_id: HirId, + rhs_span: Span, rhs_is_lit: bool, output_ty: Option<Ty<'tcx>>, }, diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index 440cb0bdbf3..f756f0a19ee 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -5,9 +5,9 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools.workspace = true +itertools = "0.12" rustc_abi = { path = "../rustc_abi" } -rustc_apfloat.workspace = true +rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } @@ -23,5 +23,5 @@ rustc_pattern_analysis = { path = "../rustc_pattern_analysis" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_trait_selection = { path = "../rustc_trait_selection" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index eb99c184bd2..7676b720e35 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -293,9 +293,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.diverge_from(loop_block); // Logic for `match`. - let scrutinee_place_builder = - unpack!(body_block = this.as_place_builder(body_block, scrutinee)); let scrutinee_span = this.thir.exprs[scrutinee].span; + let scrutinee_place_builder = unpack!( + body_block = this.lower_scrutinee(body_block, scrutinee, scrutinee_span) + ); + let match_start_span = match_span.shrink_to_lo().to(scrutinee_span); let mut patterns = Vec::with_capacity(arms.len()); @@ -343,7 +345,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr_span, |this| { this.lower_match_arms( - destination, + state_place, scrutinee_place_builder, scrutinee_span, arms, diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 6ee9674bb08..d216c4ecd11 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -388,7 +388,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } /// Evaluate the scrutinee and add the PlaceMention for it. - fn lower_scrutinee( + pub(crate) fn lower_scrutinee( &mut self, mut block: BasicBlock, scrutinee_id: ExprId, diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 6a8f0b21ee0..cdb2c5561ce 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -806,10 +806,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); body.coverage_info_hi = self.coverage_info.as_ref().map(|b| b.as_done()); - use rustc_middle::mir::pretty; - let options = pretty::PrettyPrintMirOptions::from_cli(self.tcx); - pretty::write_mir_fn(self.tcx, &body, &mut |_, _| Ok(()), &mut std::io::stdout(), options) - .unwrap(); + let writer = pretty::MirWriter::new(self.tcx); + writer.write_mir_fn(&body, &mut std::io::stdout()).unwrap(); } fn finish(self) -> Body<'tcx> { @@ -827,18 +825,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); body.coverage_info_hi = self.coverage_info.map(|b| b.into_done()); + let writer = pretty::MirWriter::new(self.tcx); for (index, block) in body.basic_blocks.iter().enumerate() { if block.terminator.is_none() { - use rustc_middle::mir::pretty; - let options = pretty::PrettyPrintMirOptions::from_cli(self.tcx); - pretty::write_mir_fn( - self.tcx, - &body, - &mut |_, _| Ok(()), - &mut std::io::stdout(), - options, - ) - .unwrap(); + writer.write_mir_fn(&body, &mut std::io::stdout()).unwrap(); span_bug!(self.fn_span, "no terminator on block {:?}", index); } } diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml index 11713bb77f1..9621f9f20bd 100644 --- a/compiler/rustc_mir_dataflow/Cargo.toml +++ b/compiler/rustc_mir_dataflow/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -polonius-engine.workspace = true +polonius-engine = "0.13.0" regex = "1" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } @@ -18,5 +18,5 @@ rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 372a3f3a8b8..b85b82b8f6d 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -10,8 +10,7 @@ use std::{io, ops, str}; use regex::Regex; use rustc_index::bit_set::DenseBitSet; use rustc_middle::mir::{ - self, BasicBlock, Body, Location, create_dump_file, dump_enabled, graphviz_safe_def_name, - traversal, + self, BasicBlock, Body, Location, MirDumper, graphviz_safe_def_name, traversal, }; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -61,11 +60,13 @@ where fs::File::create_buffered(&path)? } - None if dump_enabled(tcx, A::NAME, def_id) => { - create_dump_file(tcx, "dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)? + None => { + let Some(dumper) = MirDumper::new(tcx, A::NAME, body) else { + return Ok(()); + }; + let disambiguator = &pass_name.unwrap_or("-----"); + dumper.set_disambiguator(disambiguator).create_dump_file("dot", body)? } - - _ => return Ok(()), } }; let mut file = match file { diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index 99ef67e2625..08c43a4648c 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -5,8 +5,8 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -either.workspace = true -itertools.workspace = true +either = "1" +itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } @@ -26,5 +26,5 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 761d5461a99..4603c695ded 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1294,7 +1294,9 @@ fn create_coroutine_resume_function<'tcx>( pm::run_passes_no_validate(tcx, body, &[&abort_unwinding_calls::AbortUnwindingCalls], None); - dump_mir(tcx, false, "coroutine_resume", &0, body, |_, _| Ok(())); + if let Some(dumper) = MirDumper::new(tcx, "coroutine_resume", body) { + dumper.dump_mir(body); + } } /// An operation that can be performed on a coroutine. @@ -1446,7 +1448,9 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { assert!(body.coroutine_drop().is_none() && body.coroutine_drop_async().is_none()); - dump_mir(tcx, false, "coroutine_before", &0, body, |_, _| Ok(())); + if let Some(dumper) = MirDumper::new(tcx, "coroutine_before", body) { + dumper.dump_mir(body); + } // The first argument is the coroutine type passed by value let coroutine_ty = body.local_decls.raw[1].ty; @@ -1506,7 +1510,10 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { ) { let context_mut_ref = transform_async_context(tcx, body); expand_async_drops(tcx, body, context_mut_ref, coroutine_kind, coroutine_ty); - dump_mir(tcx, false, "coroutine_async_drop_expand", &0, body, |_, _| Ok(())); + + if let Some(dumper) = MirDumper::new(tcx, "coroutine_async_drop_expand", body) { + dumper.dump_mir(body); + } } else { cleanup_async_drops(body); } @@ -1605,14 +1612,18 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { // This is expanded to a drop ladder in `elaborate_coroutine_drops`. let drop_clean = insert_clean_drop(tcx, body, has_async_drops); - dump_mir(tcx, false, "coroutine_pre-elab", &0, body, |_, _| Ok(())); + if let Some(dumper) = MirDumper::new(tcx, "coroutine_pre-elab", body) { + dumper.dump_mir(body); + } // Expand `drop(coroutine_struct)` to a drop ladder which destroys upvars. // If any upvars are moved out of, drop elaboration will handle upvar destruction. // However we need to also elaborate the code generated by `insert_clean_drop`. elaborate_coroutine_drops(tcx, body); - dump_mir(tcx, false, "coroutine_post-transform", &0, body, |_, _| Ok(())); + if let Some(dumper) = MirDumper::new(tcx, "coroutine_post-transform", body) { + dumper.dump_mir(body); + } let can_unwind = can_unwind(tcx, body); diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index 81d7b7ba02c..951ff69c19e 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -77,7 +77,7 @@ use rustc_hir::definitions::DisambiguatorState; use rustc_middle::bug; use rustc_middle::hir::place::{Projection, ProjectionKind}; use rustc_middle::mir::visit::MutVisitor; -use rustc_middle::mir::{self, dump_mir}; +use rustc_middle::mir::{self, MirDumper}; use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, TypeVisitableExt}; pub(crate) fn coroutine_by_move_body_def_id<'tcx>( @@ -225,7 +225,10 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( ); by_move_body.source = mir::MirSource::from_instance(InstanceKind::Item(body_def.def_id().to_def_id())); - dump_mir(tcx, false, "built", &"after", &by_move_body, |_, _| Ok(())); + + if let Some(dumper) = MirDumper::new(tcx, "built", &by_move_body) { + dumper.set_disambiguator(&"after").dump_mir(&by_move_body); + } // Feed HIR because we try to access this body's attrs in the inliner. body_def.feed_hir(); diff --git a/compiler/rustc_mir_transform/src/coroutine/drop.rs b/compiler/rustc_mir_transform/src/coroutine/drop.rs index 1a314e029f4..fd2d8b2b056 100644 --- a/compiler/rustc_mir_transform/src/coroutine/drop.rs +++ b/compiler/rustc_mir_transform/src/coroutine/drop.rs @@ -605,7 +605,9 @@ pub(super) fn create_coroutine_drop_shim<'tcx>( // Temporary change MirSource to coroutine's instance so that dump_mir produces more sensible // filename. body.source.instance = coroutine_instance; - dump_mir(tcx, false, "coroutine_drop", &0, &body, |_, _| Ok(())); + if let Some(dumper) = MirDumper::new(tcx, "coroutine_drop", &body) { + dumper.dump_mir(&body); + } body.source.instance = drop_instance; // Creating a coroutine drop shim happens on `Analysis(PostCleanup) -> Runtime(Initial)` @@ -696,7 +698,9 @@ pub(super) fn create_coroutine_drop_shim_async<'tcx>( None, ); - dump_mir(tcx, false, "coroutine_drop_async", &0, &body, |_, _| Ok(())); + if let Some(dumper) = MirDumper::new(tcx, "coroutine_drop_async", &body) { + dumper.dump_mir(&body); + } body } @@ -741,7 +745,9 @@ pub(super) fn create_coroutine_drop_shim_proxy_async<'tcx>( }; body.basic_blocks_mut()[call_bb].terminator = Some(Terminator { source_info, kind }); - dump_mir(tcx, false, "coroutine_drop_proxy_async", &0, &body, |_, _| Ok(())); + if let Some(dumper) = MirDumper::new(tcx, "coroutine_drop_proxy_async", &body) { + dumper.dump_mir(&body); + } body } diff --git a/compiler/rustc_mir_transform/src/coverage/expansion.rs b/compiler/rustc_mir_transform/src/coverage/expansion.rs new file mode 100644 index 00000000000..91e0528f52f --- /dev/null +++ b/compiler/rustc_mir_transform/src/coverage/expansion.rs @@ -0,0 +1,127 @@ +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry}; +use rustc_middle::mir::coverage::BasicCoverageBlock; +use rustc_span::{ExpnId, ExpnKind, Span}; + +#[derive(Clone, Copy, Debug)] +pub(crate) struct SpanWithBcb { + pub(crate) span: Span, + pub(crate) bcb: BasicCoverageBlock, +} + +#[derive(Debug)] +pub(crate) struct ExpnTree { + nodes: FxIndexMap<ExpnId, ExpnNode>, +} + +impl ExpnTree { + pub(crate) fn get(&self, expn_id: ExpnId) -> Option<&ExpnNode> { + self.nodes.get(&expn_id) + } + + /// Yields the tree node for the given expansion ID (if present), followed + /// by the nodes of all of its descendants in depth-first order. + pub(crate) fn iter_node_and_descendants( + &self, + root_expn_id: ExpnId, + ) -> impl Iterator<Item = &ExpnNode> { + gen move { + let Some(root_node) = self.get(root_expn_id) else { return }; + yield root_node; + + // Stack of child-node-ID iterators that drives the depth-first traversal. + let mut iter_stack = vec![root_node.child_expn_ids.iter()]; + + while let Some(curr_iter) = iter_stack.last_mut() { + // Pull the next ID from the top of the stack. + let Some(&curr_id) = curr_iter.next() else { + iter_stack.pop(); + continue; + }; + + // Yield this node. + let Some(node) = self.get(curr_id) else { continue }; + yield node; + + // Push the node's children, to be traversed next. + if !node.child_expn_ids.is_empty() { + iter_stack.push(node.child_expn_ids.iter()); + } + } + } + } +} + +#[derive(Debug)] +pub(crate) struct ExpnNode { + /// Storing the expansion ID in its own node is not strictly necessary, + /// but is helpful for debugging and might be useful later. + #[expect(dead_code)] + pub(crate) expn_id: ExpnId, + + // Useful info extracted from `ExpnData`. + pub(crate) expn_kind: ExpnKind, + /// Non-dummy `ExpnData::call_site` span. + pub(crate) call_site: Option<Span>, + /// Expansion ID of `call_site`, if present. + /// This links an expansion node to its parent in the tree. + pub(crate) call_site_expn_id: Option<ExpnId>, + + /// Spans (and their associated BCBs) belonging to this expansion. + pub(crate) spans: Vec<SpanWithBcb>, + /// Expansions whose call-site is in this expansion. + pub(crate) child_expn_ids: FxIndexSet<ExpnId>, +} + +impl ExpnNode { + fn new(expn_id: ExpnId) -> Self { + let expn_data = expn_id.expn_data(); + + let call_site = Some(expn_data.call_site).filter(|sp| !sp.is_dummy()); + let call_site_expn_id = try { call_site?.ctxt().outer_expn() }; + + Self { + expn_id, + + expn_kind: expn_data.kind.clone(), + call_site, + call_site_expn_id, + + spans: vec![], + child_expn_ids: FxIndexSet::default(), + } + } +} + +/// Given a collection of span/BCB pairs from potentially-different syntax contexts, +/// arranges them into an "expansion tree" based on their expansion call-sites. +pub(crate) fn build_expn_tree(spans: impl IntoIterator<Item = SpanWithBcb>) -> ExpnTree { + let mut nodes = FxIndexMap::default(); + let new_node = |&expn_id: &ExpnId| ExpnNode::new(expn_id); + + for span_with_bcb in spans { + // Create a node for this span's enclosing expansion, and add the span to it. + let expn_id = span_with_bcb.span.ctxt().outer_expn(); + let node = nodes.entry(expn_id).or_insert_with_key(new_node); + node.spans.push(span_with_bcb); + + // Now walk up the expansion call-site chain, creating nodes and registering children. + let mut prev = expn_id; + let mut curr_expn_id = node.call_site_expn_id; + while let Some(expn_id) = curr_expn_id { + let entry = nodes.entry(expn_id); + let node_existed = matches!(entry, IndexEntry::Occupied(_)); + + let node = entry.or_insert_with_key(new_node); + node.child_expn_ids.insert(prev); + + if node_existed { + break; + } + + prev = expn_id; + curr_expn_id = node.call_site_expn_id; + } + } + + ExpnTree { nodes } +} diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index c5fef299244..08c7d346009 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -8,6 +8,7 @@ use crate::coverage::graph::CoverageGraph; use crate::coverage::mappings::ExtractedMappings; mod counters; +mod expansion; mod graph; mod hir_info; mod mappings; diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index d1b04c8f587..325935ee846 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,15 +1,14 @@ -use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir; use rustc_middle::mir::coverage::{Mapping, MappingKind, START_BCB}; use rustc_middle::ty::TyCtxt; use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span}; +use rustc_span::{BytePos, DesugaringKind, ExpnId, ExpnKind, MacroKind, Span}; use tracing::instrument; +use crate::coverage::expansion::{self, ExpnTree, SpanWithBcb}; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; use crate::coverage::hir_info::ExtractedHirInfo; -use crate::coverage::spans::from_mir::{Hole, RawSpanFromMir, SpanFromMir}; -use crate::coverage::unexpand; +use crate::coverage::spans::from_mir::{Hole, RawSpanFromMir}; mod from_mir; @@ -34,19 +33,51 @@ pub(super) fn extract_refined_covspans<'tcx>( let &ExtractedHirInfo { body_span, .. } = hir_info; let raw_spans = from_mir::extract_raw_spans_from_mir(mir_body, graph); - let mut covspans = raw_spans - .into_iter() - .filter_map(|RawSpanFromMir { raw_span, bcb }| try { - let (span, expn_kind) = - unexpand::unexpand_into_body_span_with_expn_kind(raw_span, body_span)?; - // Discard any spans that fill the entire body, because they tend - // to represent compiler-inserted code, e.g. implicitly returning `()`. - if span.source_equal(body_span) { - return None; - }; - SpanFromMir { span, expn_kind, bcb } - }) - .collect::<Vec<_>>(); + // Use the raw spans to build a tree of expansions for this function. + let expn_tree = expansion::build_expn_tree( + raw_spans + .into_iter() + .map(|RawSpanFromMir { raw_span, bcb }| SpanWithBcb { span: raw_span, bcb }), + ); + + let mut covspans = vec![]; + let mut push_covspan = |covspan: Covspan| { + let covspan_span = covspan.span; + // Discard any spans not contained within the function body span. + // Also discard any spans that fill the entire body, because they tend + // to represent compiler-inserted code, e.g. implicitly returning `()`. + if !body_span.contains(covspan_span) || body_span.source_equal(covspan_span) { + return; + } + + // Each pushed covspan should have the same context as the body span. + // If it somehow doesn't, discard the covspan, or panic in debug builds. + if !body_span.eq_ctxt(covspan_span) { + debug_assert!( + false, + "span context mismatch: body_span={body_span:?}, covspan.span={covspan_span:?}" + ); + return; + } + + covspans.push(covspan); + }; + + if let Some(node) = expn_tree.get(body_span.ctxt().outer_expn()) { + for &SpanWithBcb { span, bcb } in &node.spans { + push_covspan(Covspan { span, bcb }); + } + + // For each expansion with its call-site in the body span, try to + // distill a corresponding covspan. + for &child_expn_id in &node.child_expn_ids { + if let Some(covspan) = + single_covspan_for_child_expn(tcx, graph, &expn_tree, child_expn_id) + { + push_covspan(covspan); + } + } + } // Only proceed if we found at least one usable span. if covspans.is_empty() { @@ -57,17 +88,10 @@ pub(super) fn extract_refined_covspans<'tcx>( // Otherwise, add a fake span at the start of the body, to avoid an ugly // gap between the start of the body and the first real span. // FIXME: Find a more principled way to solve this problem. - covspans.push(SpanFromMir::for_fn_sig( - hir_info.fn_sig_span.unwrap_or_else(|| body_span.shrink_to_lo()), - )); - - // First, perform the passes that need macro information. - covspans.sort_by(|a, b| graph.cmp_in_dominator_order(a.bcb, b.bcb)); - remove_unwanted_expansion_spans(&mut covspans); - shrink_visible_macro_spans(tcx, &mut covspans); - - // We no longer need the extra information in `SpanFromMir`, so convert to `Covspan`. - let mut covspans = covspans.into_iter().map(SpanFromMir::into_covspan).collect::<Vec<_>>(); + covspans.push(Covspan { + span: hir_info.fn_sig_span.unwrap_or_else(|| body_span.shrink_to_lo()), + bcb: START_BCB, + }); let compare_covspans = |a: &Covspan, b: &Covspan| { compare_spans(a.span, b.span) @@ -117,43 +141,37 @@ pub(super) fn extract_refined_covspans<'tcx>( })); } -/// Macros that expand into branches (e.g. `assert!`, `trace!`) tend to generate -/// multiple condition/consequent blocks that have the span of the whole macro -/// invocation, which is unhelpful. Keeping only the first such span seems to -/// give better mappings, so remove the others. -/// -/// Similarly, `await` expands to a branch on the discriminant of `Poll`, which -/// leads to incorrect coverage if the `Future` is immediately ready (#98712). -/// -/// (The input spans should be sorted in BCB dominator order, so that the -/// retained "first" span is likely to dominate the others.) -fn remove_unwanted_expansion_spans(covspans: &mut Vec<SpanFromMir>) { - let mut deduplicated_spans = FxHashSet::default(); - - covspans.retain(|covspan| { - match covspan.expn_kind { - // Retain only the first await-related or macro-expanded covspan with this span. - Some(ExpnKind::Desugaring(DesugaringKind::Await)) => { - deduplicated_spans.insert(covspan.span) - } - Some(ExpnKind::Macro(MacroKind::Bang, _)) => deduplicated_spans.insert(covspan.span), - // Ignore (retain) other spans. - _ => true, +/// For a single child expansion, try to distill it into a single span+BCB mapping. +fn single_covspan_for_child_expn( + tcx: TyCtxt<'_>, + graph: &CoverageGraph, + expn_tree: &ExpnTree, + expn_id: ExpnId, +) -> Option<Covspan> { + let node = expn_tree.get(expn_id)?; + + let bcbs = + expn_tree.iter_node_and_descendants(expn_id).flat_map(|n| n.spans.iter().map(|s| s.bcb)); + + let bcb = match node.expn_kind { + // For bang-macros (e.g. `assert!`, `trace!`) and for `await`, taking + // the "first" BCB in dominator order seems to give good results. + ExpnKind::Macro(MacroKind::Bang, _) | ExpnKind::Desugaring(DesugaringKind::Await) => { + bcbs.min_by(|&a, &b| graph.cmp_in_dominator_order(a, b))? } - }); -} - -/// When a span corresponds to a macro invocation that is visible from the -/// function body, truncate it to just the macro name plus `!`. -/// This seems to give better results for code that uses macros. -fn shrink_visible_macro_spans(tcx: TyCtxt<'_>, covspans: &mut Vec<SpanFromMir>) { - let source_map = tcx.sess.source_map(); + // For other kinds of expansion, taking the "last" (most-dominated) BCB + // seems to give good results. + _ => bcbs.max_by(|&a, &b| graph.cmp_in_dominator_order(a, b))?, + }; - for covspan in covspans { - if matches!(covspan.expn_kind, Some(ExpnKind::Macro(MacroKind::Bang, _))) { - covspan.span = source_map.span_through_char(covspan.span, '!'); - } + // For bang-macro expansions, limit the call-site span to just the macro + // name plus `!`, excluding the macro arguments. + let mut span = node.call_site?; + if matches!(node.expn_kind, ExpnKind::Macro(MacroKind::Bang, _)) { + span = tcx.sess.source_map().span_through_char(span, '!'); } + + Some(Covspan { span, bcb }) } /// Discard all covspans that overlap a hole. diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 7985e1c0798..dfeaa90dc2e 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -5,10 +5,9 @@ use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::{ self, FakeReadCause, Statement, StatementKind, Terminator, TerminatorKind, }; -use rustc_span::{ExpnKind, Span}; +use rustc_span::Span; -use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; -use crate::coverage::spans::Covspan; +use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; #[derive(Debug)] pub(crate) struct RawSpanFromMir { @@ -160,32 +159,3 @@ impl Hole { true } } - -#[derive(Debug)] -pub(crate) struct SpanFromMir { - /// A span that has been extracted from MIR and then "un-expanded" back to - /// within the current function's `body_span`. After various intermediate - /// processing steps, this span is emitted as part of the final coverage - /// mappings. - /// - /// With the exception of `fn_sig_span`, this should always be contained - /// within `body_span`. - pub(crate) span: Span, - pub(crate) expn_kind: Option<ExpnKind>, - pub(crate) bcb: BasicCoverageBlock, -} - -impl SpanFromMir { - pub(crate) fn for_fn_sig(fn_sig_span: Span) -> Self { - Self::new(fn_sig_span, None, START_BCB) - } - - pub(crate) fn new(span: Span, expn_kind: Option<ExpnKind>, bcb: BasicCoverageBlock) -> Self { - Self { span, expn_kind, bcb } - } - - pub(crate) fn into_covspan(self) -> Covspan { - let Self { span, expn_kind: _, bcb } = self; - Covspan { span, bcb } - } -} diff --git a/compiler/rustc_mir_transform/src/coverage/unexpand.rs b/compiler/rustc_mir_transform/src/coverage/unexpand.rs index cb861544736..922edd3cc4f 100644 --- a/compiler/rustc_mir_transform/src/coverage/unexpand.rs +++ b/compiler/rustc_mir_transform/src/coverage/unexpand.rs @@ -1,4 +1,4 @@ -use rustc_span::{ExpnKind, Span}; +use rustc_span::Span; /// Walks through the expansion ancestors of `original_span` to find a span that /// is contained in `body_span` and has the same [syntax context] as `body_span`. @@ -7,49 +7,3 @@ pub(crate) fn unexpand_into_body_span(original_span: Span, body_span: Span) -> O // we can just delegate directly to `find_ancestor_inside_same_ctxt`. original_span.find_ancestor_inside_same_ctxt(body_span) } - -/// Walks through the expansion ancestors of `original_span` to find a span that -/// is contained in `body_span` and has the same [syntax context] as `body_span`. -/// -/// If the returned span represents a bang-macro invocation (e.g. `foo!(..)`), -/// the returned symbol will be the name of that macro (e.g. `foo`). -pub(crate) fn unexpand_into_body_span_with_expn_kind( - original_span: Span, - body_span: Span, -) -> Option<(Span, Option<ExpnKind>)> { - let (span, prev) = unexpand_into_body_span_with_prev(original_span, body_span)?; - - let expn_kind = prev.map(|prev| prev.ctxt().outer_expn_data().kind); - - Some((span, expn_kind)) -} - -/// Walks through the expansion ancestors of `original_span` to find a span that -/// is contained in `body_span` and has the same [syntax context] as `body_span`. -/// The ancestor that was traversed just before the matching span (if any) is -/// also returned. -/// -/// For example, a return value of `Some((ancestor, Some(prev)))` means that: -/// - `ancestor == original_span.find_ancestor_inside_same_ctxt(body_span)` -/// - `prev.parent_callsite() == ancestor` -/// -/// [syntax context]: rustc_span::SyntaxContext -fn unexpand_into_body_span_with_prev( - original_span: Span, - body_span: Span, -) -> Option<(Span, Option<Span>)> { - let mut prev = None; - let mut curr = original_span; - - while !body_span.contains(curr) || !curr.eq_ctxt(body_span) { - prev = Some(curr); - curr = curr.parent_callsite()?; - } - - debug_assert_eq!(Some(curr), original_span.find_ancestor_inside_same_ctxt(body_span)); - if let Some(prev) = prev { - debug_assert_eq!(Some(curr), prev.parent_callsite()); - } - - Some((curr, prev)) -} diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 4c94a6c524e..cf7425251e8 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -137,8 +137,8 @@ use rustc_index::interval::SparseIntervalMatrix; use rustc_middle::bug; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::{ - Body, HasLocalDecls, InlineAsmOperand, Local, LocalKind, Location, Operand, PassWhere, Place, - Rvalue, Statement, StatementKind, TerminatorKind, dump_mir, traversal, + Body, HasLocalDecls, InlineAsmOperand, Local, LocalKind, Location, MirDumper, Operand, + PassWhere, Place, Rvalue, Statement, StatementKind, TerminatorKind, traversal, }; use rustc_middle::ty::TyCtxt; use rustc_mir_dataflow::Analysis; @@ -810,11 +810,15 @@ fn dest_prop_mir_dump<'tcx>( let location = points.point_from_location(location); live.rows().filter(|&r| live.contains(r, location)).collect::<Vec<_>>() }; - dump_mir(tcx, false, "DestinationPropagation-dataflow", &round, body, |pass_where, w| { - if let PassWhere::BeforeLocation(loc) = pass_where { - writeln!(w, " // live: {:?}", locals_live_at(loc))?; - } - Ok(()) - }); + if let Some(dumper) = MirDumper::new(tcx, "DestinationPropagation-dataflow", body) { + let extra_data = &|pass_where, w: &mut dyn std::io::Write| { + if let PassWhere::BeforeLocation(loc) = pass_where { + writeln!(w, " // live: {:?}", locals_live_at(loc))?; + } + Ok(()) + }; + + dumper.set_disambiguator(&round).set_extra_data(extra_data).dump_mir(body) + } } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 08f25276cec..8f319e64916 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -5,6 +5,7 @@ #![feature(const_type_name)] #![feature(cow_is_borrowed)] #![feature(file_buffered)] +#![feature(gen_blocks)] #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] #![feature(try_blocks)] diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 2f0edf31162..794984d2f3e 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -12,8 +12,8 @@ use rustc_index::{IndexSlice, IndexVec}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::bug; use rustc_middle::mir::{ - self, BasicBlock, Body, ClearCrossCrate, Local, Location, Place, StatementKind, TerminatorKind, - dump_mir, + self, BasicBlock, Body, ClearCrossCrate, Local, Location, MirDumper, Place, StatementKind, + TerminatorKind, }; use rustc_middle::ty::significant_drop_order::{ extract_component_with_significant_dtor, ty_dtor_span, @@ -227,7 +227,10 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body< return; } - dump_mir(tcx, false, "lint_tail_expr_drop_order", &0 as _, body, |_, _| Ok(())); + if let Some(dumper) = MirDumper::new(tcx, "lint_tail_expr_drop_order", body) { + dumper.dump_mir(body); + } + let locals_with_user_names = collect_user_names(body); let is_closure_like = tcx.is_closure_like(def_id.to_def_id()); diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 5b3ddcc777b..ab09cdf787e 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -2,7 +2,7 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; -use rustc_middle::mir::{self, Body, MirPhase, RuntimePhase}; +use rustc_middle::mir::{Body, MirDumper, MirPhase, RuntimePhase}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use tracing::trace; @@ -281,16 +281,22 @@ fn run_passes_inner<'tcx>( let lint = tcx.sess.opts.unstable_opts.lint_mir; for pass in passes { - let name = pass.name(); + let pass_name = pass.name(); if !should_run_pass(tcx, *pass, optimizations) { continue; }; - let dump_enabled = pass.is_mir_dump_enabled(); + let dumper = if pass.is_mir_dump_enabled() + && let Some(dumper) = MirDumper::new(tcx, pass_name, body) + { + Some(dumper.set_show_pass_num().set_disambiguator(&"before")) + } else { + None + }; - if dump_enabled { - dump_mir_for_pass(tcx, body, name, false); + if let Some(dumper) = dumper.as_ref() { + dumper.dump_mir(body); } if let Some(prof_arg) = &prof_arg { @@ -302,14 +308,15 @@ fn run_passes_inner<'tcx>( pass.run_pass(tcx, body); } - if dump_enabled { - dump_mir_for_pass(tcx, body, name, true); + if let Some(dumper) = dumper { + dumper.set_disambiguator(&"after").dump_mir(body); } + if validate { - validate_body(tcx, body, format!("after pass {name}")); + validate_body(tcx, body, format!("after pass {pass_name}")); } if lint { - lint_body(tcx, body, format!("after pass {name}")); + lint_body(tcx, body, format!("after pass {pass_name}")); } body.pass_count += 1; @@ -345,18 +352,9 @@ pub(super) fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when validate::Validator { when }.run_pass(tcx, body); } -fn dump_mir_for_pass<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, pass_name: &str, is_after: bool) { - mir::dump_mir( - tcx, - true, - pass_name, - if is_after { &"after" } else { &"before" }, - body, - |_, _| Ok(()), - ); -} - pub(super) fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { assert_eq!(body.pass_count, 0); - mir::dump_mir(tcx, true, body.phase.name(), &"after", body, |_, _| Ok(())) + if let Some(dumper) = MirDumper::new(tcx, body.phase.name(), body) { + dumper.set_show_pass_num().set_disambiguator(&"after").dump_mir(body) + } } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index c6760b3583f..bca8ffb693b 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -1242,14 +1242,12 @@ fn build_construct_coroutine_by_move_shim<'tcx>( let body = new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span); - dump_mir( - tcx, - false, - if receiver_by_ref { "coroutine_closure_by_ref" } else { "coroutine_closure_by_move" }, - &0, - &body, - |_, _| Ok(()), - ); + + let pass_name = + if receiver_by_ref { "coroutine_closure_by_ref" } else { "coroutine_closure_by_move" }; + if let Some(dumper) = MirDumper::new(tcx, pass_name, &body) { + dumper.dump_mir(&body); + } body } diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index 78266d3c6d8..09a55f0b5f8 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -16,6 +16,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } serde = "1" -serde_json.workspace = true -tracing.workspace = true +serde_json = "1" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 6a836442c32..cffeb6f9807 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1535,7 +1535,20 @@ impl<'v> RootCollector<'_, 'v> { fn process_nested_body(&mut self, def_id: LocalDefId) { match self.tcx.def_kind(def_id) { DefKind::Closure => { - if self.strategy == MonoItemCollectionStrategy::Eager + // for 'pub async fn foo(..)' also trying to monomorphize foo::{closure} + let is_pub_fn_coroutine = + match *self.tcx.type_of(def_id).instantiate_identity().kind() { + ty::Coroutine(cor_id, _args) => { + let tcx = self.tcx; + let parent_id = tcx.parent(cor_id); + tcx.def_kind(parent_id) == DefKind::Fn + && tcx.asyncness(parent_id).is_async() + && tcx.visibility(parent_id).is_public() + } + ty::Closure(..) | ty::CoroutineClosure(..) => false, + _ => unreachable!(), + }; + if (self.strategy == MonoItemCollectionStrategy::Eager || is_pub_fn_coroutine) && !self .tcx .generics_of(self.tcx.typeck_root_def_id(def_id.to_def_id())) diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 43db90c08f3..05bcabad02f 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -5,13 +5,13 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -derive-where.workspace = true +derive-where = "1.2.7" rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } rustc_type_ir = { path = "../rustc_type_ir", default-features = false } rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [features] diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 7cb4ae7ff5f..6d738a10371 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -5,8 +5,8 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true -rustc-literal-escaper.workspace = true +bitflags = "2.4.1" +rustc-literal-escaper = "0.0.5" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } @@ -18,8 +18,8 @@ rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" unicode-normalization = "0.1.11" unicode-width = "0.2.0" # tidy-alphabetical-end diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 9754691a0b9..c4d30b3d328 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1516,7 +1516,7 @@ impl<'a> Parser<'a> { || self.check_noexpect(&token::DotDotDot) || self.check_keyword(exp!(Underscore)) { - etc = PatFieldsRest::Rest; + etc = PatFieldsRest::Rest(self.token.span); let mut etc_sp = self.token.span; if first_etc_and_maybe_comma_span.is_none() { if let Some(comma_tok) = diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml index 645e34b6e32..d178fcda1fb 100644 --- a/compiler/rustc_parse_format/Cargo.toml +++ b/compiler/rustc_parse_format/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc-literal-escaper.workspace = true +rustc-literal-escaper = "0.0.5" rustc_lexer = { path = "../rustc_lexer" } # tidy-alphabetical-end diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index c74608a6146..ba81ef3103b 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -24,5 +24,5 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 801a533c943..ae16a51bc69 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1583,7 +1583,7 @@ impl<'tcx> Liveness<'_, 'tcx> { }); let can_remove = match pat.kind { - hir::PatKind::Struct(_, fields, true) => { + hir::PatKind::Struct(_, fields, Some(_)) => { // if all fields are shorthand, remove the struct field, otherwise, mark with _ as prefix fields.iter().all(|f| f.is_shorthand) } diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml index e4909ab6d16..a59f7bbeb9e 100644 --- a/compiler/rustc_pattern_analysis/Cargo.toml +++ b/compiler/rustc_pattern_analysis/Cargo.toml @@ -5,9 +5,9 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc-hash.workspace = true +rustc-hash = "2.0.0" rustc_abi = { path = "../rustc_abi", optional = true } -rustc_apfloat.workspace = true +rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena", optional = true } rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_errors = { path = "../rustc_errors", optional = true } @@ -19,7 +19,7 @@ rustc_middle = { path = "../rustc_middle", optional = true } rustc_session = { path = "../rustc_session", optional = true } rustc_span = { path = "../rustc_span", optional = true } smallvec = { version = "1.8.1", features = ["union"] } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [dev-dependencies] diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml index 7de58132e13..c8bfdb91304 100644 --- a/compiler/rustc_privacy/Cargo.toml +++ b/compiler/rustc_privacy/Cargo.toml @@ -15,5 +15,5 @@ rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_ty_utils = { path = "../rustc_ty_utils" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_proc_macro/Cargo.toml b/compiler/rustc_proc_macro/Cargo.toml index 99e7fc7abc6..beb95aa3b52 100644 --- a/compiler/rustc_proc_macro/Cargo.toml +++ b/compiler/rustc_proc_macro/Cargo.toml @@ -16,7 +16,7 @@ doctest = false [dependencies] # tidy-alphabetical-start -rustc-literal-escaper.workspace = true +rustc-literal-escaper = "0.0.5" # tidy-alphabetical-end [features] diff --git a/compiler/rustc_public/Cargo.toml b/compiler/rustc_public/Cargo.toml index e67e4fe6739..70af30c1a5f 100644 --- a/compiler/rustc_public/Cargo.toml +++ b/compiler/rustc_public/Cargo.toml @@ -12,9 +12,9 @@ rustc_public_bridge = { path = "../rustc_public_bridge" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -scoped-tls.workspace = true +scoped-tls = "1.0" serde = { version = "1.0.125", features = [ "derive" ] } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [features] diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index 3d5cf0eb72d..e5cceacf15d 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -measureme.workspace = true +measureme = "12.0.1" rustc_data_structures = { path = "../rustc_data_structures" } rustc_hashes = { path = "../rustc_hashes" } rustc_hir = { path = "../rustc_hir" } @@ -15,5 +15,5 @@ rustc_query_system = { path = "../rustc_query_system" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index 0df933bc81c..7480ba03474 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -21,7 +21,7 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_thread_pool = { path = "../rustc_thread_pool" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [dependencies.hashbrown] diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index 4da4c0840df..eb98a6e85c0 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -5,9 +5,9 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true -indexmap.workspace = true -itertools.workspace = true +bitflags = "2.4.1" +indexmap = "2.4.0" +itertools = "0.12" pulldown-cmark = { version = "0.11", features = ["html"], default-features = false } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } @@ -27,6 +27,6 @@ rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index f75a625a279..fa3c06059b3 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1008,16 +1008,13 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let msg = format!("extern crate `{ident}` already in extern prelude"); self.r.tcx.dcx().span_delayed_bug(item.span, msg); } else { - entry.item_binding = Some(imported_binding); - entry.introduced_by_item = orig_name.is_some(); + entry.item_binding = Some((imported_binding, orig_name.is_some())); } entry } Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry { - item_binding: Some(imported_binding), - flag_binding: Cell::new(None), - only_item: true, - introduced_by_item: true, + item_binding: Some((imported_binding, true)), + flag_binding: None, }), }; } diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 11d93a58ae2..50a1ad23a54 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -204,7 +204,7 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { .r .extern_prelude .get(&Macros20NormalizedIdent::new(extern_crate.ident)) - .is_none_or(|entry| entry.introduced_by_item) + .is_none_or(|entry| entry.introduced_by_item()) { continue; } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 337e7d2dd86..5dfc4292a38 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -322,7 +322,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let from_item = self .extern_prelude .get(&Macros20NormalizedIdent::new(ident)) - .is_none_or(|entry| entry.introduced_by_item); + .is_none_or(|entry| entry.introduced_by_item()); // Only suggest removing an import if both bindings are to the same def, if both spans // aren't dummy spans. Further, if both bindings are imports, then the ident must have // been introduced by an item. @@ -1845,7 +1845,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error; let extern_prelude_ambiguity = || { self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)).is_some_and(|entry| { - entry.item_binding == Some(b1) && entry.flag_binding.get() == Some(b2) + entry.item_binding.map(|(b, _)| b) == Some(b1) + && entry.flag_binding.as_ref().and_then(|pb| pb.get().binding()) == Some(b2) }) }; let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index d4f7fb276a9..6a12fafcb1e 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3922,7 +3922,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { fn record_patterns_with_skipped_bindings(&mut self, pat: &Pat, rest: &ast::PatFieldsRest) { match rest { - ast::PatFieldsRest::Rest | ast::PatFieldsRest::Recovered(_) => { + ast::PatFieldsRest::Rest(_) | ast::PatFieldsRest::Recovered(_) => { // Record that the pattern doesn't introduce all the bindings it could. if let Some(partial_res) = self.r.partial_res_map.get(&pat.id) && let Some(res) = partial_res.full_res() diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 2afb52ef4d4..9674c0356c2 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -32,7 +32,7 @@ use std::sync::Arc; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; use effective_visibilities::EffectiveVisibilitiesVisitor; use errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; -use imports::{Import, ImportData, ImportKind, NameResolution}; +use imports::{Import, ImportData, ImportKind, NameResolution, PendingBinding}; use late::{ ForwardGenericParamBanReason, HasGenericParams, PathSource, PatternSource, UnnecessaryQualification, @@ -1025,18 +1025,26 @@ impl<'ra> NameBindingData<'ra> { } } -#[derive(Default, Clone)] struct ExternPreludeEntry<'ra> { /// Binding from an `extern crate` item. - item_binding: Option<NameBinding<'ra>>, + /// The boolean flag is true is `item_binding` is non-redundant, happens either when + /// `flag_binding` is `None`, or when `extern crate` introducing `item_binding` used renaming. + item_binding: Option<(NameBinding<'ra>, /* introduced by item */ bool)>, /// Binding from an `--extern` flag, lazily populated on first use. - flag_binding: Cell<Option<NameBinding<'ra>>>, - /// There was no `--extern` flag introducing this name, - /// `flag_binding` doesn't need to be populated. - only_item: bool, - /// `item_binding` is non-redundant, happens either when `only_item` is true, - /// or when `extern crate` introducing `item_binding` used renaming. - introduced_by_item: bool, + flag_binding: Option<Cell<PendingBinding<'ra>>>, +} + +impl ExternPreludeEntry<'_> { + fn introduced_by_item(&self) -> bool { + matches!(self.item_binding, Some((_, true))) + } + + fn flag() -> Self { + ExternPreludeEntry { + item_binding: None, + flag_binding: Some(Cell::new(PendingBinding::Pending)), + } + } } struct DeriveData { @@ -1528,7 +1536,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && let name = Symbol::intern(name) && name.can_be_raw() { - Some((Macros20NormalizedIdent::with_dummy_span(name), Default::default())) + let ident = Macros20NormalizedIdent::with_dummy_span(name); + Some((ident, ExternPreludeEntry::flag())) } else { None } @@ -1536,11 +1545,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .collect(); if !attr::contains_name(attrs, sym::no_core) { - extern_prelude - .insert(Macros20NormalizedIdent::with_dummy_span(sym::core), Default::default()); + let ident = Macros20NormalizedIdent::with_dummy_span(sym::core); + extern_prelude.insert(ident, ExternPreludeEntry::flag()); if !attr::contains_name(attrs, sym::no_std) { - extern_prelude - .insert(Macros20NormalizedIdent::with_dummy_span(sym::std), Default::default()); + let ident = Macros20NormalizedIdent::with_dummy_span(sym::std); + extern_prelude.insert(ident, ExternPreludeEntry::flag()); } } @@ -2062,12 +2071,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // Avoid marking `extern crate` items that refer to a name from extern prelude, // but not introduce it, as used if they are accessed from lexical scope. - if used == Used::Scope { - if let Some(entry) = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)) { - if !entry.introduced_by_item && entry.item_binding == Some(used_binding) { - return; - } - } + if used == Used::Scope + && let Some(entry) = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)) + && entry.item_binding == Some((used_binding, false)) + { + return; } let old_used = self.import_use_map.entry(import).or_insert(used); if *old_used < used { @@ -2226,7 +2234,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { finalize: bool, ) -> Option<NameBinding<'ra>> { let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); - entry.and_then(|entry| entry.item_binding).map(|binding| { + entry.and_then(|entry| entry.item_binding).map(|(binding, _)| { if finalize { self.get_mut().record_use(ident, binding, Used::Scope); } @@ -2236,31 +2244,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn extern_prelude_get_flag(&self, ident: Ident, finalize: bool) -> Option<NameBinding<'ra>> { let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); - entry.and_then(|entry| match entry.flag_binding.get() { - Some(binding) => { - if finalize { - self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); + entry.and_then(|entry| entry.flag_binding.as_ref()).and_then(|flag_binding| { + let binding = match flag_binding.get() { + PendingBinding::Ready(binding) => { + if finalize { + self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); + } + binding } - Some(binding) - } - None if entry.only_item => None, - None => { - let crate_id = if finalize { - self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span) - } else { - self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name) - }; - match crate_id { - Some(crate_id) => { + PendingBinding::Pending => { + let crate_id = if finalize { + self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span) + } else { + self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name) + }; + crate_id.map(|crate_id| { let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); - let binding = - self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); - entry.flag_binding.set(Some(binding)); - Some(binding) - } - None => finalize.then_some(self.dummy_binding), + self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT) + }) } - } + }; + flag_binding.set(PendingBinding::Ready(binding)); + binding.or_else(|| finalize.then_some(self.dummy_binding)) }) } diff --git a/compiler/rustc_sanitizers/Cargo.toml b/compiler/rustc_sanitizers/Cargo.toml index 3dbeaa435f3..9069d2c233d 100644 --- a/compiler/rustc_sanitizers/Cargo.toml +++ b/compiler/rustc_sanitizers/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true +bitflags = "2.5.0" rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } @@ -13,6 +13,6 @@ rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -tracing.workspace = true +tracing = "0.1" twox-hash = "1.6.3" # tidy-alphabetical-end diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml index 853f87ebed9..948242352e7 100644 --- a/compiler/rustc_serialize/Cargo.toml +++ b/compiler/rustc_serialize/Cargo.toml @@ -5,14 +5,14 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -indexmap.workspace = true +indexmap = "2.0.0" rustc_hashes = { path = "../rustc_hashes" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true +thin-vec = "0.2.12" # tidy-alphabetical-end [dev-dependencies] # tidy-alphabetical-start rustc_macros = { path = "../rustc_macros" } -tempfile.workspace = true +tempfile = "3.2" # tidy-alphabetical-end diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 5870fb29ae8..60d56b1b808 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true +bitflags = "2.4.1" getopts = "0.2" rand = "0.9.0" rustc_abi = { path = "../rustc_abi" } @@ -23,12 +23,14 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } termize = "0.2" -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [target.'cfg(unix)'.dependencies] +# FIXME: Remove this pin once this rustix issue is resolved +# https://github.com/bytecodealliance/rustix/issues/1496 # tidy-alphabetical-start -libc.workspace = true +libc = "=0.2.174" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index da6f2101d23..43a2d692577 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -6,8 +6,8 @@ edition = "2024" [dependencies] # tidy-alphabetical-start blake3 = "1.5.2" -derive-where.workspace = true -indexmap.workspace = true +derive-where = "1.2.7" +indexmap = { version = "2.0.0" } itoa = "1.0" md5 = { package = "md-5", version = "0.10.0" } rustc_arena = { path = "../rustc_arena" } @@ -16,9 +16,9 @@ rustc_hashes = { path = "../rustc_hashes" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } -scoped-tls.workspace = true +scoped-tls = "1.0" sha1 = "0.10.0" sha2 = "0.10.1" -tracing.workspace = true +tracing = "0.1" unicode-width = "0.2.0" # tidy-alphabetical-end diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index 0ceac4b3e1b..0df9c7682bf 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start punycode = "0.4.0" -rustc-demangle.workspace = true +rustc-demangle = "0.1.21" rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } @@ -15,5 +15,5 @@ rustc_hir = { path = "../rustc_hir" } rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml index ed59ee2a575..7fabb227d9a 100644 --- a/compiler/rustc_target/Cargo.toml +++ b/compiler/rustc_target/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true +bitflags = "2.4.1" object = { version = "0.37.0", default-features = false, features = ["elf", "macho"] } rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } @@ -16,8 +16,8 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } serde = "1.0.219" serde_derive = "1.0.219" -serde_json.workspace = true +serde_json = "1.0.59" serde_path_to_error = "0.1.17" -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_trusty.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_trusty.rs index 126f0251239..05783fde1ad 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_trusty.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_trusty.rs @@ -11,7 +11,7 @@ pub(crate) fn target() -> Target { description: Some("ARM64 Trusty".into()), tier: Some(3), host_tools: Some(false), - std: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs index 8f93523909e..7292412a18d 100644 --- a/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs @@ -20,9 +20,9 @@ pub(crate) fn target() -> Target { llvm_target: "arm64ec-pc-windows-msvc".into(), metadata: TargetMetadata { description: Some("Arm64EC Windows MSVC".into()), - tier: Some(3), + tier: Some(2), host_tools: Some(false), - std: None, // ? + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_trusty.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_trusty.rs index 31d492e83cd..2b0b0e1d117 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_trusty.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_trusty.rs @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { description: Some("Armv7-A Trusty".into()), tier: Some(3), host_tools: Some(false), - std: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs index c7b002bc9bb..dbcb5fd4e11 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs @@ -12,7 +12,7 @@ pub(crate) fn target() -> Target { description: Some("x86_64 Trusty".into()), tier: Some(3), host_tools: Some(false), - std: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_thread_pool/Cargo.toml b/compiler/rustc_thread_pool/Cargo.toml index 8e8c6469512..c92984470b7 100644 --- a/compiler/rustc_thread_pool/Cargo.toml +++ b/compiler/rustc_thread_pool/Cargo.toml @@ -20,10 +20,10 @@ smallvec = "1.8.1" [dev-dependencies] rand = "0.9" rand_xorshift = "0.4" -scoped-tls.workspace = true +scoped-tls = "1.0" [target.'cfg(unix)'.dev-dependencies] -libc.workspace = true +libc = "0.2" [[test]] name = "stack_overflow_crash" diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 6b79b98d1bf..1071105522d 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools.workspace = true +itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } @@ -21,6 +21,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index d768e0bf63f..bc984f30472 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -3,7 +3,8 @@ use std::borrow::Cow; use std::path::PathBuf; use rustc_abi::ExternAbi; -use rustc_ast::TraitObjectSyntax; +use rustc_ast::ast::LitKind; +use rustc_ast::{LitIntType, TraitObjectSyntax}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; @@ -280,6 +281,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { (suggested, noted_missing_impl) = self.try_conversion_context(&obligation, main_trait_predicate, &mut err); } + suggested |= self.detect_negative_literal( + &obligation, + main_trait_predicate, + &mut err, + ); + if let Some(ret_span) = self.return_type_span(&obligation) { if is_try_conversion { let ty = self.tcx.short_string( @@ -950,6 +957,38 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Ok(()) } + fn detect_negative_literal( + &self, + obligation: &PredicateObligation<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, + err: &mut Diag<'_>, + ) -> bool { + if let ObligationCauseCode::UnOp { hir_id, .. } = obligation.cause.code() + && let hir::Node::Expr(expr) = self.tcx.hir_node(*hir_id) + && let hir::ExprKind::Unary(hir::UnOp::Neg, inner) = expr.kind + && let hir::ExprKind::Lit(lit) = inner.kind + && let LitKind::Int(_, LitIntType::Unsuffixed) = lit.node + { + err.span_suggestion_verbose( + lit.span.shrink_to_hi(), + "consider specifying an integer type that can be negative", + match trait_pred.skip_binder().self_ty().kind() { + ty::Uint(ty::UintTy::Usize) => "isize", + ty::Uint(ty::UintTy::U8) => "i8", + ty::Uint(ty::UintTy::U16) => "i16", + ty::Uint(ty::UintTy::U32) => "i32", + ty::Uint(ty::UintTy::U64) => "i64", + ty::Uint(ty::UintTy::U128) => "i128", + _ => "i64", + } + .to_string(), + Applicability::MaybeIncorrect, + ); + return true; + } + false + } + /// When the `E` of the resulting `Result<T, E>` in an expression `foo().bar().baz()?`, /// identify those method chain sub-expressions that could or could not have been annotated /// with `?`. @@ -2730,9 +2769,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { suggested: bool, ) { let body_def_id = obligation.cause.body_id; - let span = if let ObligationCauseCode::BinOp { rhs_span: Some(rhs_span), .. } = - obligation.cause.code() - { + let span = if let ObligationCauseCode::BinOp { rhs_span, .. } = obligation.cause.code() { *rhs_span } else { span diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index aa153d3607b..40a27c9aebe 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -554,7 +554,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return true; } } else if let ( - ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id: Some(rhs_hir_id), .. }, + ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, .. }, predicate, ) = code.peel_derives_with_predicate() && let Some(typeck_results) = &self.typeck_results @@ -2801,6 +2801,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ObligationCauseCode::QuestionMark | ObligationCauseCode::CheckAssociatedTypeBounds { .. } | ObligationCauseCode::LetElse + | ObligationCauseCode::UnOp { .. } | ObligationCauseCode::BinOp { .. } | ObligationCauseCode::AscribeUserTypeProvePredicate(..) | ObligationCauseCode::AlwaysApplicableImpl @@ -3839,9 +3840,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, ) { let rhs_span = match obligation.cause.code() { - ObligationCauseCode::BinOp { rhs_span: Some(span), rhs_is_lit, .. } if *rhs_is_lit => { - span - } + ObligationCauseCode::BinOp { rhs_span, rhs_is_lit, .. } if *rhs_is_lit => rhs_span, _ => return, }; if let ty::Float(_) = trait_pred.skip_binder().self_ty().kind() @@ -5108,16 +5107,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let tcx = self.tcx; let predicate = predicate.upcast(tcx); match *cause_code { - ObligationCauseCode::BinOp { - lhs_hir_id, - rhs_hir_id: Some(rhs_hir_id), - rhs_span: Some(rhs_span), - .. - } if let Some(typeck_results) = &self.typeck_results - && let hir::Node::Expr(lhs) = tcx.hir_node(lhs_hir_id) - && let hir::Node::Expr(rhs) = tcx.hir_node(rhs_hir_id) - && let Some(lhs_ty) = typeck_results.expr_ty_opt(lhs) - && let Some(rhs_ty) = typeck_results.expr_ty_opt(rhs) => + ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, rhs_span, .. } + if let Some(typeck_results) = &self.typeck_results + && let hir::Node::Expr(lhs) = tcx.hir_node(lhs_hir_id) + && let hir::Node::Expr(rhs) = tcx.hir_node(rhs_hir_id) + && let Some(lhs_ty) = typeck_results.expr_ty_opt(lhs) + && let Some(rhs_ty) = typeck_results.expr_ty_opt(rhs) => { if let Some(pred) = predicate.as_trait_clause() && tcx.is_lang_item(pred.def_id(), LangItem::PartialEq) diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index 24360a94cc7..9f40f4d5c23 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -10,5 +10,5 @@ rustc_infer = { path = "../rustc_infer" } rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_trait_selection = { path = "../rustc_trait_selection" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml index 2ac2b46cc58..e61717e5e9c 100644 --- a/compiler/rustc_transmute/Cargo.toml +++ b/compiler/rustc_transmute/Cargo.toml @@ -11,12 +11,12 @@ rustc_hir = { path = "../rustc_hir", optional = true } rustc_middle = { path = "../rustc_middle", optional = true } rustc_span = { path = "../rustc_span", optional = true } smallvec = "1.8.1" -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [dev-dependencies] # tidy-alphabetical-start -itertools.workspace = true +itertools = "0.12" # tidy-alphabetical-end [features] diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml index 394cde5a323..ce08b300cc8 100644 --- a/compiler/rustc_ty_utils/Cargo.toml +++ b/compiler/rustc_ty_utils/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools.workspace = true +itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } @@ -20,5 +20,5 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_ty_utils/src/nested_bodies.rs b/compiler/rustc_ty_utils/src/nested_bodies.rs index 7c74d8eb635..11dfbad7dbb 100644 --- a/compiler/rustc_ty_utils/src/nested_bodies.rs +++ b/compiler/rustc_ty_utils/src/nested_bodies.rs @@ -22,9 +22,11 @@ impl<'tcx> Visitor<'tcx> for NestedBodiesVisitor<'tcx> { fn visit_nested_body(&mut self, id: hir::BodyId) { let body_def_id = self.tcx.hir_body_owner_def_id(id); if self.tcx.typeck_root_def_id(body_def_id.to_def_id()) == self.root_def_id { - self.nested_bodies.push(body_def_id); + // We visit nested bodies before adding the current body. This + // means that nested bodies are always stored before their parent. let body = self.tcx.hir_body(id); self.visit_body(body); + self.nested_bodies.push(body_def_id); } } } diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 42860fa2d88..d55e9b3b1be 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -5,11 +5,11 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true -derive-where.workspace = true +bitflags = "2.4.1" +derive-where = "1.2.7" ena = "0.14.3" -indexmap.workspace = true -rustc-hash.workspace = true +indexmap = "2.0.0" +rustc-hash = "2.0.0" rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_error_messages = { path = "../rustc_error_messages", optional = true } @@ -19,8 +19,8 @@ rustc_serialize = { path = "../rustc_serialize", optional = true } rustc_span = { path = "../rustc_span", optional = true } rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } smallvec = { version = "1.8.1", default-features = false, features = ["const_generics"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end [features] diff --git a/compiler/rustc_type_ir_macros/Cargo.toml b/compiler/rustc_type_ir_macros/Cargo.toml index 29a2cc89033..15a55575099 100644 --- a/compiler/rustc_type_ir_macros/Cargo.toml +++ b/compiler/rustc_type_ir_macros/Cargo.toml @@ -8,8 +8,8 @@ proc-macro = true [dependencies] # tidy-alphabetical-start -proc-macro2.workspace = true -quote.workspace = true +proc-macro2 = "1" +quote = "1" syn = { version = "2.0.9", features = ["full"] } synstructure = "0.13.0" # tidy-alphabetical-end diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 95d1e2069ac..c0a27775694 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -736,6 +736,31 @@ impl<T> Bound<T> { } } +impl<T: Copy> Bound<&T> { + /// Map a `Bound<&T>` to a `Bound<T>` by copying the contents of the bound. + /// + /// # Examples + /// + /// ``` + /// #![feature(bound_copied)] + /// + /// use std::ops::Bound::*; + /// use std::ops::RangeBounds; + /// + /// assert_eq!((1..12).start_bound(), Included(&1)); + /// assert_eq!((1..12).start_bound().copied(), Included(1)); + /// ``` + #[unstable(feature = "bound_copied", issue = "145966")] + #[must_use] + pub fn copied(self) -> Bound<T> { + match self { + Bound::Unbounded => Bound::Unbounded, + Bound::Included(x) => Bound::Included(*x), + Bound::Excluded(x) => Bound::Excluded(*x), + } + } +} + impl<T: Clone> Bound<&T> { /// Map a `Bound<&T>` to a `Bound<T>` by cloning the contents of the bound. /// @@ -745,8 +770,11 @@ impl<T: Clone> Bound<&T> { /// use std::ops::Bound::*; /// use std::ops::RangeBounds; /// - /// assert_eq!((1..12).start_bound(), Included(&1)); - /// assert_eq!((1..12).start_bound().cloned(), Included(1)); + /// let a1 = String::from("a"); + /// let (a2, a3, a4) = (a1.clone(), a1.clone(), a1.clone()); + /// + /// assert_eq!(Included(&a1), (a2..).start_bound()); + /// assert_eq!(Included(a3), (a4..).start_bound().cloned()); /// ``` #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "bound_cloned", since = "1.55.0")] diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index ac4a2066530..c173d7f0ae0 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -1,18 +1,18 @@ // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy #![cfg(target_has_reliable_f128)] -use std::f128::consts; - use super::{assert_approx_eq, assert_biteq}; // Note these tolerances make sense around zero, but not for more extreme exponents. /// Default tolerances. Works for values that should be near precise but not exact. Roughly /// the precision carried by `100 * 100`. +#[allow(unused)] const TOL: f128 = 1e-12; /// For operations that are near exact, usually not involving math of different /// signs. +#[allow(unused)] const TOL_PRECISE: f128 = 1e-28; /// First pattern over the mantissa @@ -44,70 +44,12 @@ fn test_mul_add() { #[test] #[cfg(any(miri, target_has_reliable_f128_math))] -fn test_recip() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_biteq!(1.0f128.recip(), 1.0); - assert_biteq!(2.0f128.recip(), 0.5); - assert_biteq!((-0.4f128).recip(), -2.5); - assert_biteq!(0.0f128.recip(), inf); +fn test_max_recip() { assert_approx_eq!( f128::MAX.recip(), 8.40525785778023376565669454330438228902076605e-4933, 1e-4900 ); - assert!(nan.recip().is_nan()); - assert_biteq!(inf.recip(), 0.0); - assert_biteq!(neg_inf.recip(), -0.0); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_powi() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_biteq!(1.0f128.powi(1), 1.0); - assert_approx_eq!((-3.1f128).powi(2), 9.6100000000000005506706202140776519387, TOL); - assert_approx_eq!(5.9f128.powi(-2), 0.028727377190462507313100483690639638451, TOL); - assert_biteq!(8.3f128.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_biteq!(inf.powi(3), inf); - assert_biteq!(neg_inf.powi(2), inf); -} - -#[test] -fn test_to_degrees() { - let pi: f128 = consts::PI; - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_biteq!(0.0f128.to_degrees(), 0.0); - assert_approx_eq!((-5.8f128).to_degrees(), -332.31552117587745090765431723855668471, TOL); - assert_approx_eq!(pi.to_degrees(), 180.0, TOL); - assert!(nan.to_degrees().is_nan()); - assert_biteq!(inf.to_degrees(), inf); - assert_biteq!(neg_inf.to_degrees(), neg_inf); - assert_biteq!(1_f128.to_degrees(), 57.2957795130823208767981548141051703); -} - -#[test] -fn test_to_radians() { - let pi: f128 = consts::PI; - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_biteq!(0.0f128.to_radians(), 0.0); - assert_approx_eq!(154.6f128.to_radians(), 2.6982790235832334267135442069489767804, TOL); - assert_approx_eq!((-332.31f128).to_radians(), -5.7999036373023566567593094812182763013, TOL); - // check approx rather than exact because round trip for pi doesn't fall on an exactly - // representable value (unlike `f32` and `f64`). - assert_approx_eq!(180.0f128.to_radians(), pi, TOL_PRECISE); - assert!(nan.to_radians().is_nan()); - assert_biteq!(inf.to_radians(), inf); - assert_biteq!(neg_inf.to_radians(), neg_inf); } #[test] diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index bb9c8a002fe..c12de7221ba 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -1,8 +1,6 @@ // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy #![cfg(target_has_reliable_f16)] -use std::f16::consts; - use super::{assert_approx_eq, assert_biteq}; /// Tolerance for results on the order of 10.0e-2 @@ -50,64 +48,8 @@ fn test_mul_add() { #[test] #[cfg(any(miri, target_has_reliable_f16_math))] -fn test_recip() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_biteq!(1.0f16.recip(), 1.0); - assert_biteq!(2.0f16.recip(), 0.5); - assert_biteq!((-0.4f16).recip(), -2.5); - assert_biteq!(0.0f16.recip(), inf); +fn test_max_recip() { assert_approx_eq!(f16::MAX.recip(), 1.526624e-5f16, 1e-4); - assert!(nan.recip().is_nan()); - assert_biteq!(inf.recip(), 0.0); - assert_biteq!(neg_inf.recip(), -0.0); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_powi() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_biteq!(1.0f16.powi(1), 1.0); - assert_approx_eq!((-3.1f16).powi(2), 9.61, TOL_0); - assert_approx_eq!(5.9f16.powi(-2), 0.028727, TOL_N2); - assert_biteq!(8.3f16.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_biteq!(inf.powi(3), inf); - assert_biteq!(neg_inf.powi(2), inf); -} - -#[test] -fn test_to_degrees() { - let pi: f16 = consts::PI; - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_biteq!(0.0f16.to_degrees(), 0.0); - assert_approx_eq!((-5.8f16).to_degrees(), -332.315521, TOL_P2); - assert_approx_eq!(pi.to_degrees(), 180.0, TOL_P2); - assert!(nan.to_degrees().is_nan()); - assert_biteq!(inf.to_degrees(), inf); - assert_biteq!(neg_inf.to_degrees(), neg_inf); - assert_biteq!(1_f16.to_degrees(), 57.2957795130823208767981548141051703); -} - -#[test] -fn test_to_radians() { - let pi: f16 = consts::PI; - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_biteq!(0.0f16.to_radians(), 0.0); - assert_approx_eq!(154.6f16.to_radians(), 2.698279, TOL_0); - assert_approx_eq!((-332.31f16).to_radians(), -5.799903, TOL_0); - assert_approx_eq!(180.0f16.to_radians(), pi, TOL_0); - assert!(nan.to_radians().is_nan()); - assert_biteq!(inf.to_radians(), inf); - assert_biteq!(neg_inf.to_radians(), neg_inf); } #[test] diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index e77e44655dc..b79295f470d 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -1,5 +1,4 @@ use core::f32; -use core::f32::consts; use super::{assert_approx_eq, assert_biteq}; @@ -9,11 +8,6 @@ const NAN_MASK1: u32 = 0x002a_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u32 = 0x0055_5555; -/// Miri adds some extra errors to float functions; make sure the tests still pass. -/// These values are purely used as a canary to test against and are thus not a stable guarantee Rust provides. -/// They serve as a way to get an idea of the real precision of floating point operations on different platforms. -const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; - // FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ #[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)] #[test] @@ -33,64 +27,6 @@ fn test_mul_add() { } #[test] -fn test_recip() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_biteq!(1.0f32.recip(), 1.0); - assert_biteq!(2.0f32.recip(), 0.5); - assert_biteq!((-0.4f32).recip(), -2.5); - assert_biteq!(0.0f32.recip(), inf); - assert!(nan.recip().is_nan()); - assert_biteq!(inf.recip(), 0.0); - assert_biteq!(neg_inf.recip(), -0.0); -} - -#[test] -fn test_powi() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(1.0f32.powi(1), 1.0); - assert_approx_eq!((-3.1f32).powi(2), 9.61, APPROX_DELTA); - assert_approx_eq!(5.9f32.powi(-2), 0.028727); - assert_biteq!(8.3f32.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_biteq!(inf.powi(3), inf); - assert_biteq!(neg_inf.powi(2), inf); -} - -#[test] -fn test_to_degrees() { - let pi: f32 = consts::PI; - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_biteq!(0.0f32.to_degrees(), 0.0); - assert_approx_eq!((-5.8f32).to_degrees(), -332.315521); - assert_biteq!(pi.to_degrees(), 180.0); - assert!(nan.to_degrees().is_nan()); - assert_biteq!(inf.to_degrees(), inf); - assert_biteq!(neg_inf.to_degrees(), neg_inf); - assert_biteq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703); -} - -#[test] -fn test_to_radians() { - let pi: f32 = consts::PI; - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_biteq!(0.0f32.to_radians(), 0.0); - assert_approx_eq!(154.6f32.to_radians(), 2.698279); - assert_approx_eq!((-332.31f32).to_radians(), -5.799903); - assert_biteq!(180.0f32.to_radians(), pi); - assert!(nan.to_radians().is_nan()); - assert_biteq!(inf.to_radians(), inf); - assert_biteq!(neg_inf.to_radians(), neg_inf); -} - -#[test] fn test_float_bits_conv() { assert_eq!((1f32).to_bits(), 0x3f800000); assert_eq!((12.5f32).to_bits(), 0x41480000); diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index fea9cc19b39..a2540586328 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -1,5 +1,4 @@ use core::f64; -use core::f64::consts; use super::{assert_approx_eq, assert_biteq}; @@ -28,63 +27,6 @@ fn test_mul_add() { } #[test] -fn test_recip() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_biteq!(1.0f64.recip(), 1.0); - assert_biteq!(2.0f64.recip(), 0.5); - assert_biteq!((-0.4f64).recip(), -2.5); - assert_biteq!(0.0f64.recip(), inf); - assert!(nan.recip().is_nan()); - assert_biteq!(inf.recip(), 0.0); - assert_biteq!(neg_inf.recip(), -0.0); -} - -#[test] -fn test_powi() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_approx_eq!(1.0f64.powi(1), 1.0); - assert_approx_eq!((-3.1f64).powi(2), 9.61); - assert_approx_eq!(5.9f64.powi(-2), 0.028727); - assert_biteq!(8.3f64.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_biteq!(inf.powi(3), inf); - assert_biteq!(neg_inf.powi(2), inf); -} - -#[test] -fn test_to_degrees() { - let pi: f64 = consts::PI; - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_biteq!(0.0f64.to_degrees(), 0.0); - assert_approx_eq!((-5.8f64).to_degrees(), -332.315521); - assert_biteq!(pi.to_degrees(), 180.0); - assert!(nan.to_degrees().is_nan()); - assert_biteq!(inf.to_degrees(), inf); - assert_biteq!(neg_inf.to_degrees(), neg_inf); -} - -#[test] -fn test_to_radians() { - let pi: f64 = consts::PI; - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_biteq!(0.0f64.to_radians(), 0.0); - assert_approx_eq!(154.6f64.to_radians(), 2.698279); - assert_approx_eq!((-332.31f64).to_radians(), -5.799903); - assert_biteq!(180.0f64.to_radians(), pi); - assert!(nan.to_radians().is_nan()); - assert_biteq!(inf.to_radians(), inf); - assert_biteq!(neg_inf.to_radians(), neg_inf); -} - -#[test] fn test_float_bits_conv() { assert_eq!((1f64).to_bits(), 0x3ff0000000000000); assert_eq!((12.5f64).to_bits(), 0x4029000000000000); diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 2c2a07920d0..5f59cb9cce3 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -1,13 +1,20 @@ use std::num::FpCategory as Fp; use std::ops::{Add, Div, Mul, Rem, Sub}; -trait TestableFloat { +trait TestableFloat: Sized { /// Unsigned int with the same size, for converting to/from bits. type Int; /// Set the default tolerance for float comparison based on the type. const APPROX: Self; + /// Allow looser tolerance for f32 on miri + const POWI_APPROX: Self = Self::APPROX; + /// Allow looser tolerance for f16 + const _180_TO_RADIANS_APPROX: Self = Self::APPROX; + /// Allow for looser tolerance for f16 + const PI_TO_DEGREES_APPROX: Self = Self::APPROX; const ZERO: Self; const ONE: Self; + const PI: Self; const MIN_POSITIVE_NORMAL: Self; const MAX_SUBNORMAL: Self; /// Smallest number @@ -25,8 +32,11 @@ trait TestableFloat { impl TestableFloat for f16 { type Int = u16; const APPROX: Self = 1e-3; + const _180_TO_RADIANS_APPROX: Self = 1e-2; + const PI_TO_DEGREES_APPROX: Self = 0.125; const ZERO: Self = 0.0; const ONE: Self = 1.0; + const PI: Self = std::f16::consts::PI; const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); const TINY: Self = Self::from_bits(0x1); @@ -39,8 +49,13 @@ impl TestableFloat for f16 { impl TestableFloat for f32 { type Int = u32; const APPROX: Self = 1e-6; + /// Miri adds some extra errors to float functions; make sure the tests still pass. + /// These values are purely used as a canary to test against and are thus not a stable guarantee Rust provides. + /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. + const POWI_APPROX: Self = if cfg!(miri) { 1e-4 } else { Self::APPROX }; const ZERO: Self = 0.0; const ONE: Self = 1.0; + const PI: Self = std::f32::consts::PI; const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); const TINY: Self = Self::from_bits(0x1); @@ -55,6 +70,7 @@ impl TestableFloat for f64 { const APPROX: Self = 1e-6; const ZERO: Self = 0.0; const ONE: Self = 1.0; + const PI: Self = std::f64::consts::PI; const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); const TINY: Self = Self::from_bits(0x1); @@ -69,6 +85,7 @@ impl TestableFloat for f128 { const APPROX: Self = 1e-9; const ZERO: Self = 0.0; const ONE: Self = 1.0; + const PI: Self = std::f128::consts::PI; const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); const TINY: Self = Self::from_bits(0x1); @@ -1340,3 +1357,86 @@ float_test! { assert_eq!(Ordering::Less, Float::total_cmp(&-s_nan(), &s_nan())); } } + +float_test! { + name: recip, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test<Float> { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + assert_biteq!((1.0 as Float).recip(), 1.0); + assert_biteq!((2.0 as Float).recip(), 0.5); + assert_biteq!((-0.4 as Float).recip(), -2.5); + assert_biteq!((0.0 as Float).recip(), inf); + assert!(nan.recip().is_nan()); + assert_biteq!(inf.recip(), 0.0); + assert_biteq!(neg_inf.recip(), -0.0); + } +} + +float_test! { + name: powi, + attrs: { + const: #[cfg(false)], + f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], + f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], + }, + test<Float> { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + assert_approx_eq!(Float::ONE.powi(1), Float::ONE); + assert_approx_eq!((-3.1 as Float).powi(2), 9.6100000000000005506706202140776519387, Float::POWI_APPROX); + assert_approx_eq!((5.9 as Float).powi(-2), 0.028727377190462507313100483690639638451); + assert_biteq!((8.3 as Float).powi(0), Float::ONE); + assert!(nan.powi(2).is_nan()); + assert_biteq!(inf.powi(3), inf); + assert_biteq!(neg_inf.powi(2), inf); + } +} + +float_test! { + name: to_degrees, + attrs: { + f16: #[cfg(target_has_reliable_f16)], + f128: #[cfg(target_has_reliable_f128)], + }, + test<Float> { + let pi: Float = Float::PI; + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + assert_biteq!((0.0 as Float).to_degrees(), 0.0); + assert_approx_eq!((-5.8 as Float).to_degrees(), -332.31552117587745090765431723855668471); + assert_approx_eq!(pi.to_degrees(), 180.0, Float::PI_TO_DEGREES_APPROX); + assert!(nan.to_degrees().is_nan()); + assert_biteq!(inf.to_degrees(), inf); + assert_biteq!(neg_inf.to_degrees(), neg_inf); + assert_biteq!((1.0 as Float).to_degrees(), 57.2957795130823208767981548141051703); + } +} + +float_test! { + name: to_radians, + attrs: { + f16: #[cfg(target_has_reliable_f16)], + f128: #[cfg(target_has_reliable_f128)], + }, + test<Float> { + let pi: Float = Float::PI; + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + assert_biteq!((0.0 as Float).to_radians(), 0.0); + assert_approx_eq!((154.6 as Float).to_radians(), 2.6982790235832334267135442069489767804); + assert_approx_eq!((-332.31 as Float).to_radians(), -5.7999036373023566567593094812182763013); + assert_approx_eq!((180.0 as Float).to_radians(), pi, Float::_180_TO_RADIANS_APPROX); + assert!(nan.to_radians().is_nan()); + assert_biteq!(inf.to_radians(), inf); + assert_biteq!(neg_inf.to_radians(), neg_inf); + } +} diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 3771699c59f..7bdc6ff7882 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -290,7 +290,6 @@ #![feature(doc_masked)] #![feature(doc_notable_trait)] #![feature(dropck_eyepatch)] -#![feature(extended_varargs_abi_support)] #![feature(f16)] #![feature(f128)] #![feature(ffi_const)] diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index aec089f7e5c..f0b6068e06c 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -186,14 +186,24 @@ pub fn chdir(p: &path::Path) -> io::Result<()> { if result == 0 { Ok(()) } else { Err(io::Error::last_os_error()) } } -pub type SplitPaths<'a> = impl Iterator<Item = PathBuf>; +// This can't just be `impl Iterator` because that requires `'a` to be live on +// drop (see #146045). +pub type SplitPaths<'a> = iter::Map< + slice::Split<'a, u8, impl FnMut(&u8) -> bool + 'static>, + impl FnMut(&[u8]) -> PathBuf + 'static, +>; #[define_opaque(SplitPaths)] pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> { - unparsed - .as_bytes() - .split(|&b| b == PATH_SEPARATOR) - .map(|part| PathBuf::from(OsStr::from_bytes(part))) + fn is_separator(&b: &u8) -> bool { + b == PATH_SEPARATOR + } + + fn into_pathbuf(part: &[u8]) -> PathBuf { + PathBuf::from(OsStr::from_bytes(part)) + } + + unparsed.as_bytes().split(is_separator).map(into_pathbuf) } #[derive(Debug)] diff --git a/library/std/tests/floats/f32.rs b/library/std/tests/floats/f32.rs index 38c906c1d87..c61a8ec4d20 100644 --- a/library/std/tests/floats/f32.rs +++ b/library/std/tests/floats/f32.rs @@ -79,8 +79,8 @@ fn test_log() { let nan: f32 = f32::NAN; let inf: f32 = f32::INFINITY; let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(10.0f32.log(10.0), 1.0); - assert_approx_eq!(2.3f32.log(3.5), 0.664858); + assert_approx_eq!(10.0f32.log(10.0), 1.0, APPROX_DELTA); + assert_approx_eq!(2.3f32.log(3.5), 0.664858, APPROX_DELTA); assert_approx_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0, APPROX_DELTA); assert!(1.0f32.log(1.0).is_nan()); assert!(1.0f32.log(-13.9).is_nan()); diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index bebae893ee7..a604e7c0585 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -8,8 +8,8 @@ use crate::core::build_steps::compile::{ }; use crate::core::build_steps::tool; use crate::core::build_steps::tool::{ - COMPILETEST_ALLOW_FEATURES, SourceType, ToolTargetBuildMode, get_tool_target_compiler, - prepare_tool_cargo, + COMPILETEST_ALLOW_FEATURES, SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, ToolTargetBuildMode, + get_tool_target_compiler, prepare_tool_cargo, }; use crate::core::builder::{ self, Alias, Builder, Cargo, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description, @@ -791,7 +791,7 @@ tool_check_step!(MiroptTestTools { tool_check_step!(TestFloatParse { path: "src/tools/test-float-parse", mode: |_builder| Mode::ToolStd, - allow_features: tool::TestFloatParse::ALLOW_FEATURES + allow_features: TEST_FLOAT_PARSE_ALLOW_FEATURES }); tool_check_step!(FeaturesStatusDump { path: "src/tools/features-status-dump", diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 9ef1fee1fec..0789eefa894 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -791,7 +791,11 @@ fn doc_std( } /// Prepare a compiler that will be able to document something for `target` at `stage`. -fn prepare_doc_compiler(builder: &Builder<'_>, target: TargetSelection, stage: u32) -> Compiler { +pub fn prepare_doc_compiler( + builder: &Builder<'_>, + target: TargetSelection, + stage: u32, +) -> Compiler { assert!(stage > 0, "Cannot document anything in stage 0"); let build_compiler = builder.compiler(stage - 1, builder.host_target); builder.std(build_compiler, target); @@ -1289,6 +1293,8 @@ impl Step for RustcBook { // functional sysroot. builder.std(self.build_compiler, self.target); let mut cmd = builder.tool_cmd(Tool::LintDocs); + cmd.arg("--build-rustc-stage"); + cmd.arg(self.build_compiler.stage.to_string()); cmd.arg("--src"); cmd.arg(builder.src.join("compiler")); cmd.arg("--out"); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 26b4aaa8b5b..95be5360b0b 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -12,14 +12,14 @@ use std::{env, fs, iter}; use build_helper::exit; use crate::core::build_steps::compile::{Std, run_cargo}; -use crate::core::build_steps::doc::DocumentationFormat; +use crate::core::build_steps::doc::{DocumentationFormat, prepare_doc_compiler}; use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags}; use crate::core::build_steps::llvm::get_llvm_version; use crate::core::build_steps::run::get_completion_paths; use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget; use crate::core::build_steps::tool::{ - self, COMPILETEST_ALLOW_FEATURES, RustcPrivateCompilers, SourceType, Tool, ToolTargetBuildMode, - get_tool_target_compiler, + self, COMPILETEST_ALLOW_FEATURES, RustcPrivateCompilers, SourceType, + TEST_FLOAT_PARSE_ALLOW_FEATURES, Tool, ToolTargetBuildMode, get_tool_target_compiler, }; use crate::core::build_steps::toolstate::ToolState; use crate::core::build_steps::{compile, dist, llvm}; @@ -96,7 +96,14 @@ impl Step for CrateBootstrap { ); let crate_name = path.rsplit_once('/').unwrap().1; - run_cargo_test(cargo, &[], &[], crate_name, bootstrap_host, builder); + run_cargo_test(cargo, &[], &[], crate_name, bootstrap_host, builder, Mode::ToolBootstrap); + } + + fn metadata(&self) -> Option<StepMetadata> { + Some( + StepMetadata::test("crate-bootstrap", self.host) + .with_metadata(self.path.as_path().to_string_lossy().to_string()), + ) } } @@ -146,7 +153,15 @@ You can skip linkcheck with --skip src/tools/linkchecker" SourceType::InTree, &[], ); - run_cargo_test(cargo, &[], &[], "linkchecker self tests", bootstrap_host, builder); + run_cargo_test( + cargo, + &[], + &[], + "linkchecker self tests", + bootstrap_host, + builder, + Mode::ToolBootstrap, + ); if builder.doc_tests == DocTests::No { return; @@ -173,6 +188,10 @@ You can skip linkcheck with --skip src/tools/linkchecker" fn make_run(run: RunConfig<'_>) { run.builder.ensure(Linkcheck { host: run.target }); } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::test("link-check", self.host)) + } } fn check_if_tidy_is_installed(builder: &Builder<'_>) -> bool { @@ -221,6 +240,10 @@ impl Step for HtmlCheck { .arg(builder.doc_out(self.target)) .run(builder); } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::test("html-check", self.target)) + } } /// Builds cargo and then runs the `src/tools/cargotest` tool, which checks out @@ -399,6 +422,10 @@ impl Step for Cargo { let _time = helpers::timeit(builder); add_flags_and_try_run_tests(builder, &mut cargo); } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::test("cargo", self.host).built_by(self.build_compiler)) + } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -455,7 +482,14 @@ impl Step for RustAnalyzer { cargo.env("SKIP_SLOW_TESTS", "1"); cargo.add_rustc_lib_path(builder); - run_cargo_test(cargo, &[], &[], "rust-analyzer", host, builder); + run_cargo_test(cargo, &[], &[], "rust-analyzer", host, builder, Mode::ToolRustc); + } + + fn metadata(&self) -> Option<StepMetadata> { + Some( + StepMetadata::test("rust-analyzer", self.compilers.target()) + .built_by(self.compilers.build_compiler()), + ) } } @@ -506,7 +540,14 @@ impl Step for Rustfmt { cargo.add_rustc_lib_path(builder); - run_cargo_test(cargo, &[], &[], "rustfmt", target, builder); + run_cargo_test(cargo, &[], &[], "rustfmt", target, builder, Mode::ToolRustc); + } + + fn metadata(&self) -> Option<StepMetadata> { + Some( + StepMetadata::test("rustfmt", self.compilers.target()) + .built_by(self.compilers.build_compiler()), + ) } } @@ -792,7 +833,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the cargo.env("TEST_RUSTC", builder.rustc(compiler)); cargo.allow_features(COMPILETEST_ALLOW_FEATURES); - run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder); + run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder, Mode::ToolStd); } } @@ -887,6 +928,13 @@ impl Step for Clippy { crate::exit!(1); } } + + fn metadata(&self) -> Option<StepMetadata> { + Some( + StepMetadata::test("clippy", self.compilers.target()) + .built_by(self.compilers.build_compiler()), + ) + } } fn bin_path_for_cargo(builder: &Builder<'_>, compiler: Compiler) -> OsString { @@ -895,9 +943,11 @@ fn bin_path_for_cargo(builder: &Builder<'_>, compiler: Compiler) -> OsString { env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("") } +/// Run the rustdoc-themes tool to test a given compiler. #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustdocTheme { - pub compiler: Compiler, + /// The compiler (more accurately, its rustdoc) that we test. + test_compiler: Compiler, } impl Step for RustdocTheme { @@ -910,9 +960,9 @@ impl Step for RustdocTheme { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.target); + let test_compiler = run.builder.compiler(run.builder.top_stage, run.target); - run.builder.ensure(RustdocTheme { compiler }); + run.builder.ensure(RustdocTheme { test_compiler }); } fn run(self, builder: &Builder<'_>) { @@ -920,21 +970,34 @@ impl Step for RustdocTheme { let mut cmd = builder.tool_cmd(Tool::RustdocTheme); cmd.arg(rustdoc.to_str().unwrap()) .arg(builder.src.join("src/librustdoc/html/static/css/rustdoc.css").to_str().unwrap()) - .env("RUSTC_STAGE", self.compiler.stage.to_string()) - .env("RUSTC_SYSROOT", builder.sysroot(self.compiler)) - .env("RUSTDOC_LIBDIR", builder.sysroot_target_libdir(self.compiler, self.compiler.host)) + .env("RUSTC_STAGE", self.test_compiler.stage.to_string()) + .env("RUSTC_SYSROOT", builder.sysroot(self.test_compiler)) + .env( + "RUSTDOC_LIBDIR", + builder.sysroot_target_libdir(self.test_compiler, self.test_compiler.host), + ) .env("CFG_RELEASE_CHANNEL", &builder.config.channel) - .env("RUSTDOC_REAL", builder.rustdoc_for_compiler(self.compiler)) + .env("RUSTDOC_REAL", builder.rustdoc_for_compiler(self.test_compiler)) .env("RUSTC_BOOTSTRAP", "1"); - cmd.args(linker_args(builder, self.compiler.host, LldThreads::No)); + cmd.args(linker_args(builder, self.test_compiler.host, LldThreads::No)); cmd.delay_failure().run(builder); } + + fn metadata(&self) -> Option<StepMetadata> { + Some( + StepMetadata::test("rustdoc-theme", self.test_compiler.host) + .stage(self.test_compiler.stage), + ) + } } +/// Test rustdoc JS for the standard library. #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustdocJSStd { - pub target: TargetSelection, + /// Compiler that will build the standary library. + build_compiler: Compiler, + target: TargetSelection, } impl Step for RustdocJSStd { @@ -948,7 +1011,10 @@ impl Step for RustdocJSStd { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(RustdocJSStd { target: run.target }); + run.builder.ensure(RustdocJSStd { + build_compiler: run.builder.compiler(run.builder.top_stage, run.builder.host_target), + target: run.target, + }); } fn run(self, builder: &Builder<'_>) { @@ -976,19 +1042,18 @@ impl Step for RustdocJSStd { } } builder.ensure(crate::core::build_steps::doc::Std::from_build_compiler( - builder.compiler(builder.top_stage, builder.host_target), + self.build_compiler, self.target, DocumentationFormat::Html, )); - let _guard = builder.msg( - Kind::Test, - "rustdoc-js-std", - None, - (builder.config.host_target, builder.top_stage), - self.target, - ); + let _guard = + builder.msg(Kind::Test, "rustdoc-js-std", None, self.build_compiler, self.target); command.run(builder); } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::test("rustdoc-js-std", self.target).stage(self.build_compiler.stage)) + } } #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -1046,10 +1111,12 @@ fn get_browser_ui_test_version(builder: &Builder<'_>, npm: &Path) -> Option<Stri .or_else(|| get_browser_ui_test_version_inner(builder, npm, true)) } +/// Run GUI tests on a given rustdoc. #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustdocGUI { - pub target: TargetSelection, - pub compiler: Compiler, + /// The compiler whose rustdoc we are testing. + test_compiler: Compiler, + target: TargetSelection, } impl Step for RustdocGUI { @@ -1073,12 +1140,12 @@ impl Step for RustdocGUI { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); - run.builder.ensure(RustdocGUI { target: run.target, compiler }); + let test_compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); + run.builder.ensure(RustdocGUI { test_compiler, target: run.target }); } fn run(self, builder: &Builder<'_>) { - builder.std(self.compiler, self.target); + builder.std(self.test_compiler, self.target); let mut cmd = builder.tool_cmd(Tool::RustdocGUITest); @@ -1086,7 +1153,7 @@ impl Step for RustdocGUI { build_stamp::clear_if_dirty( builder, &out_dir, - &builder.rustdoc_for_compiler(self.compiler), + &builder.rustdoc_for_compiler(self.test_compiler), ); if let Some(src) = builder.config.src.to_str() { @@ -1103,10 +1170,10 @@ impl Step for RustdocGUI { cmd.arg("--jobs").arg(builder.jobs().to_string()); - cmd.env("RUSTDOC", builder.rustdoc_for_compiler(self.compiler)) - .env("RUSTC", builder.rustc(self.compiler)); + cmd.env("RUSTDOC", builder.rustdoc_for_compiler(self.test_compiler)) + .env("RUSTC", builder.rustc(self.test_compiler)); - add_rustdoc_cargo_linker_args(&mut cmd, builder, self.compiler.host, LldThreads::No); + add_rustdoc_cargo_linker_args(&mut cmd, builder, self.test_compiler.host, LldThreads::No); for path in &builder.paths { if let Some(p) = helpers::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder) { @@ -1133,9 +1200,13 @@ impl Step for RustdocGUI { } let _time = helpers::timeit(builder); - let _guard = builder.msg(Kind::Test, "rustdoc-gui", None, self.compiler, self.target); + let _guard = builder.msg_test("rustdoc-gui", (self.target, self.test_compiler.stage)); try_run_tests(builder, &mut cmd, true); } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::test("rustdoc-gui", self.target).stage(self.test_compiler.stage)) + } } /// Runs `src/tools/tidy` and `cargo fmt --check` to detect various style @@ -1253,76 +1324,6 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to } } -fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf { - builder.out.join(host).join("test") -} - -/// Declares a test step that invokes compiletest on a particular test suite. -macro_rules! test { - ( - $( #[$attr:meta] )* // allow docstrings and attributes - $name:ident { - path: $path:expr, - mode: $mode:expr, - suite: $suite:expr, - default: $default:expr - $( , IS_HOST: $IS_HOST:expr )? // default: false - $( , compare_mode: $compare_mode:expr )? // default: None - $( , )? // optional trailing comma - } - ) => { - $( #[$attr] )* - #[derive(Debug, Clone, PartialEq, Eq, Hash)] - pub struct $name { - pub compiler: Compiler, - pub target: TargetSelection, - } - - impl Step for $name { - type Output = (); - const DEFAULT: bool = $default; - const IS_HOST: bool = (const { - #[allow(unused_assignments, unused_mut)] - let mut value = false; - $( value = $IS_HOST; )? - value - }); - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.suite_path($path) - } - - fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); - - run.builder.ensure($name { compiler, target: run.target }); - } - - fn run(self, builder: &Builder<'_>) { - builder.ensure(Compiletest { - compiler: self.compiler, - target: self.target, - mode: $mode, - suite: $suite, - path: $path, - compare_mode: (const { - #[allow(unused_assignments, unused_mut)] - let mut value = None; - $( value = $compare_mode; )? - value - }), - }) - } - - fn metadata(&self) -> Option<StepMetadata> { - Some( - StepMetadata::test(stringify!($name), self.target) - ) - } - } - }; -} - /// Runs `cargo test` on the `src/tools/run-make-support` crate. /// That crate is used by run-make tests. #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -1358,7 +1359,15 @@ impl Step for CrateRunMakeSupport { &[], ); cargo.allow_features("test"); - run_cargo_test(cargo, &[], &[], "run-make-support self test", host, builder); + run_cargo_test( + cargo, + &[], + &[], + "run-make-support self test", + host, + builder, + Mode::ToolBootstrap, + ); } } @@ -1395,10 +1404,88 @@ impl Step for CrateBuildHelper { &[], ); cargo.allow_features("test"); - run_cargo_test(cargo, &[], &[], "build_helper self test", host, builder); + run_cargo_test( + cargo, + &[], + &[], + "build_helper self test", + host, + builder, + Mode::ToolBootstrap, + ); } } +fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf { + builder.out.join(host).join("test") +} + +/// Declares a test step that invokes compiletest on a particular test suite. +macro_rules! test { + ( + $( #[$attr:meta] )* // allow docstrings and attributes + $name:ident { + path: $path:expr, + mode: $mode:expr, + suite: $suite:expr, + default: $default:expr + $( , IS_HOST: $IS_HOST:expr )? // default: false + $( , compare_mode: $compare_mode:expr )? // default: None + $( , )? // optional trailing comma + } + ) => { + $( #[$attr] )* + #[derive(Debug, Clone, PartialEq, Eq, Hash)] + pub struct $name { + pub compiler: Compiler, + pub target: TargetSelection, + } + + impl Step for $name { + type Output = (); + const DEFAULT: bool = $default; + const IS_HOST: bool = (const { + #[allow(unused_assignments, unused_mut)] + let mut value = false; + $( value = $IS_HOST; )? + value + }); + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.suite_path($path) + } + + fn make_run(run: RunConfig<'_>) { + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); + + run.builder.ensure($name { compiler, target: run.target }); + } + + fn run(self, builder: &Builder<'_>) { + builder.ensure(Compiletest { + compiler: self.compiler, + target: self.target, + mode: $mode, + suite: $suite, + path: $path, + compare_mode: (const { + #[allow(unused_assignments, unused_mut)] + let mut value = None; + $( value = $compare_mode; )? + value + }), + }) + } + + fn metadata(&self) -> Option<StepMetadata> { + Some( + StepMetadata::test(stringify!($name), self.target) + ) + } + } + }; +} + test!(Ui { path: "tests/ui", mode: "ui", suite: "ui", default: true }); test!(Crashes { path: "tests/crashes", mode: "crashes", suite: "crashes", default: true }); @@ -1741,7 +1828,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the builder.std(compiler, target); } - builder.ensure(RemoteCopyLibs { compiler, target }); + builder.ensure(RemoteCopyLibs { build_compiler: compiler, target }); // compiletest currently has... a lot of arguments, so let's just pass all // of them! @@ -2277,9 +2364,10 @@ HELP: You can add it into `bootstrap.toml` in `rust.codegen-backends = [{name:?} } } +/// Runs the documentation tests for a book in `src/doc` using the `rustdoc` of `test_compiler`. #[derive(Debug, Clone, PartialEq, Eq, Hash)] struct BookTest { - compiler: Compiler, + test_compiler: Compiler, path: PathBuf, name: &'static str, is_ext_doc: bool, @@ -2294,9 +2382,6 @@ impl Step for BookTest { run.never() } - /// Runs the documentation tests for a book in `src/doc`. - /// - /// This uses the `rustdoc` that sits next to `compiler`. fn run(self, builder: &Builder<'_>) { // External docs are different from local because: // - Some books need pre-processing by mdbook before being tested. @@ -2319,13 +2404,13 @@ impl BookTest { /// This runs the equivalent of `mdbook test` (via the rustbook wrapper) /// which in turn runs `rustdoc --test` on each file in the book. fn run_ext_doc(self, builder: &Builder<'_>) { - let compiler = self.compiler; + let test_compiler = self.test_compiler; - builder.std(compiler, compiler.host); + builder.std(test_compiler, test_compiler.host); // mdbook just executes a binary named "rustdoc", so we need to update // PATH so that it points to our rustdoc. - let mut rustdoc_path = builder.rustdoc_for_compiler(compiler); + let mut rustdoc_path = builder.rustdoc_for_compiler(test_compiler); rustdoc_path.pop(); let old_path = env::var_os("PATH").unwrap_or_default(); let new_path = env::join_paths(iter::once(rustdoc_path).chain(env::split_paths(&old_path))) @@ -2348,7 +2433,7 @@ impl BookTest { let target = builder.config.host_target; let cargo = tool::prepare_tool_cargo( builder, - compiler, + test_compiler, mode, target, Kind::Build, @@ -2357,7 +2442,7 @@ impl BookTest { &[], ); - let stamp = BuildStamp::new(&builder.cargo_out(compiler, mode, target)) + let stamp = BuildStamp::new(&builder.cargo_out(test_compiler, mode, target)) .with_prefix(PathBuf::from(dep).file_name().and_then(|v| v.to_str()).unwrap()); let output_paths = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false); @@ -2390,8 +2475,8 @@ impl BookTest { Kind::Test, format_args!("mdbook {}", self.path.display()), None, - compiler, - compiler.host, + test_compiler, + test_compiler.host, ); let _time = helpers::timeit(builder); let toolstate = if rustbook_cmd.delay_failure().run(builder) { @@ -2404,12 +2489,18 @@ impl BookTest { /// This runs `rustdoc --test` on all `.md` files in the path. fn run_local_doc(self, builder: &Builder<'_>) { - let compiler = self.compiler; - let host = self.compiler.host; + let test_compiler = self.test_compiler; + let host = self.test_compiler.host; - builder.std(compiler, host); + builder.std(test_compiler, host); - let _guard = builder.msg(Kind::Test, format!("book {}", self.name), None, compiler, host); + let _guard = builder.msg( + Kind::Test, + format!("book {}", self.name), + None, + (test_compiler.host, test_compiler.stage - 1), + host, + ); // Do a breadth-first traversal of the `src/doc` directory and just run // tests for all files that end in `*.md` @@ -2432,7 +2523,7 @@ impl BookTest { files.sort(); for file in files { - markdown_test(builder, compiler, &file); + markdown_test(builder, test_compiler, &file); } } } @@ -2448,7 +2539,7 @@ macro_rules! test_book { $( #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct $name { - compiler: Compiler, + test_compiler: Compiler, } impl Step for $name { @@ -2462,7 +2553,7 @@ macro_rules! test_book { fn make_run(run: RunConfig<'_>) { run.builder.ensure($name { - compiler: run.builder.compiler(run.builder.top_stage, run.target), + test_compiler: run.builder.compiler(run.builder.top_stage, run.target), }); } @@ -2482,7 +2573,7 @@ macro_rules! test_book { )? builder.ensure(BookTest { - compiler: self.compiler, + test_compiler: self.test_compiler, path: PathBuf::from($path), name: $book_name, is_ext_doc: !$default, @@ -2602,7 +2693,8 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> /// which have their own separate test steps.) #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CrateLibrustc { - compiler: Compiler, + /// The compiler that will run unit tests and doctests on the in-tree rustc source. + build_compiler: Compiler, target: TargetSelection, crates: Vec<String>, } @@ -2619,18 +2711,18 @@ impl Step for CrateLibrustc { fn make_run(run: RunConfig<'_>) { let builder = run.builder; let host = run.build_triple(); - let compiler = builder.compiler_for(builder.top_stage, host, host); + let build_compiler = builder.compiler(builder.top_stage - 1, host); let crates = run.make_run_crates(Alias::Compiler); - builder.ensure(CrateLibrustc { compiler, target: run.target, crates }); + builder.ensure(CrateLibrustc { build_compiler, target: run.target, crates }); } fn run(self, builder: &Builder<'_>) { - builder.std(self.compiler, self.target); + builder.std(self.build_compiler, self.target); // To actually run the tests, delegate to a copy of the `Crate` step. builder.ensure(Crate { - compiler: self.compiler, + build_compiler: self.build_compiler, target: self.target, mode: Mode::Rustc, crates: self.crates, @@ -2638,7 +2730,7 @@ impl Step for CrateLibrustc { } fn metadata(&self) -> Option<StepMetadata> { - Some(StepMetadata::test("CrateLibrustc", self.target)) + Some(StepMetadata::test("CrateLibrustc", self.target).built_by(self.build_compiler)) } } @@ -2652,12 +2744,14 @@ fn run_cargo_test<'a>( description: impl Into<Option<&'a str>>, target: TargetSelection, builder: &Builder<'_>, + mode: impl Into<Option<Mode>>, ) -> bool { + let mode = mode.into(); let compiler = cargo.compiler(); let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, target, builder); let _time = helpers::timeit(builder); let _group = - description.into().and_then(|what| builder.msg(Kind::Test, what, None, compiler, target)); + description.into().and_then(|what| builder.msg(Kind::Test, what, mode, compiler, target)); #[cfg(feature = "build-metrics")] builder.metrics.begin_test_suite( @@ -2755,10 +2849,11 @@ fn prepare_cargo_test( /// library crates and compiler crates. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Crate { - pub compiler: Compiler, - pub target: TargetSelection, - pub mode: Mode, - pub crates: Vec<String>, + /// The compiler that will *build* libstd or rustc in test mode. + build_compiler: Compiler, + target: TargetSelection, + mode: Mode, + crates: Vec<String>, } impl Step for Crate { @@ -2772,14 +2867,14 @@ impl Step for Crate { fn make_run(run: RunConfig<'_>) { let builder = run.builder; let host = run.build_triple(); - let compiler = builder.compiler_for(builder.top_stage, host, host); + let build_compiler = builder.compiler(builder.top_stage, host); let crates = run .paths .iter() .map(|p| builder.crate_paths[&p.assert_single_path().path].clone()) .collect(); - builder.ensure(Crate { compiler, target: run.target, mode: Mode::Std, crates }); + builder.ensure(Crate { build_compiler, target: run.target, mode: Mode::Std, crates }); } /// Runs all unit tests plus documentation tests for a given crate defined @@ -2791,19 +2886,13 @@ impl Step for Crate { /// Currently this runs all tests for a DAG by passing a bunch of `-p foo` /// arguments, and those arguments are discovered from `cargo metadata`. fn run(self, builder: &Builder<'_>) { - let compiler = self.compiler; + let build_compiler = self.build_compiler; let target = self.target; let mode = self.mode; // Prepare sysroot // See [field@compile::Std::force_recompile]. - builder.ensure(Std::new(compiler, compiler.host).force_recompile(true)); - - // If we're not doing a full bootstrap but we're testing a stage2 - // version of libstd, then what we're actually testing is the libstd - // produced in stage1. Reflect that here by updating the compiler that - // we're working with automatically. - let compiler = builder.compiler_for(compiler.stage, compiler.host, target); + builder.ensure(Std::new(build_compiler, build_compiler.host).force_recompile(true)); let mut cargo = if builder.kind == Kind::Miri { if builder.top_stage == 0 { @@ -2815,7 +2904,7 @@ impl Step for Crate { // (Implicitly prepares target sysroot) let mut cargo = builder::Cargo::new( builder, - compiler, + build_compiler, mode, SourceType::InTree, target, @@ -2841,12 +2930,19 @@ impl Step for Crate { } else { // Also prepare a sysroot for the target. if !builder.config.is_host_target(target) { - builder.ensure(compile::Std::new(compiler, target).force_recompile(true)); - builder.ensure(RemoteCopyLibs { compiler, target }); + builder.ensure(compile::Std::new(build_compiler, target).force_recompile(true)); + builder.ensure(RemoteCopyLibs { build_compiler, target }); } // Build `cargo test` command - builder::Cargo::new(builder, compiler, mode, SourceType::InTree, target, builder.kind) + builder::Cargo::new( + builder, + build_compiler, + mode, + SourceType::InTree, + target, + builder.kind, + ) }; match mode { @@ -2865,7 +2961,7 @@ impl Step for Crate { } } Mode::Rustc => { - compile::rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates); + compile::rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates); } _ => panic!("can only test libraries"), }; @@ -2882,10 +2978,19 @@ impl Step for Crate { crates.push("alloctests".to_owned()); } - run_cargo_test(cargo, &[], &crates, &*crate_description(&self.crates), target, builder); + run_cargo_test( + cargo, + &[], + &crates, + &*crate_description(&self.crates), + target, + builder, + mode, + ); } } +/// Run cargo tests for the rustdoc crate. /// Rustdoc is special in various ways, which is why this step is different from `Crate`. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CrateRustdoc { @@ -2975,13 +3080,22 @@ impl Step for CrateRustdoc { dylib_path.insert(0, PathBuf::from(&*libdir)); cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); - run_cargo_test(cargo, &[], &["rustdoc:0.0.0".to_string()], "rustdoc", target, builder); + run_cargo_test( + cargo, + &[], + &["rustdoc:0.0.0".to_string()], + "rustdoc", + target, + builder, + Mode::ToolRustc, + ); } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CrateRustdocJsonTypes { - host: TargetSelection, + build_compiler: Compiler, + target: TargetSelection, } impl Step for CrateRustdocJsonTypes { @@ -2996,23 +3110,22 @@ impl Step for CrateRustdocJsonTypes { fn make_run(run: RunConfig<'_>) { let builder = run.builder; - builder.ensure(CrateRustdocJsonTypes { host: run.target }); + builder.ensure(CrateRustdocJsonTypes { + build_compiler: get_tool_target_compiler( + builder, + ToolTargetBuildMode::Build(run.target), + ), + target: run.target, + }); } fn run(self, builder: &Builder<'_>) { - let target = self.host; - - // Use the previous stage compiler to reuse the artifacts that are - // created when running compiletest for tests/rustdoc. If this used - // `compiler`, then it would cause rustdoc to be built *again*, which - // isn't really necessary. - let compiler = builder.compiler_for(builder.top_stage, target, target); - builder.ensure(compile::Rustc::new(compiler, target)); + let target = self.target; let cargo = tool::prepare_tool_cargo( builder, - compiler, - Mode::ToolRustc, + self.build_compiler, + Mode::ToolTarget, target, builder.kind, "src/rustdoc-json-types", @@ -3021,7 +3134,7 @@ impl Step for CrateRustdocJsonTypes { ); // FIXME: this looks very wrong, libtest doesn't accept `-C` arguments and the quotes are fishy. - let libtest_args = if self.host.contains("musl") { + let libtest_args = if target.contains("musl") { ["'-Ctarget-feature=-crt-static'"].as_slice() } else { &[] @@ -3034,6 +3147,7 @@ impl Step for CrateRustdocJsonTypes { "rustdoc-json-types", target, builder, + Mode::ToolTarget, ); } } @@ -3049,7 +3163,7 @@ impl Step for CrateRustdocJsonTypes { /// the build target (us) and the server is built for the target. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct RemoteCopyLibs { - compiler: Compiler, + build_compiler: Compiler, target: TargetSelection, } @@ -3061,18 +3175,17 @@ impl Step for RemoteCopyLibs { } fn run(self, builder: &Builder<'_>) { - let compiler = self.compiler; + let build_compiler = self.build_compiler; let target = self.target; if !builder.remote_tested(target) { return; } - builder.std(compiler, target); + builder.std(build_compiler, target); builder.info(&format!("REMOTE copy libs to emulator ({target})")); - let remote_test_server = - builder.ensure(tool::RemoteTestServer { build_compiler: compiler, target }); + let remote_test_server = builder.ensure(tool::RemoteTestServer { build_compiler, target }); // Spawn the emulator and wait for it to come online let tool = builder.tool_exe(Tool::RemoteTestClient); @@ -3087,7 +3200,7 @@ impl Step for RemoteCopyLibs { cmd.run(builder); // Push all our dylibs to the emulator - for f in t!(builder.sysroot_target_libdir(compiler, target).read_dir()) { + for f in t!(builder.sysroot_target_libdir(build_compiler, target).read_dir()) { let f = t!(f); if helpers::is_dylib(&f.path()) { command(&tool).arg("push").arg(f.path()).run(builder); @@ -3133,6 +3246,9 @@ impl Step for Distcheck { .map(|args| args.split(" ").map(|s| s.to_string()).collect::<Vec<String>>()) .unwrap_or_default(); + // FIXME: unpack the source tarballs into a directory outside the source checkout, to + // ensure that it cannot access any local state + // Also ensure that it doesn't use download-ci-llvm command("tar") .arg("-xf") .arg(plain_src_tarball.tarball()) @@ -3232,7 +3348,7 @@ impl Step for Bootstrap { // bootstrap tests are racy on directory creation so just run them one at a time. // Since there's not many this shouldn't be a problem. - run_cargo_test(cargo, &["--test-threads=1"], &[], None, host, builder); + run_cargo_test(cargo, &["--test-threads=1"], &[], None, host, builder, Mode::ToolBootstrap); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -3248,9 +3364,15 @@ impl Step for Bootstrap { } } +fn get_compiler_to_test(builder: &Builder<'_>, target: TargetSelection) -> Compiler { + builder.compiler(builder.top_stage, target) +} + +/// Tests the Platform Support page in the rustc book. +/// `test_compiler` is used to query the actual targets that are checked. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct TierCheck { - pub compiler: Compiler, + test_compiler: Compiler, } impl Step for TierCheck { @@ -3263,48 +3385,42 @@ impl Step for TierCheck { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler_for( - run.builder.top_stage, - run.builder.build.host_target, - run.target, - ); - run.builder.ensure(TierCheck { compiler }); + run.builder + .ensure(TierCheck { test_compiler: get_compiler_to_test(run.builder, run.target) }); } - /// Tests the Platform Support page in the rustc book. fn run(self, builder: &Builder<'_>) { - builder.std(self.compiler, self.compiler.host); + let tool_build_compiler = builder.compiler(0, builder.host_target); + let mut cargo = tool::prepare_tool_cargo( builder, - self.compiler, - Mode::ToolStd, - self.compiler.host, + tool_build_compiler, + Mode::ToolBootstrap, + tool_build_compiler.host, Kind::Run, "src/tools/tier-check", SourceType::InTree, &[], ); cargo.arg(builder.src.join("src/doc/rustc/src/platform-support.md")); - cargo.arg(builder.rustc(self.compiler)); + cargo.arg(builder.rustc(self.test_compiler)); if builder.is_verbose() { cargo.arg("--verbose"); } - let _guard = builder.msg( - Kind::Test, - "platform support check", - None, - self.compiler, - self.compiler.host, - ); + let _guard = builder.msg_test("platform support check", self.test_compiler); BootstrapCommand::from(cargo).delay_failure().run(builder); } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::test("tier-check", self.test_compiler.host)) + } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct LintDocs { - pub compiler: Compiler, - pub target: TargetSelection, + build_compiler: Compiler, + target: TargetSelection, } impl Step for LintDocs { @@ -3313,12 +3429,23 @@ impl Step for LintDocs { const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/tools/lint-docs") + let stage = run.builder.top_stage; + // Lint docs tests might not work with stage 1, so do not run this test by default in + // `x test` below stage 2. + run.path("src/tools/lint-docs").default_condition(stage > 1) } fn make_run(run: RunConfig<'_>) { + if run.builder.top_stage < 2 { + eprintln!("WARNING: lint-docs tests might not work below stage 2"); + } + run.builder.ensure(LintDocs { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target), + build_compiler: prepare_doc_compiler( + run.builder, + run.builder.config.host_target, + run.builder.top_stage, + ), target: run.target, }); } @@ -3326,8 +3453,14 @@ impl Step for LintDocs { /// Tests that the lint examples in the rustc book generate the correct /// lints and have the expected format. fn run(self, builder: &Builder<'_>) { - builder - .ensure(crate::core::build_steps::doc::RustcBook::validate(self.compiler, self.target)); + builder.ensure(crate::core::build_steps::doc::RustcBook::validate( + self.build_compiler, + self.target, + )); + } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::test("lint-docs", self.target).built_by(self.build_compiler)) } } @@ -3356,7 +3489,7 @@ impl Step for RustInstaller { let _guard = builder.msg(Kind::Test, "rust-installer", None, build_compiler, bootstrap_host); - run_cargo_test(cargo, &[], &[], None, bootstrap_host, builder); + run_cargo_test(cargo, &[], &[], None, bootstrap_host, builder, Mode::ToolBootstrap); // We currently don't support running the test.sh script outside linux(?) environments. // Eventually this should likely migrate to #[test]s in rust-installer proper rather than a @@ -3449,7 +3582,7 @@ impl Step for TestHelpers { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CodegenCranelift { - compiler: Compiler, + compilers: RustcPrivateCompilers, target: TargetSelection, } @@ -3465,7 +3598,7 @@ impl Step for CodegenCranelift { fn make_run(run: RunConfig<'_>) { let builder = run.builder; let host = run.build_triple(); - let compiler = run.builder.compiler_for(run.builder.top_stage, host, host); + let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, host); if builder.doc_tests == DocTests::Only { return; @@ -3495,71 +3628,50 @@ impl Step for CodegenCranelift { return; } - builder.ensure(CodegenCranelift { compiler, target: run.target }); + builder.ensure(CodegenCranelift { compilers, target: run.target }); } fn run(self, builder: &Builder<'_>) { - let compiler = self.compiler; - let target = self.target; - - builder.std(compiler, target); + let compilers = self.compilers; + let build_compiler = compilers.build_compiler(); - // If we're not doing a full bootstrap but we're testing a stage2 - // version of libstd, then what we're actually testing is the libstd - // produced in stage1. Reflect that here by updating the compiler that - // we're working with automatically. - let compiler = builder.compiler_for(compiler.stage, compiler.host, target); + // We need to run the cranelift tests with the compiler against cranelift links to, not with + // the build compiler. + let target_compiler = compilers.target_compiler(); + let target = self.target; - let build_cargo = || { - let mut cargo = builder::Cargo::new( - builder, - compiler, - Mode::Codegen, // Must be codegen to ensure dlopen on compiled dylibs works - SourceType::InTree, - target, - Kind::Run, - ); + builder.std(target_compiler, target); - cargo.current_dir(&builder.src.join("compiler/rustc_codegen_cranelift")); - cargo - .arg("--manifest-path") - .arg(builder.src.join("compiler/rustc_codegen_cranelift/build_system/Cargo.toml")); - compile::rustc_cargo_env(builder, &mut cargo, target); + let mut cargo = builder::Cargo::new( + builder, + target_compiler, + Mode::Codegen, // Must be codegen to ensure dlopen on compiled dylibs works + SourceType::InTree, + target, + Kind::Run, + ); - // Avoid incremental cache issues when changing rustc - cargo.env("CARGO_BUILD_INCREMENTAL", "false"); + cargo.current_dir(&builder.src.join("compiler/rustc_codegen_cranelift")); + cargo + .arg("--manifest-path") + .arg(builder.src.join("compiler/rustc_codegen_cranelift/build_system/Cargo.toml")); + compile::rustc_cargo_env(builder, &mut cargo, target); - cargo - }; + // Avoid incremental cache issues when changing rustc + cargo.env("CARGO_BUILD_INCREMENTAL", "false"); - builder.info(&format!( - "{} cranelift stage{} ({} -> {})", - Kind::Test.description(), - compiler.stage, - &compiler.host, - target - )); - let _time = helpers::timeit(builder); + let _guard = builder.msg_test("rustc_codegen_cranelift", target_compiler); // FIXME handle vendoring for source tarballs before removing the --skip-test below let download_dir = builder.out.join("cg_clif_download"); - // FIXME: Uncomment the `prepare` command below once vendoring is implemented. - /* - let mut prepare_cargo = build_cargo(); - prepare_cargo.arg("--").arg("prepare").arg("--download-dir").arg(&download_dir); - #[expect(deprecated)] - builder.config.try_run(&mut prepare_cargo.into()).unwrap(); - */ - - let mut cargo = build_cargo(); cargo .arg("--") .arg("test") .arg("--download-dir") .arg(&download_dir) .arg("--out-dir") - .arg(builder.stage_out(compiler, Mode::ToolRustc).join("cg_clif")) + .arg(builder.stage_out(build_compiler, Mode::Codegen).join("cg_clif")) .arg("--no-unstable-features") .arg("--use-backend") .arg("cranelift") @@ -3573,11 +3685,18 @@ impl Step for CodegenCranelift { cargo.into_cmd().run(builder); } + + fn metadata(&self) -> Option<StepMetadata> { + Some( + StepMetadata::test("rustc_codegen_cranelift", self.target) + .built_by(self.compilers.build_compiler()), + ) + } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CodegenGCC { - compiler: Compiler, + compilers: RustcPrivateCompilers, target: TargetSelection, } @@ -3593,7 +3712,7 @@ impl Step for CodegenGCC { fn make_run(run: RunConfig<'_>) { let builder = run.builder; let host = run.build_triple(); - let compiler = run.builder.compiler_for(run.builder.top_stage, host, host); + let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, host); if builder.doc_tests == DocTests::Only { return; @@ -3622,68 +3741,41 @@ impl Step for CodegenGCC { return; } - builder.ensure(CodegenGCC { compiler, target: run.target }); + builder.ensure(CodegenGCC { compilers, target: run.target }); } fn run(self, builder: &Builder<'_>) { - let compiler = self.compiler; + let compilers = self.compilers; let target = self.target; let gcc = builder.ensure(Gcc { target }); builder.ensure( - compile::Std::new(compiler, target) + compile::Std::new(compilers.build_compiler(), target) .extra_rust_args(&["-Csymbol-mangling-version=v0", "-Cpanic=abort"]), ); - // If we're not doing a full bootstrap but we're testing a stage2 - // version of libstd, then what we're actually testing is the libstd - // produced in stage1. Reflect that here by updating the compiler that - // we're working with automatically. - let compiler = builder.compiler_for(compiler.stage, compiler.host, target); + let _guard = builder.msg_test("rustc_codegen_gcc", compilers.build_compiler()); - let build_cargo = || { - let mut cargo = builder::Cargo::new( - builder, - compiler, - Mode::Codegen, // Must be codegen to ensure dlopen on compiled dylibs works - SourceType::InTree, - target, - Kind::Run, - ); - - cargo.current_dir(&builder.src.join("compiler/rustc_codegen_gcc")); - cargo - .arg("--manifest-path") - .arg(builder.src.join("compiler/rustc_codegen_gcc/build_system/Cargo.toml")); - compile::rustc_cargo_env(builder, &mut cargo, target); - add_cg_gcc_cargo_flags(&mut cargo, &gcc); - - // Avoid incremental cache issues when changing rustc - cargo.env("CARGO_BUILD_INCREMENTAL", "false"); - cargo.rustflag("-Cpanic=abort"); - - cargo - }; - - builder.info(&format!( - "{} GCC stage{} ({} -> {})", - Kind::Test.description(), - compiler.stage, - &compiler.host, - target - )); - let _time = helpers::timeit(builder); + let mut cargo = builder::Cargo::new( + builder, + compilers.build_compiler(), + Mode::Codegen, // Must be codegen to ensure dlopen on compiled dylibs works + SourceType::InTree, + target, + Kind::Run, + ); - // FIXME: Uncomment the `prepare` command below once vendoring is implemented. - /* - let mut prepare_cargo = build_cargo(); - prepare_cargo.arg("--").arg("prepare"); - #[expect(deprecated)] - builder.config.try_run(&mut prepare_cargo.into()).unwrap(); - */ + cargo.current_dir(&builder.src.join("compiler/rustc_codegen_gcc")); + cargo + .arg("--manifest-path") + .arg(builder.src.join("compiler/rustc_codegen_gcc/build_system/Cargo.toml")); + compile::rustc_cargo_env(builder, &mut cargo, target); + add_cg_gcc_cargo_flags(&mut cargo, &gcc); - let mut cargo = build_cargo(); + // Avoid incremental cache issues when changing rustc + cargo.env("CARGO_BUILD_INCREMENTAL", "false"); + cargo.rustflag("-Cpanic=abort"); cargo // cg_gcc's build system ignores RUSTFLAGS. pass some flags through CG_RUSTFLAGS instead. @@ -3695,7 +3787,7 @@ impl Step for CodegenGCC { .arg("--gcc-path") .arg(gcc.libgccjit.parent().unwrap()) .arg("--out-dir") - .arg(builder.stage_out(compiler, Mode::ToolRustc).join("cg_gcc")) + .arg(builder.stage_out(compilers.build_compiler(), Mode::Codegen).join("cg_gcc")) .arg("--release") .arg("--mini-tests") .arg("--std-tests"); @@ -3703,6 +3795,13 @@ impl Step for CodegenGCC { cargo.into_cmd().run(builder); } + + fn metadata(&self) -> Option<StepMetadata> { + Some( + StepMetadata::test("rustc_codegen_gcc", self.target) + .built_by(self.compilers.build_compiler()), + ) + } } /// Test step that does two things: @@ -3711,8 +3810,17 @@ impl Step for CodegenGCC { /// float parsing routines. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct TestFloatParse { - path: PathBuf, - host: TargetSelection, + /// The build compiler which will build and run unit tests of `test-float-parse`, and which will + /// build the `test-float-parse` tool itself. + /// + /// Note that the staging is a bit funny here, because this step essentially tests std, but it + /// also needs to build the tool. So if we test stage1 std, we build: + /// 1) stage1 rustc + /// 2) Use that to build stage1 libstd + /// 3) Use that to build and run *stage2* test-float-parse + build_compiler: Compiler, + /// Target for which we build std and test that std. + target: TargetSelection, } impl Step for TestFloatParse { @@ -3725,47 +3833,47 @@ impl Step for TestFloatParse { } fn make_run(run: RunConfig<'_>) { - for path in run.paths { - let path = path.assert_single_path().path.clone(); - run.builder.ensure(Self { path, host: run.target }); - } + run.builder.ensure(Self { + build_compiler: get_compiler_to_test(run.builder, run.target), + target: run.target, + }); } fn run(self, builder: &Builder<'_>) { - let bootstrap_host = builder.config.host_target; - let compiler = builder.compiler(builder.top_stage, bootstrap_host); - let path = self.path.to_str().unwrap(); - let crate_name = self.path.iter().next_back().unwrap().to_str().unwrap(); + let build_compiler = self.build_compiler; + let target = self.target; - builder.ensure(tool::TestFloatParse { host: self.host }); + // Build the standard library that will be tested, and a stdlib for host code + builder.std(build_compiler, target); + builder.std(build_compiler, builder.host_target); // Run any unit tests in the crate let mut cargo_test = tool::prepare_tool_cargo( builder, - compiler, + build_compiler, Mode::ToolStd, - bootstrap_host, + target, Kind::Test, - path, + "src/tools/test-float-parse", SourceType::InTree, &[], ); - cargo_test.allow_features(tool::TestFloatParse::ALLOW_FEATURES); + cargo_test.allow_features(TEST_FLOAT_PARSE_ALLOW_FEATURES); - run_cargo_test(cargo_test, &[], &[], crate_name, bootstrap_host, builder); + run_cargo_test(cargo_test, &[], &[], "test-float-parse", target, builder, Mode::ToolStd); // Run the actual parse tests. let mut cargo_run = tool::prepare_tool_cargo( builder, - compiler, + build_compiler, Mode::ToolStd, - bootstrap_host, + target, Kind::Run, - path, + "src/tools/test-float-parse", SourceType::InTree, &[], ); - cargo_run.allow_features(tool::TestFloatParse::ALLOW_FEATURES); + cargo_run.allow_features(TEST_FLOAT_PARSE_ALLOW_FEATURES); if !matches!(env::var("FLOAT_PARSE_TESTS_NO_SKIP_HUGE").as_deref(), Ok("1") | Ok("true")) { cargo_run.args(["--", "--skip-huge"]); diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index b62c9a906b7..65c4c499086 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1539,42 +1539,7 @@ tool_rustc_extended!(Rustfmt { add_bins_to_sysroot: ["rustfmt"] }); -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct TestFloatParse { - pub host: TargetSelection, -} - -impl TestFloatParse { - pub const ALLOW_FEATURES: &'static str = "f16,cfg_target_has_reliable_f16_f128"; -} - -impl Step for TestFloatParse { - type Output = ToolBuildResult; - const IS_HOST: bool = true; - const DEFAULT: bool = false; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/tools/test-float-parse") - } - - fn run(self, builder: &Builder<'_>) -> ToolBuildResult { - let bootstrap_host = builder.config.host_target; - let compiler = builder.compiler(builder.top_stage, bootstrap_host); - - builder.ensure(ToolBuild { - build_compiler: compiler, - target: bootstrap_host, - tool: "test-float-parse", - mode: Mode::ToolStd, - path: "src/tools/test-float-parse", - source_type: SourceType::InTree, - extra_features: Vec::new(), - allow_features: Self::ALLOW_FEATURES, - cargo_args: Vec::new(), - artifact_kind: ToolArtifactKind::Binary, - }) - } -} +pub const TEST_FLOAT_PARSE_ALLOW_FEATURES: &str = "f16,cfg_target_has_reliable_f16_f128"; impl Builder<'_> { /// Gets a `BootstrapCommand` which is ready to run `tool` in `stage` built for diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index b224a7e7322..627085df812 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -295,7 +295,7 @@ pub fn crate_description(crates: &[impl AsRef<str>]) -> String { return "".into(); } - let mut descr = String::from(" {"); + let mut descr = String::from("{"); descr.push_str(crates[0].as_ref()); for krate in &crates[1..] { descr.push_str(", "); diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index b079117c5a7..43e67756e74 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2037,6 +2037,212 @@ mod snapshot { .render_steps(), @"[check] rustc 0 <host> -> RunMakeSupport 1 <host>"); } + fn prepare_test_config(ctx: &TestCtx) -> ConfigBuilder { + ctx.config("test") + // Bootstrap only runs by default on CI, so we have to emulate that also locally. + .args(&["--ci", "true"]) + // These rustdoc tests requires nodejs to be present. + // We can't easily opt out of it, so if it is present on the local PC, the test + // would have different result on CI, where nodejs might be missing. + .args(&["--skip", "rustdoc-js-std"]) + .args(&["--skip", "rustdoc-js"]) + .args(&["--skip", "rustdoc-gui"]) + } + + #[test] + fn test_all_stage_1() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + prepare_test_config(&ctx) + .render_steps(), @r" + [build] rustc 0 <host> -> Tidy 1 <host> + [test] tidy <> + [build] rustdoc 0 <host> + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [build] rustc 0 <host> -> Compiletest 1 <host> + [test] Ui <host> + [test] Crashes <host> + [build] rustc 0 <host> -> CoverageDump 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [test] CodegenLlvm <host> + [test] CodegenUnits <host> + [test] AssemblyLlvm <host> + [test] Incremental <host> + [test] Debuginfo <host> + [test] UiFullDeps <host> + [build] rustdoc 1 <host> + [test] Rustdoc <host> + [test] CoverageRunRustdoc <host> + [test] Pretty <host> + [build] rustc 1 <host> -> std 1 <host> + [build] rustc 0 <host> -> std 0 <host> + [test] rustc 0 <host> -> CrateLibrustc 1 <host> + [build] rustc 1 <host> -> rustc 2 <host> + [test] crate-bootstrap <host> src/tools/coverage-dump + [test] crate-bootstrap <host> src/tools/jsondoclint + [test] crate-bootstrap <host> src/tools/replace-version-placeholder + [test] crate-bootstrap <host> tidyselftest + [build] rustc 0 <host> -> UnstableBookGen 1 <host> + [build] rustc 0 <host> -> Rustbook 1 <host> + [doc] unstable-book (book) <host> + [doc] book (book) <host> + [doc] book/first-edition (book) <host> + [doc] book/second-edition (book) <host> + [doc] book/2018-edition (book) <host> + [doc] rustc 0 <host> -> standalone 1 <host> + [doc] rustc 1 <host> -> std 1 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] rustc 0 <host> -> error-index 1 <host> + [doc] rustc 0 <host> -> error-index 1 <host> + [doc] nomicon (book) <host> + [doc] rustc 1 <host> -> reference (book) 2 <host> + [doc] rustdoc (book) <host> + [doc] rust-by-example (book) <host> + [build] rustc 0 <host> -> LintDocs 1 <host> + [doc] rustc (book) <host> + [doc] cargo (book) <host> + [doc] clippy (book) <host> + [doc] embedded-book (book) <host> + [doc] edition-guide (book) <host> + [doc] style-guide (book) <host> + [doc] rustc 0 <host> -> releases 1 <host> + [build] rustc 0 <host> -> Linkchecker 1 <host> + [test] link-check <host> + [test] tier-check <host> + [test] rustc 0 <host> -> rust-analyzer 1 <host> + [build] rustc 0 <host> -> RustdocTheme 1 <host> + [test] rustdoc-theme 1 <host> + [test] RustdocUi <host> + [build] rustc 0 <host> -> JsonDocCk 1 <host> + [build] rustc 0 <host> -> JsonDocLint 1 <host> + [test] RustdocJson <host> + [doc] rustc 0 <host> -> rustc 1 <host> + [build] rustc 0 <host> -> HtmlChecker 1 <host> + [test] html-check <host> + [build] rustc 0 <host> -> RunMakeSupport 1 <host> + [build] rustc 1 <host> -> cargo 2 <host> + [test] RunMake <host> + "); + } + + #[test] + fn test_all_stage_2() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + prepare_test_config(&ctx) + .stage(2) + .render_steps(), @r" + [build] rustc 0 <host> -> Tidy 1 <host> + [test] tidy <> + [build] rustdoc 0 <host> + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [build] rustc 1 <host> -> rustc 2 <host> + [build] rustc 2 <host> -> std 2 <host> + [build] rustc 0 <host> -> Compiletest 1 <host> + [test] Ui <host> + [test] Crashes <host> + [build] rustc 0 <host> -> CoverageDump 1 <host> + [build] rustc 2 <host> -> std 2 <host> + [test] CodegenLlvm <host> + [test] CodegenUnits <host> + [test] AssemblyLlvm <host> + [test] Incremental <host> + [test] Debuginfo <host> + [build] rustc 2 <host> -> rustc 3 <host> + [test] UiFullDeps <host> + [build] rustdoc 2 <host> + [test] Rustdoc <host> + [test] CoverageRunRustdoc <host> + [test] Pretty <host> + [build] rustc 2 <host> -> std 2 <host> + [build] rustc 1 <host> -> std 1 <host> + [build] rustdoc 1 <host> + [test] rustc 1 <host> -> CrateLibrustc 2 <host> + [test] crate-bootstrap <host> src/tools/coverage-dump + [test] crate-bootstrap <host> src/tools/jsondoclint + [test] crate-bootstrap <host> src/tools/replace-version-placeholder + [test] crate-bootstrap <host> tidyselftest + [build] rustc 0 <host> -> UnstableBookGen 1 <host> + [build] rustc 0 <host> -> Rustbook 1 <host> + [doc] unstable-book (book) <host> + [doc] book (book) <host> + [doc] book/first-edition (book) <host> + [doc] book/second-edition (book) <host> + [doc] book/2018-edition (book) <host> + [doc] rustc 1 <host> -> standalone 2 <host> + [doc] rustc 1 <host> -> std 1 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] rustc 1 <host> -> error-index 2 <host> + [doc] rustc 1 <host> -> error-index 2 <host> + [doc] nomicon (book) <host> + [doc] rustc 1 <host> -> reference (book) 2 <host> + [doc] rustdoc (book) <host> + [doc] rust-by-example (book) <host> + [build] rustc 0 <host> -> LintDocs 1 <host> + [doc] rustc (book) <host> + [doc] cargo (book) <host> + [doc] clippy (book) <host> + [doc] embedded-book (book) <host> + [doc] edition-guide (book) <host> + [doc] style-guide (book) <host> + [doc] rustc 1 <host> -> releases 2 <host> + [build] rustc 0 <host> -> Linkchecker 1 <host> + [test] link-check <host> + [test] tier-check <host> + [test] rustc 1 <host> -> rust-analyzer 2 <host> + [doc] rustc (book) <host> + [test] rustc 1 <host> -> lint-docs 2 <host> + [build] rustc 0 <host> -> RustdocTheme 1 <host> + [test] rustdoc-theme 2 <host> + [test] RustdocUi <host> + [build] rustc 0 <host> -> JsonDocCk 1 <host> + [build] rustc 0 <host> -> JsonDocLint 1 <host> + [test] RustdocJson <host> + [doc] rustc 1 <host> -> rustc 2 <host> + [build] rustc 0 <host> -> HtmlChecker 1 <host> + [test] html-check <host> + [build] rustc 0 <host> -> RunMakeSupport 1 <host> + [build] rustc 2 <host> -> cargo 3 <host> + [test] RunMake <host> + "); + } + + #[test] + fn test_compiler_stage_1() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("test") + .path("compiler") + .stage(1) + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 0 <host> -> std 0 <host> + [build] rustdoc 0 <host> + [test] rustc 0 <host> -> CrateLibrustc 1 <host> + "); + } + + #[test] + fn test_compiler_stage_2() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("test") + .path("compiler") + .stage(2) + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [build] rustc 1 <host> -> rustc 2 <host> + [build] rustc 1 <host> -> std 1 <host> + [build] rustdoc 1 <host> + [test] rustc 1 <host> -> CrateLibrustc 2 <host> + "); + } + #[test] fn test_exclude() { let ctx = TestCtx::new(); @@ -2054,13 +2260,15 @@ mod snapshot { let get_steps = |args: &[&str]| ctx.config("test").args(args).get_steps(); + let rustc_metadata = + || StepMetadata::test("CrateLibrustc", host).built_by(Compiler::new(0, host)); // Ensure our test is valid, and `test::Rustc` would be run without the exclude. - get_steps(&[]).assert_contains(StepMetadata::test("CrateLibrustc", host)); + get_steps(&[]).assert_contains(rustc_metadata()); let steps = get_steps(&["--skip", "compiler/rustc_data_structures"]); // Ensure tests for rustc are not skipped. - steps.assert_contains(StepMetadata::test("CrateLibrustc", host)); + steps.assert_contains(rustc_metadata()); steps.assert_contains_fuzzy(StepMetadata::build("rustc", host)); } @@ -2077,6 +2285,7 @@ mod snapshot { [build] rustc 1 <host> -> std 1 <host> [build] rustdoc 1 <host> [build] rustdoc 0 <host> + [test] rustc 0 <host> -> cargo 1 <host> "); } @@ -2096,6 +2305,7 @@ mod snapshot { [build] rustc 2 <host> -> std 2 <host> [build] rustdoc 2 <host> [build] rustdoc 1 <host> + [test] rustc 1 <host> -> cargo 2 <host> "); } @@ -2117,6 +2327,19 @@ mod snapshot { } #[test] + fn test_tier_check() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("test") + .path("tier-check") + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [test] tier-check <host> + "); + } + + #[test] fn doc_all() { let ctx = TestCtx::new(); insta::assert_snapshot!( diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index a8eb563015f..d12cc962187 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1002,13 +1002,17 @@ impl Config { (0, Subcommand::Install) => { check_stage0("install"); } + (0, Subcommand::Test { .. }) if build_compiletest_allow_stage0 != Some(true) => { + eprintln!( + "ERROR: cannot test anything on stage 0. Use at least stage 1. If you want to run compiletest with an external stage0 toolchain, enable `build.compiletest-allow-stage0`." + ); + exit!(1); + } _ => {} } if flags_compile_time_deps && !matches!(flags_cmd, Subcommand::Check { .. }) { - eprintln!( - "WARNING: Can't use --compile-time-deps with any subcommand other than check." - ); + eprintln!("ERROR: Can't use --compile-time-deps with any subcommand other than check."); exit!(1); } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index b8ee83b20e4..9a882eae08e 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1144,14 +1144,18 @@ impl Build { }; let action = action.into().description(); - let msg = |fmt| format!("{action} stage{actual_stage} {what}{fmt}"); + let what = what.to_string(); + let msg = |fmt| { + let space = if !what.is_empty() { " " } else { "" }; + format!("{action} stage{actual_stage} {what}{space}{fmt}") + }; let msg = if let Some(target) = target.into() { let build_stage = host_and_stage.stage; let host = host_and_stage.host; if host == target { - msg(format_args!(" (stage{build_stage} -> stage{actual_stage}, {target})")) + msg(format_args!("(stage{build_stage} -> stage{actual_stage}, {target})")) } else { - msg(format_args!(" (stage{build_stage}:{host} -> stage{actual_stage}:{target})")) + msg(format_args!("(stage{build_stage}:{host} -> stage{actual_stage}:{target})")) } } else { msg(format_args!("")) @@ -1159,6 +1163,25 @@ impl Build { self.group(&msg) } + /// Return a `Group` guard for a [`Step`] that tests `what` with the given `stage` and `target` + /// (determined by `host_and_stage`). + /// Use this instead of [`Build::msg`] when there is no clear `build_compiler` to be + /// determined. + /// + /// [`Step`]: crate::core::builder::Step + #[must_use = "Groups should not be dropped until the Step finishes running"] + #[track_caller] + fn msg_test( + &self, + what: impl Display, + host_and_stage: impl Into<HostAndStage>, + ) -> Option<gha::Group> { + let HostAndStage { host, stage } = host_and_stage.into(); + let action = Kind::Test.description(); + let msg = format!("{action} stage{stage} {what} ({host})"); + self.group(&msg) + } + /// Return a `Group` guard for a [`Step`] that is only built once and isn't affected by `--stage`. /// /// [`Step`]: crate::core::builder::Step diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 606d88d3db4..2cc2fb486fa 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -531,4 +531,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "It is now possible to `check/build/dist` the standard stage 0 library if you use a stage0 rustc built from in-tree sources. This is useful for quickly cross-compiling the standard library. You have to enable build.local-rebuild for this to work.", }, + ChangeInfo { + change_id: 145663, + severity: ChangeSeverity::Warning, + summary: "It is no longer possible to `x test` with stage 0, except for running compiletest and opting into `build.compiletest-allow-stage0`.", + }, ]; diff --git a/src/ci/docker/host-x86_64/tidy/Dockerfile b/src/ci/docker/host-x86_64/tidy/Dockerfile index c8558689d3b..2dda51b155e 100644 --- a/src/ci/docker/host-x86_64/tidy/Dockerfile +++ b/src/ci/docker/host-x86_64/tidy/Dockerfile @@ -44,5 +44,5 @@ RUN bash -c 'npm install -g eslint@$(cat /tmp/eslint.version)' # NOTE: intentionally uses python2 for x.py so we can test it still works. # validate-toolstate only runs in our CI, so it's ok for it to only support python3. -ENV SCRIPT TIDY_PRINT_DIFF=1 python2.7 ../x.py test --stage 0 \ +ENV SCRIPT TIDY_PRINT_DIFF=1 python2.7 ../x.py test \ src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck diff --git a/src/doc/unstable-book/src/language-features/extended-varargs-abi-support.md b/src/doc/unstable-book/src/language-features/extended-varargs-abi-support.md deleted file mode 100644 index b20c30ec8f1..00000000000 --- a/src/doc/unstable-book/src/language-features/extended-varargs-abi-support.md +++ /dev/null @@ -1,10 +0,0 @@ -# `extended_varargs_abi_support` - -The tracking issue for this feature is: [#100189] - -[#100189]: https://github.com/rust-lang/rust/issues/100189 - ------------------------- - -This feature adds the possibility of using `sysv64`, `win64` or `efiapi` calling -conventions on functions with varargs. diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 2985971a053..5d36ffc2d3a 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -12,20 +12,20 @@ path = "lib.rs" arrayvec = { version = "0.7", default-features = false } askama = { version = "0.14", default-features = false, features = ["alloc", "config", "derive"] } base64 = "0.21.7" -indexmap.workspace = true -itertools.workspace = true +indexmap = "2" +itertools = "0.12" minifier = { version = "0.3.5", default-features = false } pulldown-cmark-escape = { version = "0.11.0", features = ["simd"] } regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } serde = { version = "1.0", features = ["derive"] } -serde_json.workspace = true +serde_json = "1.0" smallvec = "1.8.1" stringdex = { version = "0.0.1-alpha4" } -tempfile.workspace = true +tempfile = "3" threadpool = "1.8.1" +tracing = "0.1" tracing-tree = "0.3.0" -tracing.workspace = true unicode-segmentation = "1.9" # tidy-alphabetical-end diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index dddc087d124..2984f3ab50e 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -289,8 +289,26 @@ impl SerializedSearchIndex { (Some(self_type_data), None) => Some(self_type_data), (None, Some(other_type_data)) => Some(TypeData { search_unbox: other_type_data.search_unbox, - inverted_function_signature_index: other_type_data - .inverted_function_signature_index + inverted_function_inputs_index: other_type_data + .inverted_function_inputs_index + .iter() + .cloned() + .map(|mut list: Vec<u32>| { + for fnid in &mut list { + assert!( + other.function_data + [usize::try_from(*fnid).unwrap()] + .is_some(), + ); + // this is valid because we call `self.push()` once, exactly, for every entry, + // even if we're just pushing a tombstone + *fnid += u32::try_from(other_entryid_offset).unwrap(); + } + list + }) + .collect(), + inverted_function_output_index: other_type_data + .inverted_function_output_index .iter() .cloned() .map(|mut list: Vec<u32>| { @@ -310,18 +328,42 @@ impl SerializedSearchIndex { }), (Some(mut self_type_data), Some(other_type_data)) => { for (size, other_list) in other_type_data - .inverted_function_signature_index + .inverted_function_inputs_index + .iter() + .enumerate() + { + while self_type_data.inverted_function_inputs_index.len() + <= size + { + self_type_data + .inverted_function_inputs_index + .push(Vec::new()); + } + self_type_data.inverted_function_inputs_index[size].extend( + other_list.iter().copied().map(|fnid| { + assert!( + other.function_data[usize::try_from(fnid).unwrap()] + .is_some(), + ); + // this is valid because we call `self.push()` once, exactly, for every entry, + // even if we're just pushing a tombstone + fnid + u32::try_from(other_entryid_offset).unwrap() + }), + ) + } + for (size, other_list) in other_type_data + .inverted_function_output_index .iter() .enumerate() { - while self_type_data.inverted_function_signature_index.len() + while self_type_data.inverted_function_output_index.len() <= size { self_type_data - .inverted_function_signature_index + .inverted_function_output_index .push(Vec::new()); } - self_type_data.inverted_function_signature_index[size].extend( + self_type_data.inverted_function_output_index[size].extend( other_list.iter().copied().map(|fnid| { assert!( other.function_data[usize::try_from(fnid).unwrap()] @@ -443,8 +485,25 @@ impl SerializedSearchIndex { param_names: function_data.param_names.clone(), }), other.type_data[other_entryid].as_ref().map(|type_data| TypeData { - inverted_function_signature_index: type_data - .inverted_function_signature_index + inverted_function_inputs_index: type_data + .inverted_function_inputs_index + .iter() + .cloned() + .map(|mut list| { + for fnid in &mut list { + assert!( + other.function_data[usize::try_from(*fnid).unwrap()] + .is_some(), + ); + // this is valid because we call `self.push()` once, exactly, for every entry, + // even if we're just pushing a tombstone + *fnid += u32::try_from(other_entryid_offset).unwrap(); + } + list + }) + .collect(), + inverted_function_output_index: type_data + .inverted_function_output_index .iter() .cloned() .map(|mut list| { @@ -599,9 +658,13 @@ impl SerializedSearchIndex { }, ), self.type_data[id].as_ref().map( - |TypeData { search_unbox, inverted_function_signature_index }| { - let inverted_function_signature_index: Vec<Vec<u32>> = - inverted_function_signature_index + |TypeData { + search_unbox, + inverted_function_inputs_index, + inverted_function_output_index, + }| { + let inverted_function_inputs_index: Vec<Vec<u32>> = + inverted_function_inputs_index .iter() .cloned() .map(|mut list| { @@ -615,7 +678,26 @@ impl SerializedSearchIndex { list }) .collect(); - TypeData { search_unbox: *search_unbox, inverted_function_signature_index } + let inverted_function_output_index: Vec<Vec<u32>> = + inverted_function_output_index + .iter() + .cloned() + .map(|mut list| { + for id in &mut list { + *id = u32::try_from( + *map.get(&usize::try_from(*id).unwrap()).unwrap(), + ) + .unwrap(); + } + list.sort(); + list + }) + .collect(); + TypeData { + search_unbox: *search_unbox, + inverted_function_inputs_index, + inverted_function_output_index, + } }, ), self.alias_pointers[id].and_then(|alias| map.get(&alias).copied()), @@ -934,18 +1016,20 @@ struct TypeData { /// | `Unboxable<Inner>` | yes | no | no | /// | `Inner<Unboxable>` | no | no | yes | search_unbox: bool, - /// List of functions that mention this type in their type signature. + /// List of functions that mention this type in their type signature, + /// on the left side of the `->` arrow. /// - /// - The outermost list has one entry per alpha-normalized generic. - /// - /// - The second layer is sorted by number of types that appear in the + /// - The outer layer is sorted by number of types that appear in the /// type signature. The search engine iterates over these in order from /// smallest to largest. Functions with less stuff in their type /// signature are more likely to be what the user wants, because we never /// show functions that are *missing* parts of the query, so removing.. /// - /// - The final layer is the list of functions. - inverted_function_signature_index: Vec<Vec<u32>>, + /// - The inner layer is the list of functions. + inverted_function_inputs_index: Vec<Vec<u32>>, + /// List of functions that mention this type in their type signature, + /// on the right side of the `->` arrow. + inverted_function_output_index: Vec<Vec<u32>>, } impl Serialize for TypeData { @@ -953,15 +1037,21 @@ impl Serialize for TypeData { where S: Serializer, { - if self.search_unbox || !self.inverted_function_signature_index.is_empty() { + if self.search_unbox + || !self.inverted_function_inputs_index.is_empty() + || !self.inverted_function_output_index.is_empty() + { let mut seq = serializer.serialize_seq(None)?; - if !self.inverted_function_signature_index.is_empty() { - let mut buf = Vec::new(); - encode::write_postings_to_string(&self.inverted_function_signature_index, &mut buf); - let mut serialized_result = Vec::new(); - stringdex_internals::encode::write_base64_to_bytes(&buf, &mut serialized_result); - seq.serialize_element(&String::from_utf8(serialized_result).unwrap())?; - } + let mut buf = Vec::new(); + encode::write_postings_to_string(&self.inverted_function_inputs_index, &mut buf); + let mut serialized_result = Vec::new(); + stringdex_internals::encode::write_base64_to_bytes(&buf, &mut serialized_result); + seq.serialize_element(&str::from_utf8(&serialized_result).unwrap())?; + buf.clear(); + serialized_result.clear(); + encode::write_postings_to_string(&self.inverted_function_output_index, &mut buf); + stringdex_internals::encode::write_base64_to_bytes(&buf, &mut serialized_result); + seq.serialize_element(&str::from_utf8(&serialized_result).unwrap())?; if self.search_unbox { seq.serialize_element(&1)?; } @@ -984,21 +1074,39 @@ impl<'de> Deserialize<'de> for TypeData { write!(formatter, "type data") } fn visit_none<E>(self) -> Result<TypeData, E> { - Ok(TypeData { inverted_function_signature_index: vec![], search_unbox: false }) + Ok(TypeData { + inverted_function_inputs_index: vec![], + inverted_function_output_index: vec![], + search_unbox: false, + }) } fn visit_seq<A: de::SeqAccess<'de>>(self, mut v: A) -> Result<TypeData, A::Error> { - let inverted_function_signature_index: String = + let inverted_function_inputs_index: String = + v.next_element()?.unwrap_or(String::new()); + let inverted_function_output_index: String = v.next_element()?.unwrap_or(String::new()); let search_unbox: u32 = v.next_element()?.unwrap_or(0); let mut idx: Vec<u8> = Vec::new(); stringdex_internals::decode::read_base64_from_bytes( - inverted_function_signature_index.as_bytes(), + inverted_function_inputs_index.as_bytes(), &mut idx, ) .unwrap(); - let mut inverted_function_signature_index = Vec::new(); - encode::read_postings_from_string(&mut inverted_function_signature_index, &idx); - Ok(TypeData { inverted_function_signature_index, search_unbox: search_unbox == 1 }) + let mut inverted_function_inputs_index = Vec::new(); + encode::read_postings_from_string(&mut inverted_function_inputs_index, &idx); + idx.clear(); + stringdex_internals::decode::read_base64_from_bytes( + inverted_function_output_index.as_bytes(), + &mut idx, + ) + .unwrap(); + let mut inverted_function_output_index = Vec::new(); + encode::read_postings_from_string(&mut inverted_function_output_index, &idx); + Ok(TypeData { + inverted_function_inputs_index, + inverted_function_output_index, + search_unbox: search_unbox == 1, + }) } } deserializer.deserialize_any(TypeDataVisitor) @@ -1222,8 +1330,16 @@ pub(crate) fn build_index( let index = *index.get(); serialized_index.descs[index] = crate_doc; for type_data in serialized_index.type_data.iter_mut() { - if let Some(TypeData { inverted_function_signature_index, .. }) = type_data { - for list in &mut inverted_function_signature_index[..] { + if let Some(TypeData { + inverted_function_inputs_index, + inverted_function_output_index, + .. + }) = type_data + { + for list in inverted_function_inputs_index + .iter_mut() + .chain(inverted_function_output_index.iter_mut()) + { list.retain(|fnid| { serialized_index.entry_data[usize::try_from(*fnid).unwrap()] .as_ref() @@ -1449,7 +1565,8 @@ pub(crate) fn build_index( if serialized_index.type_data[id].as_mut().is_none() { serialized_index.type_data[id] = Some(TypeData { search_unbox, - inverted_function_signature_index: Vec::new(), + inverted_function_inputs_index: Vec::new(), + inverted_function_output_index: Vec::new(), }); } else if search_unbox { serialized_index.type_data[id].as_mut().unwrap().search_unbox = true; @@ -1473,7 +1590,11 @@ pub(crate) fn build_index( None }, }, - TypeData { search_unbox, inverted_function_signature_index: Vec::new() }, + TypeData { + inverted_function_inputs_index: Vec::new(), + inverted_function_output_index: Vec::new(), + search_unbox, + }, ); pathid } @@ -1695,13 +1816,14 @@ pub(crate) fn build_index( } } if let Some(search_type) = &mut item.search_type { - let mut used_in_function_signature = BTreeSet::new(); + let mut used_in_function_inputs = BTreeSet::new(); + let mut used_in_function_output = BTreeSet::new(); for item in &mut search_type.inputs { convert_render_type( item, cache, &mut serialized_index, - &mut used_in_function_signature, + &mut used_in_function_inputs, tcx, ); } @@ -1710,20 +1832,44 @@ pub(crate) fn build_index( item, cache, &mut serialized_index, - &mut used_in_function_signature, + &mut used_in_function_output, tcx, ); } + let mut used_in_constraints = Vec::new(); for constraint in &mut search_type.where_clause { + let mut used_in_constraint = BTreeSet::new(); for trait_ in &mut constraint[..] { convert_render_type( trait_, cache, &mut serialized_index, - &mut used_in_function_signature, + &mut used_in_constraint, tcx, ); } + used_in_constraints.push(used_in_constraint); + } + loop { + let mut inserted_any = false; + for (i, used_in_constraint) in used_in_constraints.iter().enumerate() { + let id = !(i as isize); + if used_in_function_inputs.contains(&id) + && !used_in_function_inputs.is_superset(&used_in_constraint) + { + used_in_function_inputs.extend(used_in_constraint.iter().copied()); + inserted_any = true; + } + if used_in_function_output.contains(&id) + && !used_in_function_output.is_superset(&used_in_constraint) + { + used_in_function_output.extend(used_in_constraint.iter().copied()); + inserted_any = true; + } + } + if !inserted_any { + break; + } } let search_type_size = search_type.size() + // Artificially give struct fields a size of 8 instead of their real @@ -1746,13 +1892,34 @@ pub(crate) fn build_index( .map(|sym| sym.map(|sym| sym.to_string()).unwrap_or(String::new())) .collect::<Vec<String>>(), }); - for index in used_in_function_signature { + for index in used_in_function_inputs { + let postings = if index >= 0 { + assert!(serialized_index.path_data[index as usize].is_some()); + &mut serialized_index.type_data[index as usize] + .as_mut() + .unwrap() + .inverted_function_inputs_index + } else { + let generic_id = usize::try_from(-index).unwrap() - 1; + for _ in serialized_index.generic_inverted_index.len()..=generic_id { + serialized_index.generic_inverted_index.push(Vec::new()); + } + &mut serialized_index.generic_inverted_index[generic_id] + }; + while postings.len() <= search_type_size { + postings.push(Vec::new()); + } + if postings[search_type_size].last() != Some(&(new_entry_id as u32)) { + postings[search_type_size].push(new_entry_id as u32); + } + } + for index in used_in_function_output { let postings = if index >= 0 { assert!(serialized_index.path_data[index as usize].is_some()); &mut serialized_index.type_data[index as usize] .as_mut() .unwrap() - .inverted_function_signature_index + .inverted_function_output_index } else { let generic_id = usize::try_from(-index).unwrap() - 1; for _ in serialized_index.generic_inverted_index.len()..=generic_id { @@ -1763,7 +1930,9 @@ pub(crate) fn build_index( while postings.len() <= search_type_size { postings.push(Vec::new()); } - postings[search_type_size].push(new_entry_id as u32); + if postings[search_type_size].last() != Some(&(new_entry_id as u32)) { + postings[search_type_size].push(new_entry_id as u32); + } } } } diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index 3ac10742e41..74f646008eb 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -270,9 +270,12 @@ declare namespace rustdoc { */ interface TypeData { searchUnbox: boolean, - invertedFunctionSignatureIndex: RoaringBitmap[], + invertedFunctionInputsIndex: RoaringBitmap[], + invertedFunctionOutputIndex: RoaringBitmap[], } + type TypeInvertedIndexPolarity = "invertedFunctionInputsIndex" | "invertedFunctionOutputIndex"; + /** * A search entry of some sort. */ diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index b003bcc7bf9..fa812a2b67b 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1696,7 +1696,7 @@ class DocSearch { } /** * function_signature, param_names - * @type {[string, number] | [number] | [string] | [] | null} + * @type {[string, string, number] | [string, string] | [] | null} */ const raw = JSON.parse(encoded); @@ -1705,32 +1705,46 @@ class DocSearch { } let searchUnbox = false; - const invertedFunctionSignatureIndex = []; + const invertedFunctionInputsIndex = []; + const invertedFunctionOutputIndex = []; if (typeof raw[0] === "string") { - if (raw[1]) { + if (raw[2]) { searchUnbox = true; } // the inverted function signature index is a list of bitmaps, // by number of types that appear in the function let i = 0; - const pb = makeUint8ArrayFromBase64(raw[0]); - const l = pb.length; + let pb = makeUint8ArrayFromBase64(raw[0]); + let l = pb.length; while (i < l) { if (pb[i] === 0) { - invertedFunctionSignatureIndex.push(RoaringBitmap.empty()); + invertedFunctionInputsIndex.push(RoaringBitmap.empty()); i += 1; } else { const bitmap = new RoaringBitmap(pb, i); i += bitmap.consumed_len_bytes; - invertedFunctionSignatureIndex.push(bitmap); + invertedFunctionInputsIndex.push(bitmap); + } + } + i = 0; + pb = makeUint8ArrayFromBase64(raw[1]); + l = pb.length; + while (i < l) { + if (pb[i] === 0) { + invertedFunctionOutputIndex.push(RoaringBitmap.empty()); + i += 1; + } else { + const bitmap = new RoaringBitmap(pb, i); + i += bitmap.consumed_len_bytes; + invertedFunctionOutputIndex.push(bitmap); } } } else if (raw[0]) { searchUnbox = true; } - return { searchUnbox, invertedFunctionSignatureIndex }; + return { searchUnbox, invertedFunctionInputsIndex, invertedFunctionOutputIndex }; } /** @@ -4009,14 +4023,19 @@ class DocSearch { * or anything else. This function returns all possible permutations. * * @param {rustdoc.ParserQueryElement|null} elem + * @param {rustdoc.TypeInvertedIndexPolarity} polarity * @returns {Promise<PostingsList<rustdoc.QueryElement>[]>} */ - const unpackPostingsList = async elem => { + const unpackPostingsList = async(elem, polarity) => { if (!elem) { return empty_postings_list; } const typeFilter = itemTypeFromName(elem.typeFilter); - const searchResults = await index.search(elem.normalizedPathLast); + const [searchResults, upla, uplb] = await Promise.all([ + index.search(elem.normalizedPathLast), + unpackPostingsListAll(elem.generics, polarity), + unpackPostingsListBindings(elem.bindings, polarity), + ]); /** * @type {Promise<[ * number, @@ -4039,7 +4058,7 @@ class DocSearch { const types = (await Promise.all(typePromises)) .filter(([_id, name, ty, path]) => name !== null && name.toLowerCase() === elem.pathLast && - ty && !ty.invertedFunctionSignatureIndex.every(bitmap => { + ty && !ty[polarity].every(bitmap => { return bitmap.isEmpty(); }) && path && path.ty !== TY_ASSOCTYPE && @@ -4078,7 +4097,7 @@ class DocSearch { this.getPathData(id), ]); if (name !== null && ty !== null && path !== null && - !ty.invertedFunctionSignatureIndex.every(bitmap => { + !ty[polarity].every(bitmap => { return bitmap.isEmpty(); }) && path.ty !== TY_ASSOCTYPE @@ -4176,18 +4195,16 @@ class DocSearch { /** @type {PostingsList<rustdoc.QueryElement>[]} */ const results = []; for (const [id, _name, typeData] of types) { - if (!typeData || typeData.invertedFunctionSignatureIndex.every(bitmap => { + if (!typeData || typeData[polarity].every(bitmap => { return bitmap.isEmpty(); })) { continue; } - const upla = await unpackPostingsListAll(elem.generics); - const uplb = await unpackPostingsListBindings(elem.bindings); for (const {invertedIndex: genericsIdx, queryElem: generics} of upla) { for (const {invertedIndex: bindingsIdx, queryElem: bindings} of uplb) { results.push({ invertedIndex: intersectInvertedIndexes( - typeData.invertedFunctionSignatureIndex, + typeData[polarity], genericsIdx, bindingsIdx, ), @@ -4219,15 +4236,16 @@ class DocSearch { * take the intersection of this bitmap. * * @param {(rustdoc.ParserQueryElement|null)[]|null} elems + * @param {rustdoc.TypeInvertedIndexPolarity} polarity * @returns {Promise<PostingsList<rustdoc.QueryElement[]>[]>} */ - const unpackPostingsListAll = async elems => { + const unpackPostingsListAll = async(elems, polarity) => { if (!elems || elems.length === 0) { return nested_everything_postings_list; } const [firstPostingsList, remainingAll] = await Promise.all([ - unpackPostingsList(elems[0]), - unpackPostingsListAll(elems.slice(1)), + unpackPostingsList(elems[0], polarity), + unpackPostingsListAll(elems.slice(1), polarity), ]); /** @type {PostingsList<rustdoc.QueryElement[]>[]} */ const results = []; @@ -4261,11 +4279,12 @@ class DocSearch { * Before passing an actual parser item to it, make sure to clone the map. * * @param {Map<string, rustdoc.ParserQueryElement[]>} elems + * @param {rustdoc.TypeInvertedIndexPolarity} polarity * @returns {Promise<PostingsList< * Map<number, rustdoc.QueryElement[]>, * >[]>} */ - const unpackPostingsListBindings = async elems => { + const unpackPostingsListBindings = async(elems, polarity) => { if (!elems) { return [{ invertedIndex: everything_inverted_index, @@ -4286,19 +4305,23 @@ class DocSearch { queryElem: new Map(), }]; } - const firstKeyIds = await index.search(firstKey); + // HEADS UP! + // We must put this map back the way we found it before returning, + // otherwise things break. + elems.delete(firstKey); + const [firstKeyIds, firstPostingsList, remainingAll] = await Promise.all([ + index.search(firstKey), + unpackPostingsListAll(firstList, polarity), + unpackPostingsListBindings(elems, polarity), + ]); if (!firstKeyIds) { + elems.set(firstKey, firstList); // User specified a non-existent key. return [{ invertedIndex: empty_inverted_index, queryElem: new Map(), }]; } - elems.delete(firstKey); - const [firstPostingsList, remainingAll] = await Promise.all([ - unpackPostingsListAll(firstList), - unpackPostingsListBindings(elems), - ]); /** @type {PostingsList<Map<number, rustdoc.QueryElement[]>>[]} */ const results = []; for (const keyId of firstKeyIds.matches().entries()) { @@ -4335,8 +4358,8 @@ class DocSearch { // finally, we can do the actual unification loop const [allInputs, allOutput] = await Promise.all([ - unpackPostingsListAll(inputs), - unpackPostingsListAll(output), + unpackPostingsListAll(inputs, "invertedFunctionInputsIndex"), + unpackPostingsListAll(output, "invertedFunctionOutputIndex"), ]); let checkCounter = 0; /** diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml index 05d5f21c12c..efa99f181b3 100644 --- a/src/tools/build-manifest/Cargo.toml +++ b/src/tools/build-manifest/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] toml = "0.7" serde = { version = "1.0", features = ["derive"] } -serde_json.workspace = true +serde_json = "1.0" anyhow = "1.0.32" flate2 = "1.0.26" xz2 = "0.1.7" diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index 72f5eaf8a4b..c3fc09343db 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -53,7 +53,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { | PatKind::Never | PatKind::Or(_) | PatKind::Err(_) => false, - PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), + PatKind::Struct(_, a, etc) => etc.is_none() && a.iter().all(|x| unary_pattern(x.pat)), PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a), PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x), PatKind::Expr(_) => true, diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index 5a7967bbf94..2705ef20b79 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -287,7 +287,7 @@ fn replace_in_pattern( } return or_pat; }, - PatKind::Struct(path, fields, has_dot_dot) => { + PatKind::Struct(path, fields, dot_dot) => { let fields = fields .iter() .map(|fld| { @@ -311,7 +311,7 @@ fn replace_in_pattern( .collect::<Vec<_>>(); let fields_string = fields.join(", "); - let dot_dot_str = if has_dot_dot { " .." } else { "" }; + let dot_dot_str = if dot_dot.is_some() { " .." } else { "" }; let (sn_pth, _) = snippet_with_context(cx, path.span(), span.ctxt(), "", app); return format!("{sn_pth} {{ {fields_string}{dot_dot_str} }}"); }, diff --git a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs index 2154cd5b24a..ae09c2e87d6 100644 --- a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs +++ b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs @@ -7,7 +7,7 @@ use super::REST_PAT_IN_FULLY_BOUND_STRUCTS; pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) { if !pat.span.from_expansion() - && let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind + && let PatKind::Struct(QPath::Resolved(_, path), fields, Some(_)) = pat.kind && let Some(def_id) = path.res.opt_def_id() && let ty = cx.tcx.type_of(def_id).instantiate_identity() && let ty::Adt(def, _) = ty.kind() diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 2113cb92137..ece29362a39 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -754,7 +754,8 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.ident(name); sub.if_some(|p| self.pat(p)); }, - PatKind::Struct(ref qpath, fields, ignore) => { + PatKind::Struct(ref qpath, fields, etc) => { + let ignore = etc.is_some(); bind!(self, qpath, fields); kind!("Struct(ref {qpath}, {fields}, {ignore})"); self.qpath(qpath, pat); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 8533fa85541..011c9b2f931 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -2011,7 +2011,7 @@ pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr< false } }, - (PatKind::Struct(pat_ident, field_pats, false), ExprKind::Struct(ident, fields, hir::StructTailExpr::None)) + (PatKind::Struct(pat_ident, field_pats, None), ExprKind::Struct(ident, fields, hir::StructTailExpr::None)) if field_pats.len() == fields.len() => { // check ident diff --git a/src/tools/collect-license-metadata/Cargo.toml b/src/tools/collect-license-metadata/Cargo.toml index 7f2e57ced05..edf9e5c5393 100644 --- a/src/tools/collect-license-metadata/Cargo.toml +++ b/src/tools/collect-license-metadata/Cargo.toml @@ -8,5 +8,5 @@ license = "MIT OR Apache-2.0" [dependencies] anyhow = "1.0.65" serde = { version = "1.0.147", features = ["derive"] } -serde_json.workspace = true +serde_json = "1.0.85" spdx-rs = "0.5.1" diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index fb71275b03c..cdada5a2230 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -20,22 +20,22 @@ diff = "0.1.10" getopts = "0.2" glob = "0.3.0" home = "0.5.5" -indexmap.workspace = true +indexmap = "2.0.0" miropt-test-tools = { path = "../miropt-test-tools" } rayon = "1.10.0" regex = "1.0" rustfix = "0.8.1" semver = { version = "1.0.23", features = ["serde"] } serde = { version = "1.0", features = ["derive"] } -serde_json.workspace = true +serde_json = "1.0" +tracing = "0.1" tracing-subscriber = { version = "0.3.3", default-features = false, features = ["ansi", "env-filter", "fmt", "parking_lot", "smallvec"] } -tracing.workspace = true unified-diff = "0.2.1" walkdir = "2" # tidy-alphabetical-end [target.'cfg(unix)'.dependencies] -libc.workspace = true +libc = "0.2" [target.'cfg(windows)'.dependencies] miow = "0.6" diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index fdd7155c21f..5519ef1af1f 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -13,6 +13,7 @@ use std::sync::{Arc, Mutex, mpsc}; use std::{env, hint, io, mem, panic, thread}; use crate::common::{Config, TestPaths}; +use crate::panic_hook; mod deadline; mod json; @@ -120,6 +121,11 @@ fn run_test_inner( completion_sender: mpsc::Sender<TestCompletion>, ) { let is_capture = !runnable_test.config.nocapture; + + // Install a panic-capture buffer for use by the custom panic hook. + if is_capture { + panic_hook::set_capture_buf(Default::default()); + } let capture_buf = is_capture.then(|| Arc::new(Mutex::new(vec![]))); if let Some(capture_buf) = &capture_buf { @@ -128,6 +134,13 @@ fn run_test_inner( let panic_payload = panic::catch_unwind(move || runnable_test.run()).err(); + if let Some(panic_buf) = panic_hook::take_capture_buf() { + let panic_buf = panic_buf.lock().unwrap_or_else(|e| e.into_inner()); + // For now, forward any captured panic message to (captured) stderr. + // FIXME(Zalathar): Once we have our own output-capture buffer for + // non-panic output, append the panic message to that buffer instead. + eprint!("{panic_buf}"); + } if is_capture { io::set_output_capture(None); } diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 8737fec80bb..fa84691a46f 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -15,6 +15,7 @@ pub mod directives; pub mod errors; mod executor; mod json; +mod panic_hook; mod raise_fd_limit; mod read2; pub mod runtest; @@ -493,6 +494,8 @@ pub fn opt_str2(maybestr: Option<String>) -> String { pub fn run_tests(config: Arc<Config>) { debug!(?config, "run_tests"); + panic_hook::install_panic_hook(); + // If we want to collect rustfix coverage information, // we first make sure that the coverage file does not exist. // It will be created later on. diff --git a/src/tools/compiletest/src/panic_hook.rs b/src/tools/compiletest/src/panic_hook.rs new file mode 100644 index 00000000000..1661ca6dabe --- /dev/null +++ b/src/tools/compiletest/src/panic_hook.rs @@ -0,0 +1,136 @@ +use std::backtrace::{Backtrace, BacktraceStatus}; +use std::cell::Cell; +use std::fmt::{Display, Write}; +use std::panic::PanicHookInfo; +use std::sync::{Arc, LazyLock, Mutex}; +use std::{env, mem, panic, thread}; + +type PanicHook = Box<dyn Fn(&PanicHookInfo<'_>) + Sync + Send + 'static>; +type CaptureBuf = Arc<Mutex<String>>; + +thread_local!( + static CAPTURE_BUF: Cell<Option<CaptureBuf>> = const { Cell::new(None) }; +); + +/// Installs a custom panic hook that will divert panic output to a thread-local +/// capture buffer, but only for threads that have a capture buffer set. +/// +/// Otherwise, the custom hook delegates to a copy of the default panic hook. +pub(crate) fn install_panic_hook() { + let default_hook = panic::take_hook(); + panic::set_hook(Box::new(move |info| custom_panic_hook(&default_hook, info))); +} + +pub(crate) fn set_capture_buf(buf: CaptureBuf) { + CAPTURE_BUF.set(Some(buf)); +} + +pub(crate) fn take_capture_buf() -> Option<CaptureBuf> { + CAPTURE_BUF.take() +} + +fn custom_panic_hook(default_hook: &PanicHook, info: &panic::PanicHookInfo<'_>) { + // Temporarily taking the capture buffer means that if a panic occurs in + // the subsequent code, that panic will fall back to the default hook. + let Some(buf) = take_capture_buf() else { + // There was no capture buffer, so delegate to the default hook. + default_hook(info); + return; + }; + + let mut out = buf.lock().unwrap_or_else(|e| e.into_inner()); + + let thread = thread::current().name().unwrap_or("(test runner)").to_owned(); + let location = get_location(info); + let payload = payload_as_str(info).unwrap_or("Box<dyn Any>"); + let backtrace = Backtrace::capture(); + + writeln!(out, "\nthread '{thread}' panicked at {location}:\n{payload}").unwrap(); + match backtrace.status() { + BacktraceStatus::Captured => { + let bt = trim_backtrace(backtrace.to_string()); + write!(out, "stack backtrace:\n{bt}",).unwrap(); + } + BacktraceStatus::Disabled => { + writeln!( + out, + "note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace", + ) + .unwrap(); + } + _ => {} + } + + drop(out); + set_capture_buf(buf); +} + +fn get_location<'a>(info: &'a PanicHookInfo<'_>) -> &'a dyn Display { + match info.location() { + Some(location) => location, + None => &"(unknown)", + } +} + +/// FIXME(Zalathar): Replace with `PanicHookInfo::payload_as_str` when that's +/// stable in beta. +fn payload_as_str<'a>(info: &'a PanicHookInfo<'_>) -> Option<&'a str> { + let payload = info.payload(); + if let Some(s) = payload.downcast_ref::<&str>() { + Some(s) + } else if let Some(s) = payload.downcast_ref::<String>() { + Some(s) + } else { + None + } +} + +fn rust_backtrace_full() -> bool { + static RUST_BACKTRACE_FULL: LazyLock<bool> = + LazyLock::new(|| matches!(env::var("RUST_BACKTRACE").as_deref(), Ok("full"))); + *RUST_BACKTRACE_FULL +} + +/// On stable, short backtraces are only available to the default panic hook, +/// so if we want something similar we have to resort to string processing. +fn trim_backtrace(full_backtrace: String) -> String { + if rust_backtrace_full() { + return full_backtrace; + } + + let mut buf = String::with_capacity(full_backtrace.len()); + // Don't print any frames until after the first `__rust_end_short_backtrace`. + let mut on = false; + // After the short-backtrace state is toggled, skip its associated "at" if present. + let mut skip_next_at = false; + + let mut lines = full_backtrace.lines(); + while let Some(line) = lines.next() { + if mem::replace(&mut skip_next_at, false) && line.trim_start().starts_with("at ") { + continue; + } + + if line.contains("__rust_end_short_backtrace") { + on = true; + skip_next_at = true; + continue; + } + if line.contains("__rust_begin_short_backtrace") { + on = false; + skip_next_at = true; + continue; + } + + if on { + writeln!(buf, "{line}").unwrap(); + } + } + + writeln!( + buf, + "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace." + ) + .unwrap(); + + buf +} diff --git a/src/tools/coverage-dump/Cargo.toml b/src/tools/coverage-dump/Cargo.toml index e491804c257..36a66f16030 100644 --- a/src/tools/coverage-dump/Cargo.toml +++ b/src/tools/coverage-dump/Cargo.toml @@ -7,9 +7,9 @@ edition = "2021" [dependencies] anyhow = "1.0.71" -itertools.workspace = true +itertools = "0.12" leb128 = "0.2.5" md5 = { package = "md-5" , version = "0.10.5" } miniz_oxide = "0.8.8" regex = "1.8.4" -rustc-demangle.workspace = true +rustc-demangle = "0.1.23" diff --git a/src/tools/features-status-dump/Cargo.toml b/src/tools/features-status-dump/Cargo.toml index d72555da486..b2976f14a01 100644 --- a/src/tools/features-status-dump/Cargo.toml +++ b/src/tools/features-status-dump/Cargo.toml @@ -8,5 +8,5 @@ edition = "2021" anyhow = { version = "1" } clap = { version = "4", features = ["derive"] } serde = { version = "1.0.125", features = [ "derive" ] } -serde_json.workspace = true +serde_json = "1.0.59" tidy = { path = "../tidy", features = ["build-metrics"] } diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml index 5edf1f3d88b..bcb3165de45 100644 --- a/src/tools/generate-copyright/Cargo.toml +++ b/src/tools/generate-copyright/Cargo.toml @@ -11,5 +11,5 @@ anyhow = "1.0.65" askama = "0.14.0" cargo_metadata = "0.21" serde = { version = "1.0.147", features = ["derive"] } -serde_json.workspace = true +serde_json = "1.0.85" thiserror = "1" diff --git a/src/tools/jsondocck/Cargo.toml b/src/tools/jsondocck/Cargo.toml index 92fde363882..80fc26cbe66 100644 --- a/src/tools/jsondocck/Cargo.toml +++ b/src/tools/jsondocck/Cargo.toml @@ -8,5 +8,5 @@ jsonpath-rust = "1.0.0" getopts = "0.2" regex = "1.4" shlex = "1.0" -serde_json.workspace = true +serde_json = "1.0" fs-err = "2.5.0" diff --git a/src/tools/jsondoclint/Cargo.toml b/src/tools/jsondoclint/Cargo.toml index 44beaf2ddfd..cc8ecefd530 100644 --- a/src/tools/jsondoclint/Cargo.toml +++ b/src/tools/jsondoclint/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" anyhow = "1.0.62" clap = { version = "4.0.15", features = ["derive"] } fs-err = "2.8.1" -rustc-hash.workspace = true +rustc-hash = "2.0.0" rustdoc-json-types = { version = "0.1.0", path = "../../rustdoc-json-types" } serde = { version = "1.0", features = ["derive"] } -serde_json.workspace = true +serde_json = "1.0.85" diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml index acafe17cb0c..6e1ab84ed18 100644 --- a/src/tools/lint-docs/Cargo.toml +++ b/src/tools/lint-docs/Cargo.toml @@ -8,6 +8,6 @@ description = "A script to extract the lint documentation for the rustc book." [dependencies] rustc-literal-escaper = "0.0.5" -serde_json.workspace = true -tempfile.workspace = true +serde_json = "1.0.57" +tempfile = "3.1.0" walkdir = "2.3.1" diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index b33344ca5dd..bc38e931fe5 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -59,6 +59,8 @@ pub struct LintExtractor<'a> { pub rustc_target: &'a str, /// The target linker overriding `rustc`'s default pub rustc_linker: Option<&'a str>, + /// Stage of the compiler that builds the docs (the stage of `rustc_path`). + pub build_rustc_stage: u32, /// Verbose output. pub verbose: bool, /// Validate the style and the code example. @@ -216,14 +218,7 @@ impl<'a> LintExtractor<'a> { if let Some(text) = line.strip_prefix("/// ") { doc_lines.push(text.to_string()); } else if let Some(text) = line.strip_prefix("#[doc = \"") { - let escaped = text.strip_suffix("\"]").unwrap(); - let mut buf = String::new(); - unescape_str(escaped, |_, res| match res { - Ok(c) => buf.push(c), - Err(err) => { - assert!(!err.is_fatal(), "failed to unescape string literal") - } - }); + let buf = parse_doc_string(text); doc_lines.push(buf); } else if line == "///" { doc_lines.push("".to_string()); @@ -234,6 +229,20 @@ impl<'a> LintExtractor<'a> { // Ignore allow of lints (useful for // invalid_rust_codeblocks). continue; + } else if let Some(text) = + line.strip_prefix("#[cfg_attr(not(bootstrap), doc = \"") + { + if self.build_rustc_stage >= 1 { + let buf = parse_doc_string(text); + doc_lines.push(buf); + } + } else if let Some(text) = + line.strip_prefix("#[cfg_attr(bootstrap, doc = \"") + { + if self.build_rustc_stage == 0 { + let buf = parse_doc_string(text); + doc_lines.push(buf); + } } else { let name = lint_name(line).map_err(|e| { format!( @@ -580,6 +589,23 @@ impl<'a> LintExtractor<'a> { } } +/// Parses a doc string that follows `#[doc = "`. +fn parse_doc_string(text: &str) -> String { + let escaped = text.strip_suffix("]").unwrap_or(text); + let escaped = escaped.strip_suffix(")").unwrap_or(escaped).strip_suffix("\""); + let Some(escaped) = escaped else { + panic!("Cannot extract docstring content from {text}"); + }; + let mut buf = String::new(); + unescape_str(escaped, |_, res| match res { + Ok(c) => buf.push(c), + Err(err) => { + assert!(!err.is_fatal(), "failed to unescape string literal") + } + }); + buf +} + /// Adds `Lint`s that have been renamed. fn add_renamed_lints(lints: &mut Vec<Lint>) { for (level, names) in RENAMES { diff --git a/src/tools/lint-docs/src/main.rs b/src/tools/lint-docs/src/main.rs index e377283b1a4..1933ce4d2f1 100644 --- a/src/tools/lint-docs/src/main.rs +++ b/src/tools/lint-docs/src/main.rs @@ -25,6 +25,7 @@ fn doit() -> Result<(), Box<dyn Error>> { let mut args = std::env::args().skip(1); let mut src_path = None; let mut out_path = None; + let mut build_rustc_stage = None; let mut rustc_path = None; let mut rustc_target = None; let mut rustc_linker = None; @@ -32,6 +33,14 @@ fn doit() -> Result<(), Box<dyn Error>> { let mut validate = false; while let Some(arg) = args.next() { match arg.as_str() { + "--build-rustc-stage" => { + build_rustc_stage = match args.next() { + Some(s) => { + Some(s.parse::<u32>().expect("build rustc stage has to be an integer")) + } + None => return Err("--build-rustc-stage requires a value".into()), + }; + } "--src" => { src_path = match args.next() { Some(s) => Some(PathBuf::from(s)), @@ -67,6 +76,9 @@ fn doit() -> Result<(), Box<dyn Error>> { s => return Err(format!("unexpected argument `{}`", s).into()), } } + if build_rustc_stage.is_none() { + return Err("--build-rustc-stage must be specified to the stage of the compiler that generates the docs".into()); + } if src_path.is_none() { return Err("--src must be specified to the directory with the compiler source".into()); } @@ -85,6 +97,7 @@ fn doit() -> Result<(), Box<dyn Error>> { rustc_path: &rustc_path.unwrap(), rustc_target: &rustc_target.unwrap(), rustc_linker: rustc_linker.as_deref(), + build_rustc_stage: build_rustc_stage.unwrap(), verbose, validate, }; diff --git a/src/tools/llvm-bitcode-linker/Cargo.toml b/src/tools/llvm-bitcode-linker/Cargo.toml index f78f8b618d3..a9210b562f3 100644 --- a/src/tools/llvm-bitcode-linker/Cargo.toml +++ b/src/tools/llvm-bitcode-linker/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] anyhow = "1.0" -tracing.workspace = true -tracing-subscriber = { version = "0.3.0", features = ["std"] } +tracing = "0.1" +tracing-subscriber = {version = "0.3.0", features = ["std"] } clap = { version = "4.3", features = ["derive"] } thiserror = "1.0.24" diff --git a/src/tools/nix-dev-shell/shell.nix b/src/tools/nix-dev-shell/shell.nix index ad33b121f97..6ca8a7c4652 100644 --- a/src/tools/nix-dev-shell/shell.nix +++ b/src/tools/nix-dev-shell/shell.nix @@ -14,6 +14,7 @@ pkgs.mkShell { packages = [ pkgs.git pkgs.nix + pkgs.glibc.out pkgs.glibc.static x # Get the runtime deps of the x wrapper @@ -23,5 +24,7 @@ pkgs.mkShell { # Avoid creating text files for ICEs. RUSTC_ICE = 0; SSL_CERT_FILE = cacert; + # cargo seems to dlopen libcurl, so we need it in the ld library path + LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath [pkgs.stdenv.cc.cc.lib pkgs.curl]}"; }; } diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml index b2833a9d7f1..f4051ae67d7 100644 --- a/src/tools/opt-dist/Cargo.toml +++ b/src/tools/opt-dist/Cargo.toml @@ -15,9 +15,9 @@ fs_extra = "1" camino = "1" tar = "0.4" xz = { version = "0.1", package = "xz2" } -serde_json.workspace = true +serde_json = "1" glob = "0.3" -tempfile.workspace = true +tempfile = "3.5" derive_builder = "0.20" clap = { version = "4", features = ["derive"] } tabled = { version = "0.15", default-features = false, features = ["std"] } diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 86ac4b9d7b4..250e0f65a9f 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -12,10 +12,10 @@ edition = "2024" # tidy-alphabetical-start bstr = "1.12" gimli = "0.32" -libc.workspace = true +libc = "0.2" object = "0.37" regex = "1.11" -serde_json.workspace = true +serde_json = "1.0" similar = "2.7" wasmparser = { version = "0.236", default-features = false, features = ["std", "features", "validate"] } # tidy-alphabetical-end diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index d212ecf392a..848bd0766e7 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -303,7 +303,7 @@ impl Rewrite for Pat { qself, path, fields, - rest == ast::PatFieldsRest::Rest, + matches!(rest, ast::PatFieldsRest::Rest(_)), self.span, context, shape, diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index f43733665ed..c1f27de7ed4 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -14,7 +14,7 @@ ignore = "0.4.18" semver = "1.0" serde = { version = "1.0.125", features = ["derive"], optional = true } termcolor = "1.1.3" -rustc-hash.workspace = true +rustc-hash = "2.0.0" fluent-syntax = "0.12" similar = "2.5.0" toml = "0.7.8" diff --git a/tests/codegen-llvm/async-fn-debug-awaitee-field.rs b/tests/codegen-llvm/async-fn-debug-awaitee-field.rs index 50860c90662..b9d3d9ee66e 100644 --- a/tests/codegen-llvm/async-fn-debug-awaitee-field.rs +++ b/tests/codegen-llvm/async-fn-debug-awaitee-field.rs @@ -18,11 +18,11 @@ pub async fn async_fn_test() { pub async fn foo() {} +// NONMSVC: [[AWAITEE_TYPE:![0-9]*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[AWAITEE_SCOPE:![0-9]*]], +// MSVC: [[AWAITEE_TYPE:![0-9]*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<async_fn_debug_awaitee_field::foo::async_fn_env$0>", +// NONMSVC: [[AWAITEE_SCOPE]] = !DINamespace(name: "foo", // NONMSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[GEN_SCOPE:![0-9]*]], // MSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<async_fn_debug_awaitee_field::async_fn_test::async_fn_env$0>", // NONMSVC: [[GEN_SCOPE:!.*]] = !DINamespace(name: "async_fn_test", // CHECK: [[SUSPEND_STRUCT:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend0", scope: [[GEN]], -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__awaitee", scope: [[SUSPEND_STRUCT]], {{.*}}, baseType: [[AWAITEE_TYPE:![0-9]*]], -// NONMSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[AWAITEE_SCOPE:![0-9]*]], -// MSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<async_fn_debug_awaitee_field::foo::async_fn_env$0>", -// NONMSVC: [[AWAITEE_SCOPE]] = !DINamespace(name: "foo", +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__awaitee", scope: [[SUSPEND_STRUCT]], {{.*}}, baseType: [[AWAITEE_TYPE]], diff --git a/tests/codegen-llvm/cffi/c-variadic-ffi.rs b/tests/codegen-llvm/cffi/c-variadic-ffi.rs index 3e99c9fb84e..1dee477e9ed 100644 --- a/tests/codegen-llvm/cffi/c-variadic-ffi.rs +++ b/tests/codegen-llvm/cffi/c-variadic-ffi.rs @@ -14,7 +14,7 @@ //@[arm32] needs-llvm-components: arm #![crate_type = "lib"] #![feature(no_core)] -#![feature(extended_varargs_abi_support, extern_system_varargs)] +#![feature(extern_system_varargs)] #![no_core] extern crate minicore; diff --git a/tests/codegen-units/item-collection/async-fn-impl.rs b/tests/codegen-units/item-collection/async-fn-impl.rs new file mode 100644 index 00000000000..540fa0b3228 --- /dev/null +++ b/tests/codegen-units/item-collection/async-fn-impl.rs @@ -0,0 +1,10 @@ +//@ edition: 2024 +// When pub async fn is monomorphized, its implementation coroutine is also monomorphized +//@ compile-flags: --crate-type=lib + +//~ MONO_ITEM fn async_fn @@ +//~ MONO_ITEM fn async_fn::{closure#0} @@ +#[unsafe(no_mangle)] +pub async fn async_fn(x: u64) -> bool { + true +} diff --git a/tests/codegen-units/item-collection/opaque-return-impls.rs b/tests/codegen-units/item-collection/opaque-return-impls.rs new file mode 100644 index 00000000000..7d5f4f5b669 --- /dev/null +++ b/tests/codegen-units/item-collection/opaque-return-impls.rs @@ -0,0 +1,89 @@ +//@ only-x86_64-unknown-linux-gnu +//@ compile-flags: -C panic=abort -Zinline-mir=no -Copt-level=0 -Zcross-crate-inline-threshold=never -Zmir-opt-level=0 -Cno-prepopulate-passes +//@ no-prefer-dynamic +//@ edition:2024 +#![crate_type = "lib"] + +trait TestTrait { + fn test_func(&self); +} + +struct TestStruct {} + +impl TestTrait for TestStruct { + fn test_func(&self) { + println!("TestStruct::test_func"); + } +} + +#[inline(never)] +pub fn foo() -> impl TestTrait { + TestStruct {} +} + +//~ MONO_ITEM fn foo +//~ MONO_ITEM fn <TestStruct as TestTrait>::test_func + +trait TestTrait2 { + fn test_func2(&self); +} + +struct TestStruct2 {} + +impl TestTrait2 for TestStruct2 { + fn test_func2(&self) { + println!("TestStruct2::test_func2"); + } +} + +#[inline(never)] +pub fn foo2() -> Box<dyn TestTrait2> { + Box::new(TestStruct2 {}) +} + +//~ MONO_ITEM fn <TestStruct2 as TestTrait2>::test_func2 +//~ MONO_ITEM fn alloc::alloc::exchange_malloc +//~ MONO_ITEM fn foo2 +//~ MONO_ITEM fn std::alloc::Global::alloc_impl +//~ MONO_ITEM fn std::boxed::Box::<TestStruct2>::new +//~ MONO_ITEM fn std::alloc::Layout::from_size_align_unchecked::precondition_check +//~ MONO_ITEM fn std::ptr::NonNull::<T>::new_unchecked::precondition_check + +struct Counter { + count: usize, +} + +impl Counter { + fn new() -> Counter { + Counter { count: 0 } + } +} + +impl Iterator for Counter { + type Item = usize; + + fn next(&mut self) -> Option<Self::Item> { + self.count += 1; + if self.count < 6 { Some(self.count) } else { None } + } +} + +#[inline(never)] +pub fn foo3() -> Box<dyn Iterator<Item = usize>> { + Box::new(Counter::new()) +} + +//~ MONO_ITEM fn <Counter as std::iter::Iterator::advance_by::SpecAdvanceBy>::spec_advance_by +//~ MONO_ITEM fn <Counter as std::iter::Iterator::advance_by::SpecAdvanceBy>::spec_advance_by::{closure#0} +//~ MONO_ITEM fn <Counter as std::iter::Iterator>::advance_by +//~ MONO_ITEM fn <Counter as std::iter::Iterator>::next +//~ MONO_ITEM fn <Counter as std::iter::Iterator>::nth +//~ MONO_ITEM fn <Counter as std::iter::Iterator>::size_hint +//~ MONO_ITEM fn <Counter as std::iter::Iterator>::try_fold::<std::num::NonZero<usize>, {closure@<Counter as std::iter::Iterator::advance_by::SpecAdvanceBy>::spec_advance_by::{closure#0}}, std::option::Option<std::num::NonZero<usize>>> +//~ MONO_ITEM fn <std::option::Option<std::num::NonZero<usize>> as std::ops::FromResidual<std::option::Option<std::convert::Infallible>>>::from_residual +//~ MONO_ITEM fn <std::option::Option<std::num::NonZero<usize>> as std::ops::Try>::branch +//~ MONO_ITEM fn <std::option::Option<std::num::NonZero<usize>> as std::ops::Try>::from_output +//~ MONO_ITEM fn foo3 +//~ MONO_ITEM fn std::boxed::Box::<Counter>::new +//~ MONO_ITEM fn Counter::new +//~ MONO_ITEM fn core::fmt::rt::<impl std::fmt::Arguments<'_>>::new_const::<1> diff --git a/tests/coverage/async.cov-map b/tests/coverage/async.cov-map index c528ad525b5..d75c4b5981a 100644 --- a/tests/coverage/async.cov-map +++ b/tests/coverage/async.cov-map @@ -103,21 +103,21 @@ Number of file 0 mappings: 3 Highest counter ID seen: (none) Function name: async::g -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 00, 16] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 00, 12] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 22) +- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 18) Highest counter ID seen: c0 Function name: async::g::{closure#0} (unused) -Raw bytes (64): 0x[01, 01, 00, 0c, 00, 1b, 17, 00, 18, 00, 01, 0b, 00, 0c, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] +Raw bytes (64): 0x[01, 01, 00, 0c, 00, 1b, 13, 00, 14, 00, 01, 0b, 00, 0c, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 12 -- Code(Zero) at (prev + 27, 23) to (start + 0, 24) +- Code(Zero) at (prev + 27, 19) to (start + 0, 20) - Code(Zero) at (prev + 1, 11) to (start + 0, 12) - Code(Zero) at (prev + 1, 9) to (start + 0, 10) - Code(Zero) at (prev + 0, 14) to (start + 0, 23) diff --git a/tests/coverage/async.coverage b/tests/coverage/async.coverage index 9fca1b6997d..9409e6b1deb 100644 --- a/tests/coverage/async.coverage +++ b/tests/coverage/async.coverage @@ -24,8 +24,8 @@ LL| | LL| 0|async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()` LL| | - LL| 1|pub async fn g(x: u8) { - ^0 + LL| 1|async fn g(x: u8) { + ^0 LL| 0| match x { LL| 0| y if e().await == y => (), LL| 0| y if f().await == y => (), diff --git a/tests/coverage/async.rs b/tests/coverage/async.rs index da0a1c0b6f0..777ad7ce7c0 100644 --- a/tests/coverage/async.rs +++ b/tests/coverage/async.rs @@ -24,7 +24,7 @@ async fn f() -> u8 { 1 } async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()` -pub async fn g(x: u8) { +async fn g(x: u8) { match x { y if e().await == y => (), y if f().await == y => (), diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index 5f7e4ce58e9..ee8934f0a84 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -118,21 +118,23 @@ Number of file 0 mappings: 4 Highest counter ID seen: (none) Function name: closure::main::{closure#12} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, a7, 01, 0a, 00, 16] +Raw bytes (15): 0x[01, 01, 00, 02, 00, a7, 01, 01, 00, 09, 00, 00, 0a, 00, 16] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 167, 10) to (start + 0, 22) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 167, 1) to (start + 0, 9) +- Code(Zero) at (prev + 0, 10) to (start + 0, 22) Highest counter ID seen: (none) Function name: closure::main::{closure#13} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, ad, 01, 11, 00, 1d] +Raw bytes (15): 0x[01, 01, 00, 02, 00, ac, 01, 0d, 00, 15, 00, 01, 11, 00, 1d] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 173, 17) to (start + 0, 29) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 172, 13) to (start + 0, 21) +- Code(Zero) at (prev + 1, 17) to (start + 0, 29) Highest counter ID seen: (none) Function name: closure::main::{closure#14} @@ -289,30 +291,33 @@ Number of file 0 mappings: 7 Highest counter ID seen: (none) Function name: closure::main::{closure#5} -Raw bytes (10): 0x[01, 01, 00, 01, 01, 8c, 01, 46, 00, 4e] +Raw bytes (15): 0x[01, 01, 00, 02, 01, 8c, 01, 3d, 00, 45, 01, 00, 46, 00, 4e] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 140, 70) to (start + 0, 78) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 140, 61) to (start + 0, 69) +- Code(Counter(0)) at (prev + 0, 70) to (start + 0, 78) Highest counter ID seen: c0 Function name: closure::main::{closure#6} -Raw bytes (10): 0x[01, 01, 00, 01, 01, 8d, 01, 4a, 00, 56] +Raw bytes (15): 0x[01, 01, 00, 02, 01, 8d, 01, 41, 00, 49, 01, 00, 4a, 00, 56] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 141, 74) to (start + 0, 86) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 141, 65) to (start + 0, 73) +- Code(Counter(0)) at (prev + 0, 74) to (start + 0, 86) Highest counter ID seen: c0 Function name: closure::main::{closure#7} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 8e, 01, 44, 00, 50] +Raw bytes (15): 0x[01, 01, 00, 02, 00, 8e, 01, 3b, 00, 43, 00, 00, 44, 00, 50] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 142, 68) to (start + 0, 80) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 142, 59) to (start + 0, 67) +- Code(Zero) at (prev + 0, 68) to (start + 0, 80) Highest counter ID seen: (none) Function name: closure::main::{closure#8} (unused) diff --git a/tests/coverage/closure.coverage b/tests/coverage/closure.coverage index 14285269228..d44ecf5a69e 100644 --- a/tests/coverage/closure.coverage +++ b/tests/coverage/closure.coverage @@ -139,9 +139,9 @@ LL| | LL| 1| let short_used_covered_closure_macro = | used_arg: u8 | println!("called"); LL| 1| let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called"); - ^0 + ^0 ^0 LL| 1| let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called"); - ^0 + ^0 ^0 LL| | LL| | LL| | @@ -173,7 +173,7 @@ LL| | LL| 1| let _short_unused_closure_line_break_no_block2 = LL| | | _unused_arg: u8 | - LL| | println!( + LL| 0| println!( LL| 0| "not called" LL| | ) LL| | ; diff --git a/tests/coverage/macro_in_closure.cov-map b/tests/coverage/macro_in_closure.cov-map index 4544aa50143..3529d0c4c32 100644 --- a/tests/coverage/macro_in_closure.cov-map +++ b/tests/coverage/macro_in_closure.cov-map @@ -1,10 +1,11 @@ Function name: macro_in_closure::NO_BLOCK::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 07, 25, 00, 2c] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 07, 1c, 00, 24, 01, 00, 25, 00, 2c] Number of files: 1 - file 0 => $DIR/macro_in_closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 7, 37) to (start + 0, 44) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 7, 28) to (start + 0, 36) +- Code(Counter(0)) at (prev + 0, 37) to (start + 0, 44) Highest counter ID seen: c0 Function name: macro_in_closure::WITH_BLOCK::{closure#0} diff --git a/tests/coverage/rustfmt-skip.cov-map b/tests/coverage/rustfmt-skip.cov-map new file mode 100644 index 00000000000..bb673a411bf --- /dev/null +++ b/tests/coverage/rustfmt-skip.cov-map @@ -0,0 +1,12 @@ +Function name: rustfmt_skip::main +Raw bytes (24): 0x[01, 01, 00, 04, 01, 0a, 01, 00, 0a, 01, 02, 05, 00, 0d, 01, 03, 09, 00, 10, 01, 02, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/rustfmt-skip.rs +Number of expressions: 0 +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 10, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: c0 + diff --git a/tests/coverage/rustfmt-skip.coverage b/tests/coverage/rustfmt-skip.coverage new file mode 100644 index 00000000000..b7276cf0ee8 --- /dev/null +++ b/tests/coverage/rustfmt-skip.coverage @@ -0,0 +1,18 @@ + LL| |//@ edition: 2024 + LL| | + LL| |// The presence of `#[rustfmt::skip]` on a function should not cause macros + LL| |// within that function to mysteriously not be instrumented. + LL| |// + LL| |// This test detects problems that can occur when building an expansion tree + LL| |// based on `ExpnData::parent` instead of `ExpnData::call_site`, for example. + LL| | + LL| |#[rustfmt::skip] + LL| 1|fn main() { + LL| | // Ensure a gap between the body start and the first statement. + LL| 1| println!( + LL| | // Keep this on a separate line, to distinguish instrumentation of + LL| | // `println!` from instrumentation of its arguments. + LL| 1| "hello" + LL| | ); + LL| 1|} + diff --git a/tests/coverage/rustfmt-skip.rs b/tests/coverage/rustfmt-skip.rs new file mode 100644 index 00000000000..6f6874c9aa0 --- /dev/null +++ b/tests/coverage/rustfmt-skip.rs @@ -0,0 +1,17 @@ +//@ edition: 2024 + +// The presence of `#[rustfmt::skip]` on a function should not cause macros +// within that function to mysteriously not be instrumented. +// +// This test detects problems that can occur when building an expansion tree +// based on `ExpnData::parent` instead of `ExpnData::call_site`, for example. + +#[rustfmt::skip] +fn main() { + // Ensure a gap between the body start and the first statement. + println!( + // Keep this on a separate line, to distinguish instrumentation of + // `println!` from instrumentation of its arguments. + "hello" + ); +} diff --git a/tests/mir-opt/building/loop_match_diverges.break_to_block_unit.built.after.mir b/tests/mir-opt/building/loop_match_diverges.break_to_block_unit.built.after.mir new file mode 100644 index 00000000000..6d779e46146 --- /dev/null +++ b/tests/mir-opt/building/loop_match_diverges.break_to_block_unit.built.after.mir @@ -0,0 +1,63 @@ +// MIR for `break_to_block_unit` after built + +fn break_to_block_unit() -> u8 { + let mut _0: u8; + let mut _1: i32; + let mut _2: !; + scope 1 { + debug state => _1; + } + + bb0: { + StorageLive(_1); + _1 = const 0_i32; + FakeRead(ForLet(None), _1); + StorageLive(_2); + goto -> bb1; + } + + bb1: { + falseUnwind -> [real: bb2, unwind: bb10]; + } + + bb2: { + PlaceMention(_1); + _1 = const 2_i32; + goto -> bb5; + } + + bb3: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb4: { + goto -> bb6; + } + + bb5: { + goto -> bb6; + } + + bb6: { + goto -> bb7; + } + + bb7: { + goto -> bb1; + } + + bb8: { + unreachable; + } + + bb9: { + StorageDead(_2); + StorageDead(_1); + return; + } + + bb10 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/loop_match_diverges.infinite_a.built.after.mir b/tests/mir-opt/building/loop_match_diverges.infinite_a.built.after.mir new file mode 100644 index 00000000000..e3766744790 --- /dev/null +++ b/tests/mir-opt/building/loop_match_diverges.infinite_a.built.after.mir @@ -0,0 +1,51 @@ +// MIR for `infinite_a` after built + +fn infinite_a(_1: u8) -> () { + debug state => _1; + let mut _0: (); + let mut _2: !; + let _3: u8; + scope 1 { + debug a => _3; + } + + bb0: { + StorageLive(_2); + goto -> bb1; + } + + bb1: { + falseUnwind -> [real: bb2, unwind: bb7]; + } + + bb2: { + PlaceMention(_1); + StorageLive(_3); + _3 = copy _1; + _1 = copy _3; + StorageDead(_3); + goto -> bb4; + } + + bb3: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb4: { + goto -> bb1; + } + + bb5: { + unreachable; + } + + bb6: { + StorageDead(_2); + return; + } + + bb7 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/loop_match_diverges.rs b/tests/mir-opt/building/loop_match_diverges.rs new file mode 100644 index 00000000000..774e195c33c --- /dev/null +++ b/tests/mir-opt/building/loop_match_diverges.rs @@ -0,0 +1,68 @@ +// skip-filecheck +#![allow(incomplete_features)] +#![feature(loop_match)] +#![crate_type = "lib"] + +// Test that a #[loop_match] without an explicit break from the loop generates valid MIR. + +enum State { + A, + B, + C, +} + +// EMIT_MIR loop_match_diverges.simple.built.after.mir +fn simple(mut state: State) -> State { + #[loop_match] + 'a: loop { + state = 'blk: { + match state { + State::A => { + #[const_continue] + break 'blk State::B; + } + State::B => { + if true { + #[const_continue] + break 'blk State::C; + } else { + #[const_continue] + break 'blk State::A; + } + } + State::C => break 'a, + } + }; + } + + state +} + +// EMIT_MIR loop_match_diverges.break_to_block_unit.built.after.mir +#[unsafe(no_mangle)] +fn break_to_block_unit() -> u8 { + let mut state = 0; + #[loop_match] + loop { + state = 'blk: { + match state { + _ => 'b: { + break 'b 2; + } + } + } + } +} + +// EMIT_MIR loop_match_diverges.infinite_a.built.after.mir +#[unsafe(no_mangle)] +fn infinite_a(mut state: u8) { + #[loop_match] + loop { + state = 'blk: { + match state { + a => a, + } + } + } +} diff --git a/tests/mir-opt/building/loop_match_diverges.simple.built.after.mir b/tests/mir-opt/building/loop_match_diverges.simple.built.after.mir new file mode 100644 index 00000000000..26476ad7762 --- /dev/null +++ b/tests/mir-opt/building/loop_match_diverges.simple.built.after.mir @@ -0,0 +1,187 @@ +// MIR for `simple` after built + +fn simple(_1: State) -> State { + debug state => _1; + let mut _0: State; + let _2: (); + let mut _3: isize; + let mut _4: !; + let mut _5: isize; + let mut _6: bool; + let mut _7: !; + let mut _8: isize; + let mut _9: !; + let mut _10: isize; + let mut _11: !; + + bb0: { + StorageLive(_2); + goto -> bb1; + } + + bb1: { + falseUnwind -> [real: bb2, unwind: bb37]; + } + + bb2: { + PlaceMention(_1); + _3 = discriminant(_1); + switchInt(move _3) -> [0: bb4, 1: bb6, 2: bb8, otherwise: bb3]; + } + + bb3: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb4: { + falseEdge -> [real: bb11, imaginary: bb6]; + } + + bb5: { + goto -> bb3; + } + + bb6: { + falseEdge -> [real: bb10, imaginary: bb8]; + } + + bb7: { + goto -> bb3; + } + + bb8: { + _2 = const (); + goto -> bb36; + } + + bb9: { + goto -> bb3; + } + + bb10: { + StorageLive(_6); + _6 = const true; + switchInt(move _6) -> [0: bb17, otherwise: bb16]; + } + + bb11: { + _1 = State::B; + _5 = discriminant(_1); + falseEdge -> [real: bb12, imaginary: bb13]; + } + + bb12: { + goto -> bb10; + } + + bb13: { + goto -> bb34; + } + + bb14: { + unreachable; + } + + bb15: { + goto -> bb32; + } + + bb16: { + _1 = State::C; + _8 = discriminant(_1); + falseEdge -> [real: bb18, imaginary: bb19]; + } + + bb17: { + goto -> bb23; + } + + bb18: { + goto -> bb20; + } + + bb19: { + goto -> bb33; + } + + bb20: { + StorageDead(_6); + goto -> bb8; + } + + bb21: { + unreachable; + } + + bb22: { + goto -> bb29; + } + + bb23: { + _1 = State::A; + _10 = discriminant(_1); + falseEdge -> [real: bb24, imaginary: bb25]; + } + + bb24: { + goto -> bb26; + } + + bb25: { + goto -> bb33; + } + + bb26: { + StorageDead(_6); + goto -> bb11; + } + + bb27: { + unreachable; + } + + bb28: { + goto -> bb29; + } + + bb29: { + StorageDead(_6); + goto -> bb32; + } + + bb30: { + unreachable; + } + + bb31: { + goto -> bb32; + } + + bb32: { + goto -> bb35; + } + + bb33: { + StorageDead(_6); + goto -> bb34; + } + + bb34: { + goto -> bb35; + } + + bb35: { + goto -> bb1; + } + + bb36: { + StorageDead(_2); + _0 = move _1; + return; + } + + bb37 (cleanup): { + resume; + } +} diff --git a/tests/ui/abi/unsupported-varargs-fnptr.rs b/tests/ui/abi/unsupported-varargs-fnptr.rs index 1d23916d039..ac3913b3ef8 100644 --- a/tests/ui/abi/unsupported-varargs-fnptr.rs +++ b/tests/ui/abi/unsupported-varargs-fnptr.rs @@ -6,8 +6,6 @@ // We have to use this flag to force ABI computation of an invalid ABI //@ compile-flags: -Clink-dead-code -#![feature(extended_varargs_abi_support)] - // sometimes fn ptrs with varargs make layout and ABI computation ICE // as found in https://github.com/rust-lang/rust/issues/142107 diff --git a/tests/ui/abi/unsupported-varargs-fnptr.stderr b/tests/ui/abi/unsupported-varargs-fnptr.stderr index 238f2b31330..c05c55df82e 100644 --- a/tests/ui/abi/unsupported-varargs-fnptr.stderr +++ b/tests/ui/abi/unsupported-varargs-fnptr.stderr @@ -1,5 +1,5 @@ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported-varargs-fnptr.rs:14:20 + --> $DIR/unsupported-varargs-fnptr.rs:12:20 | LL | fn aapcs(f: extern "aapcs" fn(usize, ...)) { | ^^^^^^^ diff --git a/tests/ui/async-await/dont-suggest-await-on-method-return-mismatch.stderr b/tests/ui/async-await/dont-suggest-await-on-method-return-mismatch.stderr index 1faaf4ddce2..aa2343e48a6 100644 --- a/tests/ui/async-await/dont-suggest-await-on-method-return-mismatch.stderr +++ b/tests/ui/async-await/dont-suggest-await-on-method-return-mismatch.stderr @@ -3,6 +3,11 @@ error[E0599]: no method named `test` found for opaque type `impl Future<Output = | LL | let x: u32 = foo().test(); | ^^^^ method not found in `impl Future<Output = A>` + | +help: consider `await`ing on the `Future` and calling the method on its `Output` + | +LL | let x: u32 = foo().await.test(); + | ++++++ error: aborting due to 1 previous error diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.rs b/tests/ui/async-await/future-sizes/async-awaiting-fut.rs index a3f0bdc8514..b5f59069f85 100644 --- a/tests/ui/async-await/future-sizes/async-awaiting-fut.rs +++ b/tests/ui/async-await/future-sizes/async-awaiting-fut.rs @@ -1,7 +1,9 @@ -//@ compile-flags: -Z print-type-sizes --crate-type lib +//@ compile-flags: -C panic=abort -Z print-type-sizes --crate-type lib +//@ needs-deterministic-layouts //@ edition:2021 //@ build-pass //@ ignore-pass +//@ only-x86_64 async fn wait() {} diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout index 642e27b2a57..b30c15bcbe6 100644 --- a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout +++ b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout @@ -48,6 +48,39 @@ print-type-size variant `Returned`: 1024 bytes print-type-size upvar `.arg`: 1024 bytes print-type-size variant `Panicked`: 1024 bytes print-type-size upvar `.arg`: 1024 bytes +print-type-size type: `std::task::Context<'_>`: 32 bytes, alignment: 8 bytes +print-type-size field `.waker`: 8 bytes +print-type-size field `.local_waker`: 8 bytes +print-type-size field `.ext`: 16 bytes +print-type-size field `._marker`: 0 bytes +print-type-size field `._marker2`: 0 bytes +print-type-size type: `std::panic::Location<'_>`: 24 bytes, alignment: 8 bytes +print-type-size field `.filename`: 16 bytes +print-type-size field `.line`: 4 bytes +print-type-size field `.col`: 4 bytes +print-type-size field `._filename`: 0 bytes +print-type-size type: `core::task::wake::ExtData<'_>`: 16 bytes, alignment: 8 bytes +print-type-size variant `Some`: 16 bytes +print-type-size field `.0`: 16 bytes +print-type-size variant `None`: 0 bytes +print-type-size field `.0`: 0 bytes +print-type-size type: `std::panic::AssertUnwindSafe<core::task::wake::ExtData<'_>>`: 16 bytes, alignment: 8 bytes +print-type-size field `.0`: 16 bytes +print-type-size type: `std::ptr::NonNull<str>`: 16 bytes, alignment: 8 bytes +print-type-size field `.pointer`: 16 bytes +print-type-size type: `std::pin::Pin<&mut {async fn body of big_fut()}>`: 8 bytes, alignment: 8 bytes +print-type-size field `.pointer`: 8 bytes +print-type-size type: `std::pin::Pin<&mut {async fn body of calls_fut<{async fn body of big_fut()}>()}>`: 8 bytes, alignment: 8 bytes +print-type-size field `.pointer`: 8 bytes +print-type-size type: `std::pin::Pin<&mut {async fn body of test()}>`: 8 bytes, alignment: 8 bytes +print-type-size field `.pointer`: 8 bytes +print-type-size type: `std::pin::Pin<&mut {async fn body of wait()}>`: 8 bytes, alignment: 8 bytes +print-type-size field `.pointer`: 8 bytes +print-type-size type: `std::ptr::DynMetadata<dyn std::any::Any>`: 8 bytes, alignment: 8 bytes +print-type-size field `._vtable_ptr`: 8 bytes +print-type-size field `._phantom`: 0 bytes +print-type-size type: `std::ptr::NonNull<std::ptr::metadata::VTable>`: 8 bytes, alignment: 8 bytes +print-type-size field `.pointer`: 8 bytes print-type-size type: `std::mem::ManuallyDrop<bool>`: 1 bytes, alignment: 1 bytes print-type-size field `.value`: 1 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes @@ -70,3 +103,7 @@ print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 0 bytes print-type-size variant `Returned`: 0 bytes print-type-size variant `Panicked`: 0 bytes +print-type-size type: `std::marker::PhantomData<&str>`: 0 bytes, alignment: 1 bytes +print-type-size type: `std::marker::PhantomData<*mut ()>`: 0 bytes, alignment: 1 bytes +print-type-size type: `std::marker::PhantomData<dyn std::any::Any>`: 0 bytes, alignment: 1 bytes +print-type-size type: `std::marker::PhantomData<fn(&()) -> &()>`: 0 bytes, alignment: 1 bytes diff --git a/tests/ui/async-await/future-sizes/large-arg.rs b/tests/ui/async-await/future-sizes/large-arg.rs index 5fbae22a771..809f7cf1f93 100644 --- a/tests/ui/async-await/future-sizes/large-arg.rs +++ b/tests/ui/async-await/future-sizes/large-arg.rs @@ -1,7 +1,9 @@ -//@ compile-flags: -Z print-type-sizes --crate-type=lib +//@ compile-flags: -C panic=abort -Z print-type-sizes --crate-type=lib +//@ needs-deterministic-layouts //@ edition: 2021 //@ build-pass //@ ignore-pass +//@ only-x86_64 pub async fn test() { let _ = a([0u8; 1024]).await; diff --git a/tests/ui/async-await/future-sizes/large-arg.stdout b/tests/ui/async-await/future-sizes/large-arg.stdout index 67168a3d6ef..e00420d1493 100644 --- a/tests/ui/async-await/future-sizes/large-arg.stdout +++ b/tests/ui/async-await/future-sizes/large-arg.stdout @@ -58,3 +58,45 @@ print-type-size variant `Returned`: 1024 bytes print-type-size upvar `.t`: 1024 bytes print-type-size variant `Panicked`: 1024 bytes print-type-size upvar `.t`: 1024 bytes +print-type-size type: `std::task::Context<'_>`: 32 bytes, alignment: 8 bytes +print-type-size field `.waker`: 8 bytes +print-type-size field `.local_waker`: 8 bytes +print-type-size field `.ext`: 16 bytes +print-type-size field `._marker`: 0 bytes +print-type-size field `._marker2`: 0 bytes +print-type-size type: `std::panic::Location<'_>`: 24 bytes, alignment: 8 bytes +print-type-size field `.filename`: 16 bytes +print-type-size field `.line`: 4 bytes +print-type-size field `.col`: 4 bytes +print-type-size field `._filename`: 0 bytes +print-type-size type: `core::task::wake::ExtData<'_>`: 16 bytes, alignment: 8 bytes +print-type-size variant `Some`: 16 bytes +print-type-size field `.0`: 16 bytes +print-type-size variant `None`: 0 bytes +print-type-size field `.0`: 0 bytes +print-type-size type: `std::panic::AssertUnwindSafe<core::task::wake::ExtData<'_>>`: 16 bytes, alignment: 8 bytes +print-type-size field `.0`: 16 bytes +print-type-size type: `std::ptr::NonNull<str>`: 16 bytes, alignment: 8 bytes +print-type-size field `.pointer`: 16 bytes +print-type-size type: `std::pin::Pin<&mut {async fn body of a<[u8; 1024]>()}>`: 8 bytes, alignment: 8 bytes +print-type-size field `.pointer`: 8 bytes +print-type-size type: `std::pin::Pin<&mut {async fn body of b<[u8; 1024]>()}>`: 8 bytes, alignment: 8 bytes +print-type-size field `.pointer`: 8 bytes +print-type-size type: `std::pin::Pin<&mut {async fn body of c<[u8; 1024]>()}>`: 8 bytes, alignment: 8 bytes +print-type-size field `.pointer`: 8 bytes +print-type-size type: `std::pin::Pin<&mut {async fn body of test()}>`: 8 bytes, alignment: 8 bytes +print-type-size field `.pointer`: 8 bytes +print-type-size type: `std::ptr::DynMetadata<dyn std::any::Any>`: 8 bytes, alignment: 8 bytes +print-type-size field `._vtable_ptr`: 8 bytes +print-type-size field `._phantom`: 0 bytes +print-type-size type: `std::ptr::NonNull<std::ptr::metadata::VTable>`: 8 bytes, alignment: 8 bytes +print-type-size field `.pointer`: 8 bytes +print-type-size type: `std::task::Poll<()>`: 1 bytes, alignment: 1 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `Ready`: 0 bytes +print-type-size field `.0`: 0 bytes +print-type-size variant `Pending`: 0 bytes +print-type-size type: `std::marker::PhantomData<&str>`: 0 bytes, alignment: 1 bytes +print-type-size type: `std::marker::PhantomData<*mut ()>`: 0 bytes, alignment: 1 bytes +print-type-size type: `std::marker::PhantomData<dyn std::any::Any>`: 0 bytes, alignment: 1 bytes +print-type-size type: `std::marker::PhantomData<fn(&()) -> &()>`: 0 bytes, alignment: 1 bytes diff --git a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs deleted file mode 100644 index 1e0576b2186..00000000000 --- a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ only-x86_64 - -fn efiapi(f: extern "efiapi" fn(usize, ...)) { - //~^ ERROR: unstable - f(22, 44); -} -fn sysv(f: extern "sysv64" fn(usize, ...)) { - //~^ ERROR: unstable - f(22, 44); -} -fn win(f: extern "win64" fn(usize, ...)) { - //~^ ERROR: unstable - f(22, 44); -} - -fn main() {} diff --git a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr deleted file mode 100644 index 7ef54b639ad..00000000000 --- a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0658]: C-variadic functions with the "efiapi" calling convention are unstable - --> $DIR/feature-gate-extended_varargs_abi_support.rs:3:14 - | -LL | fn efiapi(f: extern "efiapi" fn(usize, ...)) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #100189 <https://github.com/rust-lang/rust/issues/100189> for more information - = help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: C-variadic functions with the "sysv64" calling convention are unstable - --> $DIR/feature-gate-extended_varargs_abi_support.rs:7:12 - | -LL | fn sysv(f: extern "sysv64" fn(usize, ...)) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #100189 <https://github.com/rust-lang/rust/issues/100189> for more information - = help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: C-variadic functions with the "win64" calling convention are unstable - --> $DIR/feature-gate-extended_varargs_abi_support.rs:11:11 - | -LL | fn win(f: extern "win64" fn(usize, ...)) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #100189 <https://github.com/rust-lang/rust/issues/100189> for more information - = help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/c-variadic/issue-86053-1.rs b/tests/ui/c-variadic/issue-86053-1.rs index 8eeb99a4cc1..537d0263adf 100644 --- a/tests/ui/c-variadic/issue-86053-1.rs +++ b/tests/ui/c-variadic/issue-86053-1.rs @@ -13,6 +13,6 @@ fn ordering4 < 'a , 'b > ( a : , self , self , self , //~| ERROR unexpected `self` parameter in function //~| ERROR unexpected `self` parameter in function //~| ERROR `...` must be the last argument of a C-variadic function - //~| ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR cannot find type `F` in this scope } diff --git a/tests/ui/c-variadic/issue-86053-1.stderr b/tests/ui/c-variadic/issue-86053-1.stderr index 3bf8b7ba5d8..675dfd335c4 100644 --- a/tests/ui/c-variadic/issue-86053-1.stderr +++ b/tests/ui/c-variadic/issue-86053-1.stderr @@ -46,7 +46,7 @@ error: `...` must be the last argument of a C-variadic function LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) { | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/issue-86053-1.rs:11:12 | LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) { diff --git a/tests/ui/c-variadic/same-program-multiple-abis-arm.rs b/tests/ui/c-variadic/same-program-multiple-abis-arm.rs index 1b0bdecabfb..1445bbb47bb 100644 --- a/tests/ui/c-variadic/same-program-multiple-abis-arm.rs +++ b/tests/ui/c-variadic/same-program-multiple-abis-arm.rs @@ -1,4 +1,3 @@ -#![feature(extended_varargs_abi_support)] //@ run-pass //@ only-arm //@ ignore-thumb (this test uses arm assembly) diff --git a/tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs b/tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs index b21accb999e..aff8ab613c4 100644 --- a/tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs +++ b/tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs @@ -1,4 +1,3 @@ -#![feature(extended_varargs_abi_support)] //@ run-pass //@ only-x86_64 diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs index 800dd580af2..ad4fca8252d 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs @@ -71,6 +71,6 @@ extern "cmse-nonsecure-entry" fn wrapped_trait_object( } extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) { - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR requires `va_list` lang_item } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr index f0190671b5a..7aeb6969feb 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr @@ -1,4 +1,4 @@ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/generics.rs:73:53 | LL | extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) { diff --git a/tests/ui/feature-gates/feature-gate-c_variadic.rs b/tests/ui/feature-gates/feature-gate-c_variadic.rs index f189f02a26d..45c68842093 100644 --- a/tests/ui/feature-gates/feature-gate-c_variadic.rs +++ b/tests/ui/feature-gates/feature-gate-c_variadic.rs @@ -2,3 +2,9 @@ pub unsafe extern "C" fn test(_: i32, ap: ...) { } //~^ ERROR C-variadic functions are unstable + +trait Trait { + unsafe extern "C" fn trait_test(_: i32, ap: ...) { } + //~^ ERROR C-variadic functions are unstable + //~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +} diff --git a/tests/ui/feature-gates/feature-gate-c_variadic.stderr b/tests/ui/feature-gates/feature-gate-c_variadic.stderr index 1b6a8c92af5..e30a2f1ede3 100644 --- a/tests/ui/feature-gates/feature-gate-c_variadic.stderr +++ b/tests/ui/feature-gates/feature-gate-c_variadic.stderr @@ -1,3 +1,9 @@ +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention + --> $DIR/feature-gate-c_variadic.rs:7:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) { } + | ^^^^^^^ + error[E0658]: C-variadic functions are unstable --> $DIR/feature-gate-c_variadic.rs:3:1 | @@ -8,6 +14,16 @@ LL | pub unsafe extern "C" fn test(_: i32, ap: ...) { } = help: add `#![feature(c_variadic)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 1 previous error +error[E0658]: C-variadic functions are unstable + --> $DIR/feature-gate-c_variadic.rs:7:5 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #44930 <https://github.com/rust-lang/rust/issues/44930> for more information + = help: add `#![feature(c_variadic)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/frontmatter/frontmatter-whitespace-1.rs b/tests/ui/frontmatter/frontmatter-whitespace-1.rs index 8b6e2d1af84..3b7f762d26e 100644 --- a/tests/ui/frontmatter/frontmatter-whitespace-1.rs +++ b/tests/ui/frontmatter/frontmatter-whitespace-1.rs @@ -1,7 +1,7 @@ --- //~^ ERROR: invalid preceding whitespace for frontmatter opening +//~^^ ERROR: unclosed frontmatter --- -//~^ ERROR: invalid preceding whitespace for frontmatter close #![feature(frontmatter)] diff --git a/tests/ui/frontmatter/frontmatter-whitespace-1.stderr b/tests/ui/frontmatter/frontmatter-whitespace-1.stderr index 37ece27acb2..f16788fa399 100644 --- a/tests/ui/frontmatter/frontmatter-whitespace-1.stderr +++ b/tests/ui/frontmatter/frontmatter-whitespace-1.stderr @@ -10,17 +10,21 @@ note: frontmatter opening should not be preceded by whitespace LL | --- | ^^ -error: invalid preceding whitespace for frontmatter close - --> $DIR/frontmatter-whitespace-1.rs:3:1 +error: unclosed frontmatter + --> $DIR/frontmatter-whitespace-1.rs:1:3 | -LL | --- - | ^^^^^ +LL | / --- +LL | | +LL | | +LL | | --- +LL | | + | |_^ | -note: frontmatter close should not be preceded by whitespace - --> $DIR/frontmatter-whitespace-1.rs:3:1 +note: frontmatter opening here was not closed + --> $DIR/frontmatter-whitespace-1.rs:1:3 | LL | --- - | ^^ + | ^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/frontmatter/frontmatter-whitespace-2.rs b/tests/ui/frontmatter/frontmatter-whitespace-2.rs index e8c100849b4..7a28e5c1b85 100644 --- a/tests/ui/frontmatter/frontmatter-whitespace-2.rs +++ b/tests/ui/frontmatter/frontmatter-whitespace-2.rs @@ -1,4 +1,5 @@ ---cargo +//~^ ERROR: unclosed frontmatter //@ compile-flags: --crate-type lib @@ -6,10 +7,8 @@ fn foo(x: i32) -> i32 { ---x - //~^ ERROR: invalid preceding whitespace for frontmatter close - //~| ERROR: extra characters after frontmatter close are not allowed + //~^ WARNING: use of a double negation [double_negations] } -//~^ ERROR: unexpected closing delimiter: `}` // this test is for the weird case that valid Rust code can have three dashes // within them and get treated as a frontmatter close. diff --git a/tests/ui/frontmatter/frontmatter-whitespace-2.stderr b/tests/ui/frontmatter/frontmatter-whitespace-2.stderr index ada6af0ec04..2ae63cdc6fe 100644 --- a/tests/ui/frontmatter/frontmatter-whitespace-2.stderr +++ b/tests/ui/frontmatter/frontmatter-whitespace-2.stderr @@ -1,26 +1,30 @@ -error: invalid preceding whitespace for frontmatter close - --> $DIR/frontmatter-whitespace-2.rs:8:1 +error: unclosed frontmatter + --> $DIR/frontmatter-whitespace-2.rs:1:1 | -LL | ---x - | ^^^^^^^^ +LL | / ---cargo +... | +LL | | + | |_^ | -note: frontmatter close should not be preceded by whitespace - --> $DIR/frontmatter-whitespace-2.rs:8:1 +note: frontmatter opening here was not closed + --> $DIR/frontmatter-whitespace-2.rs:1:1 | -LL | ---x - | ^^^^ +LL | ---cargo + | ^^^ -error: extra characters after frontmatter close are not allowed - --> $DIR/frontmatter-whitespace-2.rs:8:1 +warning: use of a double negation + --> $DIR/frontmatter-whitespace-2.rs:9:6 | LL | ---x - | ^^^^^^^^ - -error: unexpected closing delimiter: `}` - --> $DIR/frontmatter-whitespace-2.rs:11:1 + | ^^^ + | + = note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages + = note: use `-= 1` if you meant to decrement the value + = note: `#[warn(double_negations)]` on by default +help: add parentheses for clarity | -LL | } - | ^ unexpected closing delimiter +LL | --(-x) + | + + -error: aborting due to 3 previous errors +error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/frontmatter/multifrontmatter-2.rs b/tests/ui/frontmatter/multifrontmatter-2.rs index 33cc30cb465..8e5b45a0bf7 100644 --- a/tests/ui/frontmatter/multifrontmatter-2.rs +++ b/tests/ui/frontmatter/multifrontmatter-2.rs @@ -1,12 +1,12 @@ --- --- -//~^ ERROR: invalid preceding whitespace for frontmatter close --- -//~^ ERROR: expected item, found `-` -// FIXME(frontmatter): make this diagnostic better --- +// hyphens only need to be escaped when at the start of a line +//@ check-pass + #![feature(frontmatter)] fn main() {} diff --git a/tests/ui/frontmatter/multifrontmatter-2.stderr b/tests/ui/frontmatter/multifrontmatter-2.stderr deleted file mode 100644 index ed9ac4029e2..00000000000 --- a/tests/ui/frontmatter/multifrontmatter-2.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: invalid preceding whitespace for frontmatter close - --> $DIR/multifrontmatter-2.rs:2:1 - | -LL | --- - | ^^^^ - | -note: frontmatter close should not be preceded by whitespace - --> $DIR/multifrontmatter-2.rs:2:1 - | -LL | --- - | ^ - -error: expected item, found `-` - --> $DIR/multifrontmatter-2.rs:5:2 - | -LL | --- - | ^ expected item - | - = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html> - -error: aborting due to 2 previous errors - diff --git a/tests/ui/impl-trait/non-defining-uses/as-projection-term.next.stderr b/tests/ui/impl-trait/non-defining-uses/as-projection-term.next.stderr deleted file mode 100644 index 96e242d5d48..00000000000 --- a/tests/ui/impl-trait/non-defining-uses/as-projection-term.next.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: non-defining use of `impl Sized + '_` in the defining scope - --> $DIR/as-projection-term.rs:14:19 - | -LL | prove_proj(|| recur()); - | ^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/impl-trait/non-defining-uses/as-projection-term.rs b/tests/ui/impl-trait/non-defining-uses/as-projection-term.rs index f0cf333b6a1..19f983bab70 100644 --- a/tests/ui/impl-trait/non-defining-uses/as-projection-term.rs +++ b/tests/ui/impl-trait/non-defining-uses/as-projection-term.rs @@ -1,7 +1,7 @@ //@ revisions: current next //@[next] compile-flags: -Znext-solver //@ ignore-compare-mode-next-solver (explicit revisions) -//@[current] check-pass +//@ check-pass fn prove_proj<R>(_: impl FnOnce() -> R) {} fn recur<'a>() -> impl Sized + 'a { @@ -12,6 +12,6 @@ fn recur<'a>() -> impl Sized + 'a { // inference variable at this point, we unify it with `opaque<'1>` and // end up ignoring that defining use as the hidden type is equal to its key. prove_proj(|| recur()); - //[next]~^ ERROR non-defining use of `impl Sized + '_` in the defining scope } + fn main() {} diff --git a/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.current.stderr b/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.current.stderr new file mode 100644 index 00000000000..30424ec58f9 --- /dev/null +++ b/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.current.stderr @@ -0,0 +1,17 @@ +error[E0792]: expected generic type parameter, found `impl Foo` + --> $DIR/double-wrap-with-defining-use.rs:12:26 + | +LL | fn a<T: Foo>(x: T) -> impl Foo { + | - this generic parameter must be used with a generic type parameter +LL | if true { x } else { a(a(x)) } + | ^^^^^^^ + +error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/double-wrap-with-defining-use.rs:12:26 + | +LL | if true { x } else { a(a(x)) } + | ^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.rs b/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.rs index 339277fec37..734b1920772 100644 --- a/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.rs +++ b/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.rs @@ -1,12 +1,17 @@ // Regression test for ICE from issue #140545 // The error message is confusing and wrong, but that's a different problem (#139350) + //@ edition:2018 +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] check-pass trait Foo {} -fn a(x: impl Foo) -> impl Foo { +fn a<T: Foo>(x: T) -> impl Foo { if true { x } else { a(a(x)) } - //~^ ERROR: expected generic type parameter, found `impl Foo` [E0792] - //~| ERROR: type parameter `impl Foo` is part of concrete type but not used in parameter list for the `impl Trait` type alias + //[current]~^ ERROR: expected generic type parameter, found `impl Foo` [E0792] + //[current]~| ERROR: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias } fn main(){} diff --git a/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.stderr b/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.stderr deleted file mode 100644 index 1b02811e31b..00000000000 --- a/tests/ui/impl-trait/non-defining-uses/double-wrap-with-defining-use.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0792]: expected generic type parameter, found `impl Foo` - --> $DIR/double-wrap-with-defining-use.rs:7:26 - | -LL | fn a(x: impl Foo) -> impl Foo { - | -------- this generic parameter must be used with a generic type parameter -LL | if true { x } else { a(a(x)) } - | ^^^^^^^ - -error: type parameter `impl Foo` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/double-wrap-with-defining-use.rs:7:26 - | -LL | if true { x } else { a(a(x)) } - | ^^^^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/impl-trait/non-defining-uses/recursive-call.rs b/tests/ui/impl-trait/non-defining-uses/recursive-call.rs new file mode 100644 index 00000000000..ecddf2cec47 --- /dev/null +++ b/tests/ui/impl-trait/non-defining-uses/recursive-call.rs @@ -0,0 +1,30 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass + +// Regression test for the non-defining use error in `gll`. + +struct Foo; +impl Foo { + fn recur(&self, b: bool) -> impl Sized + '_ { + if b { + let temp = Foo; + temp.recur(false); + // desugars to `Foo::recur(&temp);` + } + + self + } + + fn in_closure(&self) -> impl Sized + '_ { + let _ = || { + let temp = Foo; + temp.in_closure(); + // desugars to `Foo::in_closure(&temp);` + }; + + self + } +} +fn main() {} diff --git a/tests/ui/loop-match/diverges.rs b/tests/ui/loop-match/diverges.rs new file mode 100644 index 00000000000..f1b3ffb2076 --- /dev/null +++ b/tests/ui/loop-match/diverges.rs @@ -0,0 +1,44 @@ +//@ build-pass +//@ compile-flags: -Zvalidate-mir +#![allow(incomplete_features)] +#![feature(loop_match)] +#![crate_type = "lib"] + +// Test that a #[loop_match] without an explicit break from the loop generates valid MIR. + +fn break_to_block_unit() -> u8 { + let mut state = 0; + #[loop_match] + loop { + state = 'blk: { + match state { + _ => 'b: { + break 'b 2; + } + } + } + } +} + +fn break_to_block_value() -> u8 { + let mut state = 0u8; + #[loop_match] + 'a: loop { + state = 'blk: { + match state { + _ => break 'blk state, + } + } + } +} + +fn infinite_a(mut state: u8) { + #[loop_match] + loop { + state = 'blk: { + match state { + a => a, + } + } + } +} diff --git a/tests/ui/mir/issue-83499-input-output-iteration-ice.rs b/tests/ui/mir/issue-83499-input-output-iteration-ice.rs index 78e5c961802..9277994d9b3 100644 --- a/tests/ui/mir/issue-83499-input-output-iteration-ice.rs +++ b/tests/ui/mir/issue-83499-input-output-iteration-ice.rs @@ -5,6 +5,6 @@ fn main() {} fn foo(_: Bar, ...) -> impl {} -//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR cannot find type `Bar` in this scope //~| ERROR at least one trait must be specified diff --git a/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr b/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr index 80a8a94aea4..4a1aa49eb6e 100644 --- a/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr +++ b/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr @@ -1,4 +1,4 @@ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/issue-83499-input-output-iteration-ice.rs:7:16 | LL | fn foo(_: Bar, ...) -> impl {} diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs index 1cd6d13d56b..e7a0248cffa 100644 --- a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs +++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs @@ -4,29 +4,29 @@ fn main() {} fn f1_1(x: isize, ...) {} -//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention fn f1_2(...) {} -//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention extern "C" fn f2_1(x: isize, ...) {} -//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention extern "C" fn f2_2(...) {} -//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention extern "C" fn f2_3(..., x: isize) {} -//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR `...` must be the last argument of a C-variadic function extern "C" fn f3_1(x: isize, ...) {} -//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention extern "C" fn f3_2(...) {} -//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention extern "C" fn f3_3(..., x: isize) {} -//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR `...` must be the last argument of a C-variadic function const unsafe extern "C" fn f4_1(x: isize, ...) {} @@ -35,12 +35,12 @@ const unsafe extern "C" fn f4_1(x: isize, ...) {} const extern "C" fn f4_2(x: isize, ...) {} //~^ ERROR functions cannot be both `const` and C-variadic -//~| ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time const extern "C" fn f4_3(..., x: isize, ...) {} //~^ ERROR functions cannot be both `const` and C-variadic -//~| ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR `...` must be the last argument of a C-variadic function extern "C" { @@ -52,34 +52,34 @@ struct X; impl X { fn i_f1(x: isize, ...) {} - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention fn i_f2(...) {} - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention fn i_f3(..., x: isize, ...) {} - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR `...` must be the last argument of a C-variadic function fn i_f4(..., x: isize, ...) {} - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR `...` must be the last argument of a C-variadic function const fn i_f5(x: isize, ...) {} - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR functions cannot be both `const` and C-variadic //~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time } trait T { fn t_f1(x: isize, ...) {} - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention fn t_f2(x: isize, ...); - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention fn t_f3(...) {} - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention fn t_f4(...); - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention fn t_f5(..., x: isize) {} - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR `...` must be the last argument of a C-variadic function fn t_f6(..., x: isize); - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR `...` must be the last argument of a C-variadic function } diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr index b740cef0200..5379045967a 100644 --- a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr +++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr @@ -1,22 +1,22 @@ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:6:19 | LL | fn f1_1(x: isize, ...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:9:9 | LL | fn f1_2(...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:12:30 | LL | extern "C" fn f2_1(x: isize, ...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20 | LL | extern "C" fn f2_2(...) {} @@ -28,19 +28,19 @@ error: `...` must be the last argument of a C-variadic function LL | extern "C" fn f2_3(..., x: isize) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:18:20 | LL | extern "C" fn f2_3(..., x: isize) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:22:30 | LL | extern "C" fn f3_1(x: isize, ...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:25:20 | LL | extern "C" fn f3_2(...) {} @@ -52,7 +52,7 @@ error: `...` must be the last argument of a C-variadic function LL | extern "C" fn f3_3(..., x: isize) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:28:20 | LL | extern "C" fn f3_3(..., x: isize) {} @@ -70,7 +70,7 @@ error: functions cannot be both `const` and C-variadic LL | const extern "C" fn f4_2(x: isize, ...) {} | ^^^^^ `const` because of this ^^^ C-variadic because of this -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:36:36 | LL | const extern "C" fn f4_2(x: isize, ...) {} @@ -91,7 +91,7 @@ LL | const extern "C" fn f4_3(..., x: isize, ...) {} | | C-variadic because of this | `const` because of this -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:41:26 | LL | const extern "C" fn f4_3(..., x: isize, ...) {} @@ -103,13 +103,13 @@ error: `...` must be the last argument of a C-variadic function LL | fn e_f2(..., x: isize); | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:54:23 | LL | fn i_f1(x: isize, ...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:56:13 | LL | fn i_f2(...) {} @@ -121,7 +121,7 @@ error: `...` must be the last argument of a C-variadic function LL | fn i_f3(..., x: isize, ...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:58:13 | LL | fn i_f3(..., x: isize, ...) {} @@ -133,7 +133,7 @@ error: `...` must be the last argument of a C-variadic function LL | fn i_f4(..., x: isize, ...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:61:13 | LL | fn i_f4(..., x: isize, ...) {} @@ -147,31 +147,31 @@ LL | const fn i_f5(x: isize, ...) {} | | | `const` because of this -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:64:29 | LL | const fn i_f5(x: isize, ...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:71:23 | LL | fn t_f1(x: isize, ...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:73:23 | LL | fn t_f2(x: isize, ...); | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:75:13 | LL | fn t_f3(...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:77:13 | LL | fn t_f4(...); @@ -183,7 +183,7 @@ error: `...` must be the last argument of a C-variadic function LL | fn t_f5(..., x: isize) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:79:13 | LL | fn t_f5(..., x: isize) {} @@ -195,7 +195,7 @@ error: `...` must be the last argument of a C-variadic function LL | fn t_f6(..., x: isize); | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:82:13 | LL | fn t_f6(..., x: isize); diff --git a/tests/ui/print_type_sizes/async.rs b/tests/ui/print_type_sizes/async.rs index 805bccbcf63..951e7cd1012 100644 --- a/tests/ui/print_type_sizes/async.rs +++ b/tests/ui/print_type_sizes/async.rs @@ -1,7 +1,9 @@ -//@ compile-flags: -Z print-type-sizes --crate-type lib +//@ compile-flags: -C panic=abort -Z print-type-sizes --crate-type lib +//@ needs-deterministic-layouts //@ edition:2021 //@ build-pass //@ ignore-pass +//@ only-x86_64 #![allow(dropping_copy_types)] diff --git a/tests/ui/print_type_sizes/async.stdout b/tests/ui/print_type_sizes/async.stdout index 83a6962e4cd..d3d6b6471c6 100644 --- a/tests/ui/print_type_sizes/async.stdout +++ b/tests/ui/print_type_sizes/async.stdout @@ -16,6 +16,35 @@ print-type-size type: `std::mem::MaybeUninit<[u8; 8192]>`: 8192 bytes, alignment print-type-size variant `MaybeUninit`: 8192 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 8192 bytes +print-type-size type: `std::task::Context<'_>`: 32 bytes, alignment: 8 bytes +print-type-size field `.waker`: 8 bytes +print-type-size field `.local_waker`: 8 bytes +print-type-size field `.ext`: 16 bytes +print-type-size field `._marker`: 0 bytes +print-type-size field `._marker2`: 0 bytes +print-type-size type: `std::panic::Location<'_>`: 24 bytes, alignment: 8 bytes +print-type-size field `.filename`: 16 bytes +print-type-size field `.line`: 4 bytes +print-type-size field `.col`: 4 bytes +print-type-size field `._filename`: 0 bytes +print-type-size type: `core::task::wake::ExtData<'_>`: 16 bytes, alignment: 8 bytes +print-type-size variant `Some`: 16 bytes +print-type-size field `.0`: 16 bytes +print-type-size variant `None`: 0 bytes +print-type-size field `.0`: 0 bytes +print-type-size type: `std::panic::AssertUnwindSafe<core::task::wake::ExtData<'_>>`: 16 bytes, alignment: 8 bytes +print-type-size field `.0`: 16 bytes +print-type-size type: `std::ptr::NonNull<str>`: 16 bytes, alignment: 8 bytes +print-type-size field `.pointer`: 16 bytes +print-type-size type: `std::pin::Pin<&mut {async fn body of test()}>`: 8 bytes, alignment: 8 bytes +print-type-size field `.pointer`: 8 bytes +print-type-size type: `std::pin::Pin<&mut {async fn body of wait()}>`: 8 bytes, alignment: 8 bytes +print-type-size field `.pointer`: 8 bytes +print-type-size type: `std::ptr::DynMetadata<dyn std::any::Any>`: 8 bytes, alignment: 8 bytes +print-type-size field `._vtable_ptr`: 8 bytes +print-type-size field `._phantom`: 0 bytes +print-type-size type: `std::ptr::NonNull<std::ptr::metadata::VTable>`: 8 bytes, alignment: 8 bytes +print-type-size field `.pointer`: 8 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes print-type-size field `.value`: 1 bytes print-type-size type: `std::mem::MaybeUninit<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes @@ -32,3 +61,7 @@ print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 0 bytes print-type-size variant `Returned`: 0 bytes print-type-size variant `Panicked`: 0 bytes +print-type-size type: `std::marker::PhantomData<&str>`: 0 bytes, alignment: 1 bytes +print-type-size type: `std::marker::PhantomData<*mut ()>`: 0 bytes, alignment: 1 bytes +print-type-size type: `std::marker::PhantomData<dyn std::any::Any>`: 0 bytes, alignment: 1 bytes +print-type-size type: `std::marker::PhantomData<fn(&()) -> &()>`: 0 bytes, alignment: 1 bytes diff --git a/tests/ui/privacy/private-field-ty-err.stderr b/tests/ui/privacy/private-field-ty-err.stderr index 17d50f24a94..0eecad14cfc 100644 --- a/tests/ui/privacy/private-field-ty-err.stderr +++ b/tests/ui/privacy/private-field-ty-err.stderr @@ -3,6 +3,11 @@ error[E0616]: field `len` of struct `Foo` is private | LL | if x.len { | ^^^ private field + | +help: a method `len` also exists, call it with parentheses + | +LL | if x.len() { + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index 72a9820bb64..4a73a4747ad 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -23,10 +23,10 @@ ast-stats - Path 72 (NN.N%) 1 ast-stats - Struct 72 (NN.N%) 1 ast-stats - Lit 144 (NN.N%) 2 ast-stats - Block 216 (NN.N%) 3 -ast-stats Pat 504 (NN.N%) 7 72 -ast-stats - Struct 72 (NN.N%) 1 -ast-stats - Wild 72 (NN.N%) 1 -ast-stats - Ident 360 (NN.N%) 5 +ast-stats Pat 560 (NN.N%) 7 80 +ast-stats - Struct 80 (NN.N%) 1 +ast-stats - Wild 80 (NN.N%) 1 +ast-stats - Ident 400 (NN.N%) 5 ast-stats GenericParam 480 (NN.N%) 5 96 ast-stats GenericBound 352 (NN.N%) 4 88 ast-stats - Trait 352 (NN.N%) 4 @@ -57,7 +57,7 @@ ast-stats GenericArgs 40 (NN.N%) 1 40 ast-stats - AngleBracketed 40 (NN.N%) 1 ast-stats Crate 40 (NN.N%) 1 40 ast-stats ---------------------------------------------------------------- -ast-stats Total 7_472 129 +ast-stats Total 7_528 129 ast-stats ================================================================ hir-stats ================================================================ hir-stats HIR STATS: input_stats @@ -85,11 +85,11 @@ hir-stats - Ptr 48 (NN.N%) 1 hir-stats - Ref 48 (NN.N%) 1 hir-stats - Path 624 (NN.N%) 13 hir-stats Generics 560 (NN.N%) 10 56 +hir-stats Pat 400 (NN.N%) 5 80 +hir-stats - Struct 80 (NN.N%) 1 +hir-stats - Wild 80 (NN.N%) 1 +hir-stats - Binding 240 (NN.N%) 3 hir-stats GenericParam 400 (NN.N%) 5 80 -hir-stats Pat 360 (NN.N%) 5 72 -hir-stats - Struct 72 (NN.N%) 1 -hir-stats - Wild 72 (NN.N%) 1 -hir-stats - Binding 216 (NN.N%) 3 hir-stats Block 288 (NN.N%) 6 48 hir-stats GenericBound 256 (NN.N%) 4 64 hir-stats - Trait 256 (NN.N%) 4 @@ -119,5 +119,5 @@ hir-stats TraitItemId 8 (NN.N%) 2 4 hir-stats ImplItemId 8 (NN.N%) 2 4 hir-stats ForeignItemId 4 (NN.N%) 1 4 hir-stats ---------------------------------------------------------------- -hir-stats Total 8_584 173 +hir-stats Total 8_624 173 hir-stats ================================================================ diff --git a/tests/ui/suggestions/negative-literal-infered-to-unsigned.rs b/tests/ui/suggestions/negative-literal-infered-to-unsigned.rs new file mode 100644 index 00000000000..39797574b97 --- /dev/null +++ b/tests/ui/suggestions/negative-literal-infered-to-unsigned.rs @@ -0,0 +1,13 @@ +fn main() { + for x in -5..5 { + //~^ ERROR: the trait bound `usize: Neg` is not satisfied + //~| HELP: consider specifying an integer type that can be negative + do_something(x); + } + let x = -5; + //~^ ERROR: the trait bound `usize: Neg` is not satisfied + //~| HELP: consider specifying an integer type that can be negative + do_something(x); +} + +fn do_something(_val: usize) {} diff --git a/tests/ui/suggestions/negative-literal-infered-to-unsigned.stderr b/tests/ui/suggestions/negative-literal-infered-to-unsigned.stderr new file mode 100644 index 00000000000..b49ea224d2b --- /dev/null +++ b/tests/ui/suggestions/negative-literal-infered-to-unsigned.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `usize: Neg` is not satisfied + --> $DIR/negative-literal-infered-to-unsigned.rs:2:14 + | +LL | for x in -5..5 { + | ^^ the trait `Neg` is not implemented for `usize` + | +help: consider specifying an integer type that can be negative + | +LL | for x in -5isize..5 { + | +++++ + +error[E0277]: the trait bound `usize: Neg` is not satisfied + --> $DIR/negative-literal-infered-to-unsigned.rs:7:13 + | +LL | let x = -5; + | ^^ the trait `Neg` is not implemented for `usize` + | +help: consider specifying an integer type that can be negative + | +LL | let x = -5isize; + | +++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/type-alias-impl-trait/split-paths-may-dangle.rs b/tests/ui/type-alias-impl-trait/split-paths-may-dangle.rs new file mode 100644 index 00000000000..61c5342cdbb --- /dev/null +++ b/tests/ui/type-alias-impl-trait/split-paths-may-dangle.rs @@ -0,0 +1,11 @@ +// Regression test for issue #146045 - ensure that the TAIT `SplitPaths` does not +// require the borrowed string to be live. +//@ check-pass +//@ edition:2015 + +pub fn repro() -> Option<std::path::PathBuf> { + let unparsed = std::ffi::OsString::new(); + std::env::split_paths(&unparsed).next() +} + +fn main() {} diff --git a/tests/ui/typeck/suggest-method-name-with-maybe-ty-mismatch-146008.rs b/tests/ui/typeck/suggest-method-name-with-maybe-ty-mismatch-146008.rs new file mode 100644 index 00000000000..671f280e814 --- /dev/null +++ b/tests/ui/typeck/suggest-method-name-with-maybe-ty-mismatch-146008.rs @@ -0,0 +1,14 @@ +struct LlamaModel; + +impl LlamaModel { + fn chat_template(&self) -> Result<&str, ()> { + todo!() + } +} + +fn template_from_str(_x: &str) {} + +fn main() { + let model = LlamaModel; + template_from_str(&model.chat_template); //~ ERROR attempted to take value of method `chat_template` on type `LlamaModel` +} diff --git a/tests/ui/typeck/suggest-method-name-with-maybe-ty-mismatch-146008.stderr b/tests/ui/typeck/suggest-method-name-with-maybe-ty-mismatch-146008.stderr new file mode 100644 index 00000000000..7f5dd0617b1 --- /dev/null +++ b/tests/ui/typeck/suggest-method-name-with-maybe-ty-mismatch-146008.stderr @@ -0,0 +1,14 @@ +error[E0615]: attempted to take value of method `chat_template` on type `LlamaModel` + --> $DIR/suggest-method-name-with-maybe-ty-mismatch-146008.rs:13:30 + | +LL | template_from_str(&model.chat_template); + | ^^^^^^^^^^^^^ method, not a field + | +help: use parentheses to call the method + | +LL | template_from_str(&model.chat_template()); + | ++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0615`. |
