diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 682ba78cddc5f..6e036e59b2349 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3921,6 +3921,12 @@ pub struct Delegation { pub from_glob: bool, } +impl Delegation { + pub fn last_segment_span(&self) -> Span { + self.path.segments.last().unwrap().ident.span + } +} + #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub enum DelegationSuffixes { List(ThinVec<(Ident, Option)>), diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 4a5363b379f8c..a5cd643e3ca76 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -44,22 +44,20 @@ use hir::{BodyId, HirId}; use rustc_abi::ExternAbi; use rustc_ast as ast; use rustc_ast::*; -use rustc_data_structures::fx::FxHashSet; -use rustc_errors::ErrorGuaranteed; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir::attrs::{AttributeKind, InlineAttr}; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, FnDeclFlags}; use rustc_middle::span_bug; -use rustc_middle::ty::Asyncness; +use rustc_middle::ty::{Asyncness, TyCtxt}; use rustc_span::symbol::kw; -use rustc_span::{Ident, Span, Symbol}; -use smallvec::SmallVec; +use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; use crate::delegation::generics::{GenericsGenerationResult, GenericsGenerationResults}; use crate::errors::{CycleInDelegationSignatureResolution, UnresolvedDelegationCallee}; use crate::{ AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, - ResolverAstLoweringExt, + ResolverAstLoweringExt, index_crate, }; mod generics; @@ -105,6 +103,66 @@ static ATTRS_ADDITIONS: &[AttrAdditionInfo] = &[ }, ]; +pub(crate) fn delegations_resolutions( + tcx: TyCtxt<'_>, + _: (), +) -> FxIndexMap> { + let krate = tcx.hir_crate(()); + + let (resolver, ast_crate) = &*krate.delayed_resolver.borrow(); + + // FIXME!!!(fn_delegation): make ast index lifetime same as resolver, + // as it is too bad to reindex whole crate on each delegation lowering. + let ast_index = index_crate(resolver, ast_crate); + + let mut result = FxIndexMap::>::default(); + + for &def_id in &krate.delayed_ids { + let delegation = ast_index[def_id].delegation().expect("processing delegations"); + let span = delegation.last_segment_span(); + + if let Some(info) = resolver.delegation_info(def_id) { + let res = info.resolution_id.map(|id| check_for_cycles(tcx, id, span).map(|_| id)); + result.insert(def_id, res.flatten()); + } else { + tcx.dcx().span_delayed_bug( + span, + format!("delegation resolution record was not found for {def_id:?}"), + ); + } + } + + result +} + +fn check_for_cycles(tcx: TyCtxt<'_>, mut def_id: DefId, span: Span) -> Result<(), ErrorGuaranteed> { + let mut visited: FxHashSet = Default::default(); + + let (resolver, _) = &*tcx.hir_crate(()).delayed_resolver.borrow(); + + loop { + visited.insert(def_id); + + // If def_id is in local crate and it corresponds to another delegation + // it means that we refer to another delegation as a callee, so in order to obtain + // a signature DefId we obtain NodeId of the callee delegation and try to get signature from it. + if let Some(local_id) = def_id.as_local() + && let Some(info) = resolver.delegation_info(local_id) + && let Ok(id) = info.resolution_id + { + def_id = id; + if visited.contains(&def_id) { + return Err(match visited.len() { + 1 => tcx.dcx().emit_err(UnresolvedDelegationCallee { span }), + _ => tcx.dcx().emit_err(CycleInDelegationSignatureResolution { span }), + }); + } + } else { + return Ok(()); + } + } +} + impl<'hir> LoweringContext<'_, 'hir> { fn is_method(&self, def_id: DefId, span: Span) -> bool { match self.tcx.def_kind(def_id) { @@ -119,13 +177,13 @@ impl<'hir> LoweringContext<'_, 'hir> { delegation: &Delegation, item_id: NodeId, ) -> DelegationResults<'hir> { - let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span); + let span = self.lower_span(delegation.last_segment_span()); - // Delegation can be unresolved in illegal places such as function bodies in extern blocks (see #151356) - let sig_id = if let Some(delegation_info) = self.resolver.delegation_info(self.owner.def_id) - { - self.get_sig_id(delegation_info.resolution_id, span) - } else { + let sig_id = self.tcx.delegations_resolutions(()).get(&self.owner.def_id).copied(); + + // Delegation can be missing from the `delegations_resolutions` table + // in illegal places such as function bodies in extern blocks (see #151356). + let Some(Ok(sig_id)) = sig_id else { self.dcx().span_delayed_bug( span, format!("LoweringContext: the delegation {:?} is unresolved", item_id), @@ -134,49 +192,39 @@ impl<'hir> LoweringContext<'_, 'hir> { return self.generate_delegation_error(span, delegation); }; - match sig_id { - Ok(sig_id) => { - self.add_attrs_if_needed(span, sig_id); + self.add_attrs_if_needed(span, sig_id); - let is_method = self.is_method(sig_id, span); + let is_method = self.is_method(sig_id, span); - let (param_count, c_variadic) = self.param_count(sig_id); + let (param_count, c_variadic) = self.param_count(sig_id); - let mut generics = self.uplift_delegation_generics(delegation, sig_id, is_method); + let mut generics = self.uplift_delegation_generics(delegation, sig_id, is_method); - let (body_id, call_expr_id) = self.lower_delegation_body( - delegation, - is_method, - param_count, - &mut generics, - span, - ); + let (body_id, call_expr_id) = + self.lower_delegation_body(delegation, is_method, param_count, &mut generics, span); - let decl = self.lower_delegation_decl( - sig_id, - param_count, - c_variadic, - span, - &generics, - delegation.id, - call_expr_id, - ); + let decl = self.lower_delegation_decl( + sig_id, + param_count, + c_variadic, + span, + &generics, + delegation.id, + call_expr_id, + ); - let sig = self.lower_delegation_sig(sig_id, decl, span); - let ident = self.lower_ident(delegation.ident); + let sig = self.lower_delegation_sig(sig_id, decl, span); + let ident = self.lower_ident(delegation.ident); - let generics = self.arena.alloc(hir::Generics { - has_where_clause_predicates: false, - params: self.arena.alloc_from_iter(generics.all_params()), - predicates: self.arena.alloc_from_iter(generics.all_predicates()), - span, - where_clause_span: span, - }); + let generics = self.arena.alloc(hir::Generics { + has_where_clause_predicates: false, + params: self.arena.alloc_from_iter(generics.all_params()), + predicates: self.arena.alloc_from_iter(generics.all_predicates()), + span, + where_clause_span: span, + }); - DelegationResults { body_id, sig, ident, generics } - } - Err(_) => self.generate_delegation_error(span, delegation), - } + DelegationResults { body_id, sig, ident, generics } } fn add_attrs_if_needed(&mut self, span: Span, sig_id: DefId) { @@ -230,36 +278,6 @@ impl<'hir> LoweringContext<'_, 'hir> { .collect::>() } - fn get_sig_id(&self, mut def_id: DefId, span: Span) -> Result { - let mut visited: FxHashSet = Default::default(); - let mut path: SmallVec<[DefId; 1]> = Default::default(); - - loop { - visited.insert(def_id); - - path.push(def_id); - - // If def_id is in local crate and it corresponds to another delegation - // it means that we refer to another delegation as a callee, so in order to obtain - // a signature DefId we obtain NodeId of the callee delegation and try to get signature from it. - if let Some(local_id) = def_id.as_local() - && let Some(delegation_info) = self.resolver.delegation_info(local_id) - { - def_id = delegation_info.resolution_id; - if visited.contains(&def_id) { - // We encountered a cycle in the resolution, or delegation callee refers to non-existent - // entity, in this case emit an error. - return Err(match visited.len() { - 1 => self.dcx().emit_err(UnresolvedDelegationCallee { span }), - _ => self.dcx().emit_err(CycleInDelegationSignatureResolution { span }), - }); - } - } else { - return Ok(path[0]); - } - } - } - fn get_resolution_id(&self, node_id: NodeId) -> Option { self.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id()) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c861b17c00c6f..18c6d0cf3f864 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -60,6 +60,7 @@ use rustc_hir::{ use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; use rustc_middle::hir::{self as mid_hir}; +use rustc_middle::queries::Providers; use rustc_middle::span_bug; use rustc_middle::ty::{DelegationInfo, PerOwnerResolverData, ResolverAstLowering, TyCtxt}; use rustc_session::errors::add_feature_diagnostics; @@ -91,6 +92,12 @@ mod pat; mod path; pub mod stability; +pub fn provide(providers: &mut Providers) { + providers.hir_crate = lower_to_hir; + providers.lower_delayed_owner = lower_delayed_owner; + providers.delegations_resolutions = delegation::delegations_resolutions; +} + struct LoweringContext<'a, 'hir> { tcx: TyCtxt<'hir>, resolver: &'a ResolverAstLowering<'hir>, @@ -433,6 +440,16 @@ enum AstOwner<'a> { ForeignItem(&'a ast::ForeignItem), } +impl AstOwner<'_> { + fn delegation(&self) -> Option<&ast::Delegation> { + match self { + AstOwner::Item(Item { kind: ItemKind::Delegation(d), .. }) + | AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation(d), .. }, _) => Some(d), + _ => None, + } + } +} + #[derive(Copy, Clone, Debug)] enum TryBlockScope { /// There isn't a `try` block, so a `?` will use `return`. @@ -512,7 +529,7 @@ fn compute_hir_hash( }) } -pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> { +fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> { // Queries that borrow `resolver_for_lowering`. tcx.ensure_done().output_filenames(()); tcx.ensure_done().early_lint_checks(()); @@ -536,13 +553,11 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> { let mut delayed_ids: FxIndexSet = Default::default(); for def_id in ast_index.indices() { - match &ast_index[def_id] { - AstOwner::Item(Item { kind: ItemKind::Delegation { .. }, .. }) - | AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation { .. }, .. }, _) => { - delayed_ids.insert(def_id); - } - _ => lowerer.lower_node(def_id), - }; + if ast_index[def_id].delegation().is_some() { + delayed_ids.insert(def_id); + } else { + lowerer.lower_node(def_id); + } } // Don't hash unless necessary, because it's expensive. @@ -554,7 +569,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> { } /// Lowers an AST owner corresponding to `def_id`, now only delegations are lowered this way. -pub fn lower_delayed_owner(tcx: TyCtxt<'_>, def_id: LocalDefId) { +fn lower_delayed_owner(tcx: TyCtxt<'_>, def_id: LocalDefId) { let krate = tcx.hir_crate(()); let (resolver, krate) = &*krate.delayed_resolver.borrow(); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index fddba21e9eca1..df6f2909796ee 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -877,8 +877,6 @@ pub fn write_interface<'tcx>(tcx: TyCtxt<'tcx>) { pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { let providers = &mut Providers::default(); providers.queries.analysis = analysis; - providers.queries.hir_crate = rustc_ast_lowering::lower_to_hir; - providers.queries.lower_delayed_owner = rustc_ast_lowering::lower_delayed_owner; // `hir_delayed_owner` is fed during `lower_delayed_owner`, by default it returns phantom, // as if this query was not fed it means that `MaybeOwner` does not exist for provided LocalDefId. providers.queries.hir_delayed_owner = |_, _| MaybeOwner::Phantom; @@ -887,6 +885,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { providers.queries.resolutions = |tcx, ()| tcx.resolver_for_lowering_raw(()).1; providers.queries.early_lint_checks = early_lint_checks; providers.queries.env_var_os = env_var_os; + rustc_ast_lowering::provide(&mut providers.queries); limits::provide(&mut providers.queries); proc_macro_decls::provide(&mut providers.queries); rustc_expand::provide(&mut providers.queries); diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 397c0eed1715a..1e0abdcc196fa 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -2069,6 +2069,12 @@ rustc_queries! { desc { "getting delegation user-specified args" } } + query delegations_resolutions(_: ()) -> &'tcx FxIndexMap> { + arena_cache + eval_always + desc { "getting delegations resolutions" } + } + /// Does lifetime resolution on items. Importantly, we can't resolve /// lifetimes directly on things like trait methods, because of trait params. /// See `rustc_resolve::late::lifetimes` for details. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9d9ab24b4d474..8ea14b0c5a28b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -270,7 +270,7 @@ pub struct DelegationInfo { /// Refers to the next element in a delegation resolution chain. /// Usually points to the final resolution, as most "chains" are just /// one step to a trait or an impl. - pub resolution_id: DefId, + pub resolution_id: Result, } #[derive(Clone, Copy, Debug, StableHash)] diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 9e2cfa57e5809..06e5d83eba55b 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3899,24 +3899,24 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.visit_path(&delegation.path); }); - let resolution_id = if is_in_trait_impl { item_id } else { delegation.id }; + let resolution_node_id = if is_in_trait_impl { item_id } else { delegation.id }; let def_id = self .r .partial_res_map - .get(&resolution_id) + .get(&resolution_node_id) .and_then(|r| r.expect_full_res().opt_def_id()); - if let Some(resolution_id) = def_id { - self.r - .delegation_infos - .insert(self.r.current_owner.def_id, DelegationInfo { resolution_id }); - } else { + + let resolution_id = def_id.ok_or_else(|| { self.r.tcx.dcx().span_delayed_bug( delegation.path.span, format!( - "LoweringContext: couldn't resolve node {resolution_id:?} in delegation item", + "LateResolutionVisitor: couldn't resolve node {resolution_node_id:?} in delegation item", ), - ); - }; + ) + }); + + let info = DelegationInfo { resolution_id }; + self.r.delegation_infos.insert(self.r.current_owner.def_id, info); let Some(body) = &delegation.body else { return }; self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 25b9d74417bba..0dd6cd0d6fc3b 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -21,6 +21,7 @@ use crate::core::build_steps::llvm::get_llvm_version; use crate::core::build_steps::run::{get_completion_paths, get_help_path}; use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget; use crate::core::build_steps::test::compiletest::CompiletestMode; +use crate::core::build_steps::test::failed_tests::{RecordFailedTests, SetupFailedTestsFile}; use crate::core::build_steps::tool::{ self, RustcPrivateCompilers, SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, Tool, ToolTargetBuildMode, get_tool_target_compiler, @@ -45,6 +46,7 @@ use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests}; use crate::{CLang, CodegenBackendKind, GitRepo, Mode, PathSet, TestTarget, envify}; mod compiletest; +pub mod failed_tests; /// Runs `cargo test` on various internal tools used by bootstrap. #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -86,6 +88,7 @@ impl Step for CrateBootstrap { fn run(self, builder: &Builder<'_>) { let bootstrap_host = builder.config.host_target; let compiler = builder.compiler(0, bootstrap_host); + let record_failed_tests = builder.ensure(SetupFailedTestsFile); let mut path = self.path.to_str().unwrap(); // Map alias `tidyselftest` back to the actual crate path of tidy. @@ -105,7 +108,7 @@ 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, record_failed_tests); } fn metadata(&self) -> Option { @@ -162,6 +165,7 @@ You can skip linkcheck with --skip src/tools/linkchecker" // Test the linkchecker itself. let bootstrap_host = builder.config.host_target; let compiler = builder.compiler(0, bootstrap_host); + let record_failed_tests = builder.ensure(SetupFailedTestsFile); let cargo = tool::prepare_tool_cargo( builder, @@ -173,7 +177,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, + record_failed_tests, + ); if !builder.test_target.runs_doctests() { return; @@ -365,6 +377,7 @@ impl Step for Cargo { // using stage 1 cargo. So we actually build cargo using the stage 0 compiler, and then // run its tests against the stage 1 compiler (called `tested_compiler` below). builder.ensure(tool::Cargo::from_build_compiler(self.build_compiler, self.host)); + let record_failed_tests = builder.ensure(SetupFailedTestsFile); let tested_compiler = builder.compiler(self.build_compiler.stage + 1, self.host); builder.std(tested_compiler, self.host); @@ -429,7 +442,7 @@ impl Step for Cargo { ); let _time = helpers::timeit(builder); - add_flags_and_try_run_tests(builder, &mut cargo); + add_flags_and_try_run_tests(builder, &mut cargo, record_failed_tests); } fn metadata(&self) -> Option { @@ -468,6 +481,7 @@ impl Step for RustAnalyzer { fn run(self, builder: &Builder<'_>) { let build_compiler = self.compilers.build_compiler(); let target = self.compilers.target(); + let record_failed_tests = builder.ensure(SetupFailedTestsFile); // NOTE: rust-analyzer repo currently (as of 2025-12-11) does not run tests against 32-bit // targets, so we also don't run them in rust-lang/rust CI (because that will just mean that @@ -482,13 +496,14 @@ impl Step for RustAnalyzer { return; } + let suite = "src/tools/rust-analyzer"; let mut cargo = tool::prepare_tool_cargo( builder, build_compiler, Mode::ToolRustcPrivate, target, Kind::Test, - "src/tools/rust-analyzer", + suite, SourceType::InTree, &["in-rust-tree".to_owned()], ); @@ -539,7 +554,15 @@ impl Step for RustAnalyzer { let skip_tests = skip_tests.iter().map(|s| s.as_str()).collect::>(); cargo.add_rustc_lib_path(builder); - run_cargo_test(cargo, skip_tests.as_slice(), &[], "rust-analyzer", target, builder); + run_cargo_test( + cargo, + skip_tests.as_slice(), + &[], + "rust-analyzer", + target, + builder, + record_failed_tests, + ); } fn metadata(&self) -> Option { @@ -578,6 +601,7 @@ impl Step for Rustfmt { fn run(self, builder: &Builder<'_>) { let build_compiler = self.compilers.build_compiler(); let target = self.compilers.target(); + let record_failed_tests = builder.ensure(SetupFailedTestsFile); // FIXME(#156525): `compile::Sysroot::run` intentionally do not copy `rustc-dev` artifacts // until they're requested with `builder.ensure(Rustc)`, relevant for `download-rustc` @@ -601,7 +625,7 @@ impl Step for Rustfmt { cargo.add_rustc_lib_path(builder); - run_cargo_test(cargo, &[], &[], "rustfmt", target, builder); + run_cargo_test(cargo, &[], &[], "rustfmt", target, builder, record_failed_tests); } fn metadata(&self) -> Option { @@ -872,6 +896,7 @@ impl Step for CompiletestTest { /// Runs `cargo test` for compiletest. fn run(self, builder: &Builder<'_>) { let host = self.host; + let record_failed_tests = builder.ensure(SetupFailedTestsFile); // Now that compiletest uses only stable Rust, building it always uses // the stage 0 compiler. However, some of its unit tests need to be able @@ -905,7 +930,15 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the // format, namely that of the staged compiler. cargo.env("TEST_RUSTC", builder.rustc(staged_compiler)); - run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder); + run_cargo_test( + cargo, + &[], + &[], + "compiletest self test", + host, + builder, + record_failed_tests, + ); } } @@ -933,6 +966,7 @@ impl Step for StdarchVerify { fn run(self, builder: &Builder<'_>) { let host = builder.config.host_target; + let record_failed_tests = builder.ensure(SetupFailedTestsFile); let build_compiler = builder.compiler(0, host); let cargo = tool::prepare_tool_cargo( @@ -953,6 +987,7 @@ impl Step for StdarchVerify { Some("stdarch-verify"), host, builder, + record_failed_tests, ); } } @@ -1298,6 +1333,7 @@ impl Step for RustdocGUI { fn run(self, builder: &Builder<'_>) { builder.std(self.test_compiler, self.target); + let record_failed_tests = builder.ensure(SetupFailedTestsFile); let mut cmd = builder.tool_cmd(Tool::RustdocGUITest); @@ -1366,7 +1402,7 @@ impl Step for RustdocGUI { let _time = helpers::timeit(builder); let _guard = builder.msg_test("rustdoc-gui", self.target, self.test_compiler.stage); - try_run_tests(builder, &mut cmd, true); + try_run_tests(builder, &mut cmd, true, record_failed_tests); } fn metadata(&self) -> Option { @@ -1534,6 +1570,7 @@ impl Step for CrateRunMakeSupport { fn run(self, builder: &Builder<'_>) { let host = self.host; let compiler = builder.compiler(0, host); + let record_failed_tests = builder.ensure(SetupFailedTestsFile); let mut cargo = tool::prepare_tool_cargo( builder, @@ -1546,7 +1583,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, + record_failed_tests, + ); } } @@ -1571,6 +1616,7 @@ impl Step for CrateBuildHelper { fn run(self, builder: &Builder<'_>) { let host = self.host; let compiler = builder.compiler(0, host); + let record_failed_tests = builder.ensure(SetupFailedTestsFile); let mut cargo = tool::prepare_tool_cargo( builder, @@ -1583,7 +1629,15 @@ 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, + record_failed_tests, + ); } } @@ -1966,6 +2020,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let target = self.target; let mode = self.mode; let suite = self.suite; + let record_failed_tests = builder.ensure(SetupFailedTestsFile); // Path for test suite let suite_path = self.path; @@ -2614,7 +2669,7 @@ Please disable assertions with `rust.debug-assertions = false`. target, test_compiler.stage, ); - try_run_tests(builder, &mut cmd, false); + try_run_tests(builder, &mut cmd, false, record_failed_tests.clone()); if let Some(compare_mode) = compare_mode { cmd.arg("--compare-mode").arg(compare_mode); @@ -2637,7 +2692,7 @@ Please disable assertions with `rust.debug-assertions = false`. suite, mode, compare_mode, test_compiler.host, target )); let _time = helpers::timeit(builder); - try_run_tests(builder, &mut cmd, false); + try_run_tests(builder, &mut cmd, false, record_failed_tests); } } @@ -3029,6 +3084,7 @@ fn run_cargo_test<'a>( description: impl Into>, target: TargetSelection, builder: &Builder<'_>, + record_failed_tests: RecordFailedTests, ) -> bool { let compiler = cargo.compiler(); let stage = match cargo.mode() { @@ -3051,7 +3107,7 @@ fn run_cargo_test<'a>( }, builder, ); - add_flags_and_try_run_tests(builder, &mut cargo) + add_flags_and_try_run_tests(builder, &mut cargo, record_failed_tests) } /// Given a `cargo test` subcommand, pass it the appropriate test flags given a `builder`. @@ -3181,6 +3237,7 @@ impl Step for Crate { // Prepare sysroot // See [field@compile::Std::force_recompile]. builder.ensure(Std::new(build_compiler, build_compiler.host).force_recompile(true)); + let record_failed_tests = builder.ensure(SetupFailedTestsFile); let mut cargo = if builder.kind == Kind::Miri { if builder.top_stage == 0 { @@ -3275,9 +3332,9 @@ impl Step for Crate { } if crates.iter().any(|crate_| crate_ == "alloc") { crates.push("alloctests".to_owned()); - } - - run_cargo_test(cargo, &[], &crates, &*crate_description(&self.crates), target, builder); + }; + let description = crate_description(&self.crates); + run_cargo_test(cargo, &[], &crates, &*description, target, builder, record_failed_tests); } } @@ -3308,6 +3365,7 @@ impl Step for CrateRustdoc { fn run(self, builder: &Builder<'_>) { let target = self.host; + let record_failed_tests = builder.ensure(SetupFailedTestsFile); let compiler = if builder.download_rustc() { builder.compiler(builder.top_stage, target) @@ -3374,7 +3432,15 @@ 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, + record_failed_tests, + ); } } @@ -3410,6 +3476,7 @@ impl Step for CrateRustdocJsonTypes { fn run(self, builder: &Builder<'_>) { let target = self.target; + let record_failed_tests = builder.ensure(SetupFailedTestsFile); let cargo = tool::prepare_tool_cargo( builder, @@ -3436,6 +3503,7 @@ impl Step for CrateRustdocJsonTypes { "rustdoc-json-types", target, builder, + record_failed_tests, ); } } @@ -3682,6 +3750,7 @@ impl Step for Bootstrap { fn run(self, builder: &Builder<'_>) { let host = builder.config.host_target; let build_compiler = builder.compiler(0, host); + let record_failed_tests = builder.ensure(SetupFailedTestsFile); // Some tests require cargo submodule to be present. builder.build.require_submodule("src/tools/cargo", None); @@ -3713,7 +3782,7 @@ impl Step for Bootstrap { cargo.env("INSTA_UPDATE", "always"); } - run_cargo_test(cargo, &[], &[], None, host, builder); + run_cargo_test(cargo, &[], &[], None, host, builder, record_failed_tests); } fn make_run(run: RunConfig<'_>) { @@ -3850,6 +3919,7 @@ impl Step for RustInstaller { fn run(self, builder: &Builder<'_>) { let bootstrap_host = builder.config.host_target; let build_compiler = builder.compiler(0, bootstrap_host); + let record_failed_tests = builder.ensure(SetupFailedTestsFile); let cargo = tool::prepare_tool_cargo( builder, build_compiler, @@ -3862,7 +3932,7 @@ impl Step for RustInstaller { ); let _guard = builder.msg_test("rust-installer", bootstrap_host, 1); - run_cargo_test(cargo, &[], &[], None, bootstrap_host, builder); + run_cargo_test(cargo, &[], &[], None, bootstrap_host, builder, record_failed_tests); // 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 @@ -4229,6 +4299,7 @@ impl Step for TestFloatParse { // 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); + let record_failed_tests = builder.ensure(SetupFailedTestsFile); // Run any unit tests in the crate let mut cargo_test = tool::prepare_tool_cargo( @@ -4243,7 +4314,15 @@ impl Step for TestFloatParse { ); cargo_test.allow_features(TEST_FLOAT_PARSE_ALLOW_FEATURES); - run_cargo_test(cargo_test, &[], &[], "test-float-parse", target, builder); + run_cargo_test( + cargo_test, + &[], + &[], + "test-float-parse", + target, + builder, + record_failed_tests, + ); // Run the actual parse tests. let mut cargo_run = tool::prepare_tool_cargo( @@ -4325,6 +4404,7 @@ impl Step for RemoteTestClientTests { fn run(self, builder: &Builder<'_>) { let bootstrap_host = builder.config.host_target; let compiler = builder.compiler(0, bootstrap_host); + let record_failed_tests = builder.ensure(SetupFailedTestsFile); let cargo = tool::prepare_tool_cargo( builder, @@ -4337,6 +4417,14 @@ impl Step for RemoteTestClientTests { &[], ); - run_cargo_test(cargo, &[], &[], "remote-test-client", bootstrap_host, builder); + run_cargo_test( + cargo, + &[], + &[], + "remote-test-client", + bootstrap_host, + builder, + record_failed_tests, + ); } } diff --git a/src/bootstrap/src/core/build_steps/test/failed_tests.rs b/src/bootstrap/src/core/build_steps/test/failed_tests.rs new file mode 100644 index 0000000000000..8be6e50fd3db1 --- /dev/null +++ b/src/bootstrap/src/core/build_steps/test/failed_tests.rs @@ -0,0 +1,110 @@ +use std::collections::BTreeSet; +use std::fs::{self, File}; +use std::io::{BufRead, BufReader, ErrorKind}; +use std::path::{Path, PathBuf}; + +use crate::core::builder::{Builder, ShouldRun, Step}; +use crate::t; + +#[derive(Clone)] +pub struct RecordFailedTests { + failed_tests_path: Option, +} + +impl RecordFailedTests { + pub fn path(&self) -> Option<&Path> { + self.failed_tests_path.as_deref() + } +} + +/// This step is run as a dependency of most testing steps. +/// Upon running, a file is created for failed tests to be recorded in if `--record` is passed on +/// the command line. +/// +/// This step is the only way to get access to a token type called [`RecordFailedTests`]. +/// Having this token type signifies the fact that a file was created to store failed tests in, +/// and is required to create a `Renderer`, the type that renders the outputs of tests. +/// +/// If `--rerun` isn't passed, or we're in dry-run mode, running this step is a no-op, +/// and the `RecordFailedTest` type doesn't (need to) signify anything. +#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] +pub struct SetupFailedTestsFile; +impl Step for SetupFailedTestsFile { + type Output = RecordFailedTests; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.never() + } + + fn run(self, builder: &Builder<'_>) -> Self::Output { + if !builder.config.cmd.record() || builder.config.dry_run() { + return RecordFailedTests { failed_tests_path: None }; + } + + let failed_tests_path = builder.config.record_failed_tests_path.clone(); + println!( + "setting up tracking of failed tests in {} (`--record` was passed)", + failed_tests_path.display() + ); + if failed_tests_path.exists() { + println!("deleting previously recorded failed tests"); + t!(fs::remove_file(&failed_tests_path)); + } + RecordFailedTests { failed_tests_path: Some(failed_tests_path) } + } +} + +pub fn collect_previously_failed_tests(failed_tests_file_path: &PathBuf) -> Vec { + let mut paths = BTreeSet::new(); + + println!( + "`--rerun` passed so looking for failed tests in {}", + failed_tests_file_path.display() + ); + + let lines: Vec = match File::open(failed_tests_file_path) { + Ok(f) => t!(BufReader::new(f).lines().collect()), + Err(e) if e.kind() == ErrorKind::NotFound => { + println!( + "WARNING: failed tests file doesn't exist: `--rerun` only makes sense after a previous test run with `--record`" + ); + return Vec::new(); + } + Err(e) => t!(Err(e)), + }; + + const MAX_RERUN_PRINTS: usize = 10; + + for line in lines { + let trimmed = line.as_str().trim(); + let without_revision = + trimmed.rsplit_once("#").map(|(before, _)| before).unwrap_or(trimmed); + let without_suite_prefix = without_revision + .strip_prefix("[") + .and_then(|rest| rest.split_once("]")) + .map(|(_, after)| after.trim()) + .unwrap_or(without_revision); + + let failed_test_path = PathBuf::from(without_suite_prefix.to_string()); + if paths.insert(failed_test_path.clone()) { + if paths.len() == 1 { + println!("rerunning previously failed tests:"); + } + if paths.len() <= MAX_RERUN_PRINTS { + println!(" {}", failed_test_path.display()); + } + } + } + + if paths.len() > MAX_RERUN_PRINTS { + println!(" and {} more...", paths.len() - MAX_RERUN_PRINTS) + } + + if paths.is_empty() { + println!( + "WARNING: failed tests file doesn't contain any failed tests: `--rerun` only makes sense after a previous test run with `--record`" + ); + } + + paths.into_iter().collect() +} diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index b933e668c26ae..5a9c7264c006f 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -30,6 +30,7 @@ use tracing::{instrument, span}; use crate::core::build_steps::llvm; use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS; +use crate::core::build_steps::test::failed_tests::collect_previously_failed_tests; pub use crate::core::config::flags::Subcommand; use crate::core::config::flags::{Color, Flags, Warnings}; use crate::core::config::target_selection::TargetSelectionList; @@ -125,6 +126,7 @@ pub struct Config { pub stage0_metadata: build_helper::stage0_parser::Stage0, pub android_ndk: Option, pub optimized_compiler_builtins: CompilerBuiltins, + pub record_failed_tests_path: PathBuf, pub stdout_is_tty: bool, pub stderr_is_tty: bool, @@ -507,6 +509,7 @@ impl Config { dist_stage: build_dist_stage, bench_stage: build_bench_stage, patch_binaries_for_nix: build_patch_binaries_for_nix, + record_failed_tests_path: build_record_failed_tests_path, // This field is only used by bootstrap.py metrics: _, android_ndk: build_android_ndk, @@ -1305,6 +1308,19 @@ impl Config { ); let verbose_tests = rust_verbose_tests.unwrap_or(exec_ctx.is_verbose()); + let record_failed_tests_path = + out.join(build_record_failed_tests_path.unwrap_or_else(|| "failed-tests".to_string())); + + let paths = { + let mut paths = Vec::new(); + if flags_cmd.rerun() { + paths = collect_previously_failed_tests(&record_failed_tests_path); + } else { + paths.extend(flags_paths); + } + paths + }; + Config { // tidy-alphabetical-start android_ndk: build_android_ndk, @@ -1435,13 +1451,14 @@ impl Config { out, patch_binaries_for_nix: build_patch_binaries_for_nix, path_modification_cache, - paths: flags_paths, + paths, prefix: install_prefix.map(PathBuf::from), print_step_rusage: build_print_step_rusage.unwrap_or(false), print_step_timings: build_print_step_timings.unwrap_or(false), profiler: build_profiler.unwrap_or(false), python: build_python.map(PathBuf::from), quiet: flags_quiet, + record_failed_tests_path, reproducible_artifacts: flags_reproducible_artifact, reuse: build_reuse.map(PathBuf::from), rust_analyzer_info, diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index dce8a4c09a7e4..bf171f1de34e0 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -440,6 +440,15 @@ pub enum Subcommand { #[arg(long)] #[doc(hidden)] no_doc: bool, + + /// Record all the failed tests in a file in the build directory. + /// + /// On subsequent invocations, this set of tests can be rerun by passing `--rerun` + #[arg(long)] + record: bool, + /// Rerun tests that previously failed, and stored with `--record`. + #[arg(long)] + rerun: bool, }, /// Build and run some test suites *in Miri* Miri { @@ -723,6 +732,20 @@ impl Subcommand { _ => false, } } + + pub fn record(&self) -> bool { + match self { + Subcommand::Test { record, .. } => *record, + _ => false, + } + } + + pub fn rerun(&self) -> bool { + match self { + Subcommand::Test { rerun, .. } => *rerun, + _ => false, + } + } } /// Returns the shell completion for a given shell, if the result differs from the current diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs index 27bf753f6914d..ed20a2958e382 100644 --- a/src/bootstrap/src/core/config/toml/build.rs +++ b/src/bootstrap/src/core/config/toml/build.rs @@ -78,6 +78,7 @@ define_config! { tidy_extra_checks: Option = "tidy-extra-checks", ccache: Option = "ccache", exclude: Option> = "exclude", + record_failed_tests_path: Option = "record_failed_tests_path", } } diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 331403f959b4c..566ad003ebe01 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -621,6 +621,11 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "`x.py` stopped accepting partial argument names. Use full names to avoid errors.", }, + ChangeInfo { + change_id: 154586, + severity: ChangeSeverity::Info, + summary: "New option `build.record_failed_tests_path` to store failed tests when passing `--record`. These can be rerun with `--rerun`.", + }, ChangeInfo { change_id: 154587, severity: ChangeSeverity::Info, diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 1d133a9c9e2f3..9062760a74fd5 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -6,12 +6,14 @@ //! and rustc) libtest doesn't include the rendered human-readable output as a JSON field. We had //! to reimplement all the rendering logic in this module because of that. +use std::fs::File; use std::io::{BufRead, BufReader, Read, Write}; use std::process::ChildStdout; use std::time::Duration; use termcolor::{Color, ColorSpec, WriteColor}; +use crate::core::build_steps::test::failed_tests::RecordFailedTests; use crate::core::builder::Builder; use crate::utils::exec::BootstrapCommand; @@ -20,21 +22,23 @@ const TERSE_TESTS_PER_LINE: usize = 88; pub(crate) fn add_flags_and_try_run_tests( builder: &Builder<'_>, cmd: &mut BootstrapCommand, + record_failed_tests: RecordFailedTests, ) -> bool { if !cmd.get_args().any(|arg| arg == "--") { cmd.arg("--"); } cmd.args(["-Z", "unstable-options", "--format", "json"]); - try_run_tests(builder, cmd, false) + try_run_tests(builder, cmd, false, record_failed_tests) } pub(crate) fn try_run_tests( builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool, + record_failed_tests: RecordFailedTests, ) -> bool { - if run_tests(builder, cmd, stream) { + if run_tests(builder, cmd, stream, record_failed_tests) { return true; } @@ -47,7 +51,12 @@ pub(crate) fn try_run_tests( false } -fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> bool { +fn run_tests( + builder: &Builder<'_>, + cmd: &mut BootstrapCommand, + stream: bool, + record_failed_tests: RecordFailedTests, +) -> bool { builder.do_if_verbose(|| println!("running: {cmd:?}")); let Some(mut streaming_command) = cmd.stream_capture_stdout(&builder.config.exec_ctx) else { @@ -56,7 +65,8 @@ fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> // This runs until the stdout of the child is closed, which means the child exited. We don't // run this on another thread since the builder is not Sync. - let renderer = Renderer::new(streaming_command.stdout.take().unwrap(), builder); + let renderer = + Renderer::new(streaming_command.stdout.take().unwrap(), builder, record_failed_tests); if stream { renderer.stream_all(); } else { @@ -87,10 +97,30 @@ struct Renderer<'a> { ignored_tests: usize, terse_tests_in_line: usize, ci_latest_logged_percentage: f64, + + failed_tests: Option, } impl<'a> Renderer<'a> { - fn new(stdout: ChildStdout, builder: &'a Builder<'a>) -> Self { + fn new( + stdout: ChildStdout, + builder: &'a Builder<'a>, + record_failed_tests: RecordFailedTests, + ) -> Self { + let failed_tests = record_failed_tests.path().and_then(|path| { + // create the file (overwriting any previous) to get ready to record new failed tests + match File::options().create(true).append(true).truncate(false).open(path) { + Ok(f) => Some(f), + Err(e) => { + println!( + "Couldn't open file {} to write test failures to: {e}. (attempted because `--record` was passed). Test failures will not be recorded.", + path.display() + ); + None + } + } + }); + Self { stdout: BufReader::new(stdout), benches: Vec::new(), @@ -102,6 +132,7 @@ impl<'a> Renderer<'a> { ignored_tests: 0, terse_tests_in_line: 0, ci_latest_logged_percentage: 0.0, + failed_tests, } } @@ -268,6 +299,13 @@ impl<'a> Renderer<'a> { for failure in &self.failures { println!(" {}", failure.name); } + + if self.failed_tests.is_some() { + println!( + "This list of test failures was recorded.\nUse `x test --rerun` to retry just these {} failed tests.", + self.failures.len(), + ) + } } if !self.benches.is_empty() { @@ -360,6 +398,13 @@ impl<'a> Renderer<'a> { } Message::Test(TestMessage::Failed(outcome)) => { self.render_test_outcome(Outcome::Failed, &outcome); + if let Some(failed_tests) = &mut self.failed_tests + && let Err(e) = writeln!(failed_tests, "{}", outcome.name) + { + eprintln!( + "failed to write test failure to file: {e} (attempted because `--record` was passed)" + ); + } self.failures.push(outcome); } Message::Test(TestMessage::Timeout { name }) => { diff --git a/src/doc/rustc-dev-guide/ci/sembr/Cargo.lock b/src/doc/rustc-dev-guide/ci/sembr/Cargo.lock index 4defe49579f3b..36a50dec5a70a 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/Cargo.lock +++ b/src/doc/rustc-dev-guide/ci/sembr/Cargo.lock @@ -43,22 +43,22 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.10" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys", ] [[package]] @@ -347,7 +347,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -356,15 +356,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-sys" version = "0.61.2" @@ -373,68 +364,3 @@ checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ "windows-link", ] - -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index d33dd7b83a6a7..15aba34317178 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -f2b291d902bfde7d7f209fc3a64908134bcef201 +49b19d32b9f01a5aa606f3bf2e90e6e0aa462c03 diff --git a/src/doc/rustc-dev-guide/src/autodiff/debugging.md b/src/doc/rustc-dev-guide/src/autodiff/debugging.md index 3b2278f1a0759..627d36b1c68b4 100644 --- a/src/doc/rustc-dev-guide/src/autodiff/debugging.md +++ b/src/doc/rustc-dev-guide/src/autodiff/debugging.md @@ -28,7 +28,7 @@ The actual numbers will depend on your code. To confirm that your previous step worked, we will use llvm's `opt` tool. Find your path to the opt binary, with a path similar to `/rust/build//ci-llvm/bin/opt`. If you build LLVM from source, you'll likely need to replace `ci-llvm` with `build`. Also find `llvmenzyme-21.` path, similar to `/rust/build/target-triple/enzyme/build/enzyme/llvmenzyme-21`. Please keep in mind that llvm frequently updates it's llvm backend, so the version number might be higher (20, 21, ...). Once you have both, run the following command: ```sh - out.ll -load-pass-plugin=/path/to/build//stage1/lib/libEnzyme-21.so -passes="enzyme" -enzyme-strict-aliasing=0 -s + out.ll -load-pass-plugin=/path/to/build//stage1/lib/libEnzyme-21.so -passes="enzyme" -enzyme-strict-aliasing=0 -S ``` This command might fail for future versions or on your system, in which case you should replace libEnzyme-21.so with LLVMEnzyme-21.so. Look at the Enzyme docs for instructions on how to build it. You might need to also adjust how to build your LLVM version. @@ -41,7 +41,7 @@ If you fail to get the same error, please open an issue in the rust repository. First find your `llvm-extract` binary, it's in the same folder as your opt binary. then run: ```sh - -s --func= --recursive --rfunc="enzyme_autodiff*" --rfunc="enzyme_fwddiff*" --rfunc= out.ll -o mwe.ll + -S --func= --recursive --rfunc="enzyme_autodiff*" --rfunc="enzyme_fwddiff*" --rfunc= out.ll -o mwe.ll ``` This command creates `mwe.ll`, a minimal working example. diff --git a/src/doc/rustc-dev-guide/src/autodiff/installation.md b/src/doc/rustc-dev-guide/src/autodiff/installation.md index a1e802ffaea5e..b68675397f230 100644 --- a/src/doc/rustc-dev-guide/src/autodiff/installation.md +++ b/src/doc/rustc-dev-guide/src/autodiff/installation.md @@ -13,18 +13,13 @@ Please open an issue if you want to help enabling automatic builds for your pref ## Installation guide -If you want to use `std::autodiff` and don't plan to contribute PR's to the project, then we recommend to just use your existing nightly installation and download the missing component. -In the future, rustup will be able to do it for you. -For now, you'll have to manually download and copy it. - -1) On our github repository, find the last merged PR: [`Repo`] -2) Scroll down to the lower end of the PR, where you'll find a rust-bors message saying `Test successful` with a `CI` link. -3) Click on the `CI` link, and grep for your target. E.g. `dist-x86_64-linux` or `dist-aarch64-llvm-mingw` and click `Load summary`. -4) Under the `CI artifacts` section, find the `enzyme-nightly` artifact, download, and unpack it. -5) Copy the artifact (libEnzyme-22.so for linux, libEnzyme-22.dylib for apple, etc.), which should be in a folder named `enzyme-preview`, to your rust toolchain directory. E.g. for linux: `cp ~/Downloads/enzyme-nightly-x86_64-unknown-linux-gnu/enzyme-preview/lib/rustlib/x86_64-unknown-linux-gnu/lib/libEnzyme-22.so ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib` - -Apple support was temporarily reverted, due to downstream breakages. -Please (currently) build it from source. +If you want to use `std::autodiff` on Linux or Windows and don't plan to contribute PR's to the project, then we recommend to just use your existing nightly installation and download the missing component. Please run: + +```console +rustup +nightly component add enzyme +``` + +Apple support was temporarily reverted, due to downstream breakages. Please build it from source till we can re-enable it. ## Installation guide for Nix user. diff --git a/src/doc/rustc-dev-guide/src/autodiff/internals.md b/src/doc/rustc-dev-guide/src/autodiff/internals.md index e381b091e898a..b9753c9dc1f27 100644 --- a/src/doc/rustc-dev-guide/src/autodiff/internals.md +++ b/src/doc/rustc-dev-guide/src/autodiff/internals.md @@ -15,7 +15,7 @@ fn main() { } ``` -The detailed documentation for the `std::autodiff` module is available at [std::autodiff](https://doc.rust-lang.org/std/autodiff/index.html). +The detailed documentation for the `std::autodiff` module is available at [std::autodiff](https://doc.rust-lang.org/nightly/std/autodiff/index.html). Differentiable programming is used in various fields like numerical computing, [solid mechanics][ratel], [computational chemistry][molpipx], [fluid dynamics][waterlily] or for Neural Network training via Backpropagation, [ODE solver][diffsol], [differentiable rendering][libigl], [quantum computing][catalyst], and climate simulations. @@ -25,3 +25,12 @@ Differentiable programming is used in various fields like numerical computing, [ [diffsol]: https://github.com/martinjrobins/diffsol [libigl]: https://github.com/alecjacobson/libigl-enzyme-example?tab=readme-ov-file#run [catalyst]: https://github.com/PennyLaneAI/catalyst + + +`std::autodiff` is currently based on Enzyme, an LLVM based tool for automatic differentation. There are three main reasons for relying on compiler based autodiff: + +- **Usability**: Current autodiff crates do not support normal Rust programs. They either enforce a custom DSL, require the usage of library provided types (instead of e.g. slices or arrays), or are limited to scalar functions. Compiler based autodiff allows users to write normal Rust code, including arrays, slices, user-defined structs and enums, control flow, and more. +- **Performance**: Most existing Rust autodiff approaches have a constant overhead per operation. This can easily be amortized for ML applications which have few expensive operations on large tensors. It is, however, often unacceptable for applications in the HPC or scientific computing field. By working on (optimized) LLVM IR, compiler based autodiff can achieve [significantly][Enzyme] better performance in those cases. +- **Features**: By operating on such a low level and sharing the implementation with other LLVM based languages, we can leverage the large amount of work already done in the Enzyme project. For example, we can support Rust code calling MPI routines, or GPU code, including libraries like CuBLAS. + +[Enzyme]: https://dl.acm.org/doi/10.5555/3495724.3496770 diff --git a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md index 317b7c2564cbc..fccc3600f13b6 100644 --- a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md +++ b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md @@ -45,6 +45,12 @@ git clone https://github.com/rust-lang/rust.git cd rust ``` +> **NOTE**: On Windows, antivirus scanning can make Git and build commands +> noticeably slower in a large checkout. If that happens, consider adding only +> the Rust checkout directory to the +> [Windows Security exclusion list][windows-security-exclusions]. +> Avoid adding broader exclusions than needed. + ### Partial clone the repository Due to the size of the repository, cloning on a slower internet connection can take a long time, @@ -97,6 +103,7 @@ This chapter focuses on the basics to be productive, but if you want to learn more about `x.py`, [read this chapter][bootstrap]. [bootstrap]: ./bootstrapping/intro.md +[windows-security-exclusions]: https://support.microsoft.com/windows/add-an-exclusion-to-windows-security-811816c0-4dfd-af4a-47e4-c301afe13b26 Also, using `x` rather than `x.py` is recommended as: @@ -279,6 +286,16 @@ Instead, you can build a specific component by providing its name, like this: If you choose the `library` profile when running `x setup`, you can omit `--stage 1` (it's the default). +If you want to build a tool, you can use: + +```bash +./x build src/tools/cargo +``` + +You can also check the [the section on tool tests][tool-tests-link]. + +[tool-tests-link]: ../tests/intro.md#tool-tests + ## Creating a rustup toolchain Once you have successfully built `rustc`, you will have created a bunch diff --git a/src/doc/rustc-dev-guide/src/building/quickstart.md b/src/doc/rustc-dev-guide/src/building/quickstart.md index 42058246cd05f..ca645f94fd9f1 100644 --- a/src/doc/rustc-dev-guide/src/building/quickstart.md +++ b/src/doc/rustc-dev-guide/src/building/quickstart.md @@ -40,6 +40,12 @@ compiler toolchain. You can use it with rustup by linking it. rustup toolchain link stage1 build/host/stage1 ``` +**NOTE**: If you use `./x setup tools`, the default stage will be set to 2 instead of 1. +Adjust your command accordingly: +```sh +rustup toolchain link stage2 build/host/stage2 +``` + Now you have a toolchain called `stage1` linked to your build. You can use it to test the compiler. diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 7f4779515b13c..4e292c5476d1c 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -255,6 +255,9 @@ It is also perfectly fine (and even encouraged!) to use the CI to test your changes if it can help your productivity. In particular, we don't recommend running the full `./x test` suite locally, since it takes a very long time to execute. +See the [Testing with CI] chapter for using Rust's CI to test your changes. + +[Testing with CI]: https://rustc-dev-guide.rust-lang.org/tests/ci.html#testing-with-ci ### r+ diff --git a/src/doc/rustc-dev-guide/src/implementing-new-features.md b/src/doc/rustc-dev-guide/src/implementing-new-features.md index e5a6d03f43fdd..4a23188393d1e 100644 --- a/src/doc/rustc-dev-guide/src/implementing-new-features.md +++ b/src/doc/rustc-dev-guide/src/implementing-new-features.md @@ -1,4 +1,3 @@ - # Implementing new language features @@ -191,7 +190,7 @@ The below steps needs to be followed in order to implement a new unstable featur If the feature gate is not set, you should either maintain the pre-feature behavior or raise an error, depending on what makes sense. - Errors should generally use [`rustc_session::parse::feature_err`]. + Errors should generally use [`rustc_session::errors::feature_err`]. For an example of adding an error, see [#81015]. For features introducing new syntax, pre-expansion gating should be used instead. @@ -221,7 +220,7 @@ The below steps needs to be followed in order to implement a new unstable featur [`GatedSpans`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/parse/struct.GatedSpans.html [#81015]: https://github.com/rust-lang/rust/pull/81015 -[`rustc_session::parse::feature_err`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/parse/fn.feature_err.html +[`rustc_session::errors::feature_err`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/errors/fn.feature_err.html [`rustc_ast_passes::feature_gate::check_crate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_passes/feature_gate/fn.check_crate.html [value the stability of Rust]: https://github.com/rust-lang/rfcs/blob/master/text/1122-language-semver.md [stability in code]: #stability-in-code diff --git a/src/doc/rustc-dev-guide/src/macro-expansion.md b/src/doc/rustc-dev-guide/src/macro-expansion.md index 60067c4f85c37..40b6ef27f9b82 100644 --- a/src/doc/rustc-dev-guide/src/macro-expansion.md +++ b/src/doc/rustc-dev-guide/src/macro-expansion.md @@ -76,15 +76,14 @@ If we can't make progress in an iteration, this represents a compile error. an AST, which may produce parse errors. - During expansion, we create [`SyntaxContext`]s (hierarchy 2) (see [Hygiene][hybelow] below). - - These three passes happen one after another on every AST fragment + - These two passes happen one after another on every AST fragment freshly expanded from a macro: - [`NodeId`]s are assigned by [`InvocationCollector`]. This also collects new macro calls from this new AST piece and adds them to the queue. - - ["Def paths"][defpath] are created and [`DefId`]s are - assigned to them by [`DefCollector`]. - - Names are put into modules (from the resolver's point of - view) by [`BuildReducedGraphVisitor`]. + - [`DefCollector`] creates ["Def paths"][defpath], assigns the + corresponding [`DefId`]s, and also builds the reduced graph + (putting names into modules from the resolver's point of view). 3. After expanding a single macro and integrating its output, continue to the next iteration of [`fully_expand_fragment`][fef]. 5. If it's not resolved: @@ -92,7 +91,6 @@ If we can't make progress in an iteration, this represents a compile error. 2. Continue to next iteration... [`AstFragment`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_expand/expand/enum.AstFragment.html -[`BuildReducedGraphVisitor`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/build_reduced_graph/struct.BuildReducedGraphVisitor.html [`DefCollector`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/def_collector/struct.DefCollector.html [`DefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html [`ExpnId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/hygiene/struct.ExpnId.html diff --git a/src/doc/rustc-dev-guide/src/normalization.md b/src/doc/rustc-dev-guide/src/normalization.md index b458b04c17194..66cbec807cb4e 100644 --- a/src/doc/rustc-dev-guide/src/normalization.md +++ b/src/doc/rustc-dev-guide/src/normalization.md @@ -164,7 +164,6 @@ In this example: When interfacing with the type system it will often be the case that it's necessary to request a type be normalized. There are a number of different entry points to the underlying normalization logic and each entry point should only be used in specific parts of the compiler. - An additional complication is that the compiler is currently undergoing a transition from the old trait solver to the new trait solver. As part of this transition our approach to normalization in the compiler has changed somewhat significantly, resulting in some normalization entry points being "old solver only" slated for removal in the long-term once the new solver has stabilized. The transition can be tracked via the [WG-trait-system-refactor](https://github.com/rust-lang/rust/labels/WG-trait-system-refactor) label in Github. diff --git a/src/doc/rustc-dev-guide/src/offload/usage.md b/src/doc/rustc-dev-guide/src/offload/usage.md index 6d406ec4cc73b..80c2288eba4c1 100644 --- a/src/doc/rustc-dev-guide/src/offload/usage.md +++ b/src/doc/rustc-dev-guide/src/offload/usage.md @@ -54,22 +54,28 @@ fn main() { ``` ## Compile instructions -It is important to use a clang compiler build on the same llvm as rustc. +It is important to use a clang compiler build on the same LLVM as rustc. Just calling clang without the full path will likely use your system clang, which probably will be incompatible. So either substitute clang/lld invocations below with absolute path, or set your `PATH` accordingly. -First we generate the device (gpu) code. -Replace the target-cpu with the right code for your gpu. +First we generate the device (GPU) code. + +
+ +Replace the `target-cpu` (gfx90a) with the right code for your GPU. These are often referred to as "LLVM target names"[^list]. + +
+ ``` RUSTFLAGS="-Ctarget-cpu=gfx90a --emit=llvm-bc,llvm-ir -Zoffload=Device -Csave-temps -Zunstable-options" cargo +offload build -Zunstable-options -r -v --target amdgcn-amd-amdhsa -Zbuild-std=core ``` You might afterwards need to copy your target/release/deps/.bc to lib.bc for now, before the next step. -Now we generate the host (cpu) code. +Now we generate the host (CPU) code. ``` -RUSTFLAGS="--emit=llvm-bc,llvm-ir -Csave-temps -Zoffload=Host=/p/lustre1/drehwald1/prog/offload/r/target/amdgcn-amd-amdhsa/release/deps/host.out -Zunstable-options" cargo +offload build -r +RUSTFLAGS="--emit=llvm-bc,llvm-ir -Csave-temps -Zoffload=Host=/p/lustre1/drehwald1/prog/offload/r/target/amdgcn-amd-amdhsa/release/deps/device.bin -Zunstable-options" cargo +offload build -r ``` -This call also does a lot of work and generates multiple intermediate files for llvm offload. +This call also does a lot of work and generates multiple intermediate files for LLVM offload. While we integrated most offload steps into rustc by now, one binary invocation still remains for now: ``` @@ -77,7 +83,7 @@ While we integrated most offload steps into rustc by now, one binary invocation ``` You can try to find the paths to those files on your system. -However, I recommend to not fix the paths, but rather just re-generate them by copying a bare-mode openmp example and compiling it with your clang. +However, I recommend to not fix the paths, but rather just re-generate them by copying a bare-mode OpenMP example and compiling it with your clang. By adding `-###` to your clang invocation, you can see the invidual steps. It will show multiple steps, just look for the clang-linker-wrapper example. Make sure to still include the path to the `host.o` file, and not whatever tmp file you got when compiling your c++ example with the following call. @@ -96,3 +102,5 @@ To receive more information about the memory transfer, you can enable info print ``` LIBOMPTARGET_INFO=-1 ./main ``` + +[^list]: https://rocm.docs.amd.com/en/latest/reference/gpu-arch-specs.html or https://developer.nvidia.com/cuda/gpus. Alternatively, check `rustc --print target-cpus`. diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals.md b/src/doc/rustc-dev-guide/src/rustdoc-internals.md index f3fd47812a96b..df8adab351e65 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc-internals.md +++ b/src/doc/rustc-dev-guide/src/rustdoc-internals.md @@ -222,7 +222,7 @@ directly, even during `HTML` generation. This [didn't used to be the case], and a lot of `rustdoc`'s architecture was designed around not doing that, but a `TyCtxt` is now passed to `formats::renderer::run_format`, which is used to -run generation for both `HTML` and the (unstable as of Nov 2025) JSON format. +run generation for both `HTML` and the (unstable as of May 2026) JSON format. This change has allowed other changes to remove data from the "clean" [`AST`][ast] that can be easily derived from `TyCtxt` queries, and we'll usually accept diff --git a/src/doc/rustc-dev-guide/src/solve/opaque-types.md b/src/doc/rustc-dev-guide/src/solve/opaque-types.md index 6bb4534608dbd..4dc20c8c9fc92 100644 --- a/src/doc/rustc-dev-guide/src/solve/opaque-types.md +++ b/src/doc/rustc-dev-guide/src/solve/opaque-types.md @@ -5,6 +5,39 @@ This should be a self-contained explanation of the behavior in the new solver. [opaque types]: ../opaque-types-type-alias-impl-trait.md +## Non-Defining vs Defining Uses + +The distinction between non-defining and defining uses determines the inference behavior and governs the strictness of the abstraction. A defining use reveals the underlying hidden type, while a non-defining use enforces rigidity, treating the type as an abstract placeholder. + +### Non-defining Use + +This concept is what makes an opaque type rigid. By treating the underlying type as unknown, the solver maintains abstraction. + +```rust +fn foo() -> impl Copy { + let x: u32 = 56; + x +} + +fn bar() { + let x = foo(); + // Even though we know 'foo' returns a u32.The solver enforces + // rigidity here and is a NON-DEFINING use. +} +``` + +### Defining Use + +This is where the opaque type is actually defined. A defining use tells the compiler exactly what the concrete type is behind the abstraction. + +```rust +fn foo() -> impl Copy { + let x: u32 = 56; + // The return value x defines the hidden type as u32 and is a DEFINING use. + x +} +``` + ## opaques are alias types Opaque types are treated the same as other aliases, most notabily associated types, diff --git a/src/doc/rustc-dev-guide/src/stabilization-guide.md b/src/doc/rustc-dev-guide/src/stabilization-guide.md index f159fad89596a..eb11a0e63fe13 100644 --- a/src/doc/rustc-dev-guide/src/stabilization-guide.md +++ b/src/doc/rustc-dev-guide/src/stabilization-guide.md @@ -89,7 +89,7 @@ Next, search for the feature string (in this case, `pub_restricted`) in the code Change uses of `#![feature(XXX)]` from the `std` and any rustc crates (which includes test folders under `library/` and `compiler/` but not the toplevel `tests/` one) to be `#![cfg_attr(bootstrap, feature(XXX))]`. -This includes the feature-gate only for stage0, which is built using the current beta (this is needed because the feature is still unstable in the current beta). +This includes the feature-gate only for stage1, which is built using the current beta (this is needed because the feature is still unstable in the current beta). Also, remove those strings from any tests (e.g. under `tests/`). If there are tests specifically targeting the feature-gate (i.e., testing that the feature-gate is required to use the feature, but nothing else), simply remove the test. diff --git a/src/doc/rustc-dev-guide/src/tests/minicore.md b/src/doc/rustc-dev-guide/src/tests/minicore.md index 0fd7af7c60bbb..0814440d8dacd 100644 --- a/src/doc/rustc-dev-guide/src/tests/minicore.md +++ b/src/doc/rustc-dev-guide/src/tests/minicore.md @@ -1,6 +1,5 @@ # `minicore` test auxiliary: using `core` stubs - [`tests/auxiliary/minicore.rs`][`minicore`] is a test auxiliary for ui/codegen/assembly/mir-opt test suites. It provides `core` stubs for tests that need to diff --git a/src/doc/rustc-dev-guide/src/tests/misc.md b/src/doc/rustc-dev-guide/src/tests/misc.md index cc8f501224fac..ace1c8a319333 100644 --- a/src/doc/rustc-dev-guide/src/tests/misc.md +++ b/src/doc/rustc-dev-guide/src/tests/misc.md @@ -2,7 +2,6 @@ ## `RUSTC_BOOTSTRAP` and stability - This is a bootstrap/compiler implementation detail, but it can also be useful for testing: diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index 1e74a3de40403..02986119756bd 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -96,7 +96,7 @@ will check for output files: - `dont-check-compiler-stdout` — Ignores stdout from the compiler. - `compare-output-by-lines` — Some tests have non-deterministic orders of output, so we need to compare by lines. -UI tests run with `-Zdeduplicate-diagnostics=no` flag which disables rustc's +UI tests run with `-Zdeduplicate-diagnostics=no` flag, which disables rustc's built-in diagnostic deduplication mechanism. This means you may see some duplicate messages in the output. This helps illuminate situations where duplicate diagnostics are being generated. @@ -394,8 +394,8 @@ E.g. use `//@ dont-require-annotations: NOTE` to annotate notes selectively. Avoid using this directive for `ERROR`s and `WARN`ings, unless there's a serious reason, like target-dependent compiler output. -Some diagnostics are never required to be line-annotated, regardless of their kind or directives, -for example secondary lines of multiline diagnostics, +Some diagnostics are never required to be line-annotated, regardless of their kind or directives. +Examples are secondary lines of multiline diagnostics, or ubiquitous diagnostics like `aborting due to N previous errors`. UI tests use the `-A unused` flag by default to ignore all unused warnings, as diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish index 0b50ee19f8a57..4d40b28414677 100644 --- a/src/etc/completions/x.fish +++ b/src/etc/completions/x.fish @@ -465,6 +465,8 @@ complete -c x -n "__fish_x_using_subcommand test" -l rustfix-coverage -d 'enable complete -c x -n "__fish_x_using_subcommand test" -l no-capture -d 'don\'t capture stdout/stderr of tests' complete -c x -n "__fish_x_using_subcommand test" -l bypass-ignore-backends -d 'Ignore `//@ ignore-backends` directives' complete -c x -n "__fish_x_using_subcommand test" -l no-doc -d 'Deprecated. Use `--all-targets` or `--tests` instead' +complete -c x -n "__fish_x_using_subcommand test" -l record -d 'Record all the failed tests in a file in the build directory' +complete -c x -n "__fish_x_using_subcommand test" -l rerun -d 'Rerun tests that previously failed, and stored with `--record`' complete -c x -n "__fish_x_using_subcommand test" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x -n "__fish_x_using_subcommand test" -s q -l quiet -d 'use quiet output' complete -c x -n "__fish_x_using_subcommand test" -s i -l incremental -d 'use incremental compilation' @@ -520,6 +522,8 @@ complete -c x -n "__fish_x_using_subcommand t" -l rustfix-coverage -d 'enable th complete -c x -n "__fish_x_using_subcommand t" -l no-capture -d 'don\'t capture stdout/stderr of tests' complete -c x -n "__fish_x_using_subcommand t" -l bypass-ignore-backends -d 'Ignore `//@ ignore-backends` directives' complete -c x -n "__fish_x_using_subcommand t" -l no-doc -d 'Deprecated. Use `--all-targets` or `--tests` instead' +complete -c x -n "__fish_x_using_subcommand t" -l record -d 'Record all the failed tests in a file in the build directory' +complete -c x -n "__fish_x_using_subcommand t" -l rerun -d 'Rerun tests that previously failed, and stored with `--record`' complete -c x -n "__fish_x_using_subcommand t" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x -n "__fish_x_using_subcommand t" -s q -l quiet -d 'use quiet output' complete -c x -n "__fish_x_using_subcommand t" -s i -l incremental -d 'use incremental compilation' diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1 index e03994f4acaf0..f9bebb22b916f 100644 --- a/src/etc/completions/x.ps1 +++ b/src/etc/completions/x.ps1 @@ -543,6 +543,8 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--no-capture', '--no-capture', [CompletionResultType]::ParameterName, 'don''t capture stdout/stderr of tests') [CompletionResult]::new('--bypass-ignore-backends', '--bypass-ignore-backends', [CompletionResultType]::ParameterName, 'Ignore `//@ ignore-backends` directives') [CompletionResult]::new('--no-doc', '--no-doc', [CompletionResultType]::ParameterName, 'Deprecated. Use `--all-targets` or `--tests` instead') + [CompletionResult]::new('--record', '--record', [CompletionResultType]::ParameterName, 'Record all the failed tests in a file in the build directory') + [CompletionResult]::new('--rerun', '--rerun', [CompletionResultType]::ParameterName, 'Rerun tests that previously failed, and stored with `--record`') [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-q', '-q', [CompletionResultType]::ParameterName, 'use quiet output') @@ -606,6 +608,8 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--no-capture', '--no-capture', [CompletionResultType]::ParameterName, 'don''t capture stdout/stderr of tests') [CompletionResult]::new('--bypass-ignore-backends', '--bypass-ignore-backends', [CompletionResultType]::ParameterName, 'Ignore `//@ ignore-backends` directives') [CompletionResult]::new('--no-doc', '--no-doc', [CompletionResultType]::ParameterName, 'Deprecated. Use `--all-targets` or `--tests` instead') + [CompletionResult]::new('--record', '--record', [CompletionResultType]::ParameterName, 'Record all the failed tests in a file in the build directory') + [CompletionResult]::new('--rerun', '--rerun', [CompletionResultType]::ParameterName, 'Rerun tests that previously failed, and stored with `--record`') [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-q', '-q', [CompletionResultType]::ParameterName, 'use quiet output') diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index 8e3bec4fdd925..b098de6e7daff 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -465,6 +465,8 @@ complete -c x.py -n "__fish_x.py_using_subcommand test" -l rustfix-coverage -d ' complete -c x.py -n "__fish_x.py_using_subcommand test" -l no-capture -d 'don\'t capture stdout/stderr of tests' complete -c x.py -n "__fish_x.py_using_subcommand test" -l bypass-ignore-backends -d 'Ignore `//@ ignore-backends` directives' complete -c x.py -n "__fish_x.py_using_subcommand test" -l no-doc -d 'Deprecated. Use `--all-targets` or `--tests` instead' +complete -c x.py -n "__fish_x.py_using_subcommand test" -l record -d 'Record all the failed tests in a file in the build directory' +complete -c x.py -n "__fish_x.py_using_subcommand test" -l rerun -d 'Rerun tests that previously failed, and stored with `--record`' complete -c x.py -n "__fish_x.py_using_subcommand test" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_x.py_using_subcommand test" -s q -l quiet -d 'use quiet output' complete -c x.py -n "__fish_x.py_using_subcommand test" -s i -l incremental -d 'use incremental compilation' @@ -520,6 +522,8 @@ complete -c x.py -n "__fish_x.py_using_subcommand t" -l rustfix-coverage -d 'ena complete -c x.py -n "__fish_x.py_using_subcommand t" -l no-capture -d 'don\'t capture stdout/stderr of tests' complete -c x.py -n "__fish_x.py_using_subcommand t" -l bypass-ignore-backends -d 'Ignore `//@ ignore-backends` directives' complete -c x.py -n "__fish_x.py_using_subcommand t" -l no-doc -d 'Deprecated. Use `--all-targets` or `--tests` instead' +complete -c x.py -n "__fish_x.py_using_subcommand t" -l record -d 'Record all the failed tests in a file in the build directory' +complete -c x.py -n "__fish_x.py_using_subcommand t" -l rerun -d 'Rerun tests that previously failed, and stored with `--record`' complete -c x.py -n "__fish_x.py_using_subcommand t" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_x.py_using_subcommand t" -s q -l quiet -d 'use quiet output' complete -c x.py -n "__fish_x.py_using_subcommand t" -s i -l incremental -d 'use incremental compilation' diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index edcc5d0bb5ef1..6c952de7eaac9 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -543,6 +543,8 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--no-capture', '--no-capture', [CompletionResultType]::ParameterName, 'don''t capture stdout/stderr of tests') [CompletionResult]::new('--bypass-ignore-backends', '--bypass-ignore-backends', [CompletionResultType]::ParameterName, 'Ignore `//@ ignore-backends` directives') [CompletionResult]::new('--no-doc', '--no-doc', [CompletionResultType]::ParameterName, 'Deprecated. Use `--all-targets` or `--tests` instead') + [CompletionResult]::new('--record', '--record', [CompletionResultType]::ParameterName, 'Record all the failed tests in a file in the build directory') + [CompletionResult]::new('--rerun', '--rerun', [CompletionResultType]::ParameterName, 'Rerun tests that previously failed, and stored with `--record`') [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-q', '-q', [CompletionResultType]::ParameterName, 'use quiet output') @@ -606,6 +608,8 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--no-capture', '--no-capture', [CompletionResultType]::ParameterName, 'don''t capture stdout/stderr of tests') [CompletionResult]::new('--bypass-ignore-backends', '--bypass-ignore-backends', [CompletionResultType]::ParameterName, 'Ignore `//@ ignore-backends` directives') [CompletionResult]::new('--no-doc', '--no-doc', [CompletionResultType]::ParameterName, 'Deprecated. Use `--all-targets` or `--tests` instead') + [CompletionResult]::new('--record', '--record', [CompletionResultType]::ParameterName, 'Record all the failed tests in a file in the build directory') + [CompletionResult]::new('--rerun', '--rerun', [CompletionResultType]::ParameterName, 'Rerun tests that previously failed, and stored with `--record`') [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-q', '-q', [CompletionResultType]::ParameterName, 'use quiet output') diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index f32a078b2094d..b2542b94b9468 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -4638,7 +4638,7 @@ _x.py() { return 0 ;; x.py__test) - opts="-v -q -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --quiet --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -q -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --record --rerun --verbose --quiet --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4856,7 +4856,7 @@ _x.py() { return 0 ;; x.py__test) - opts="-v -q -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --quiet --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -q -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --record --rerun --verbose --quiet --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index 16fca305719ca..5199c6cbaf350 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -544,6 +544,8 @@ _arguments "${_arguments_options[@]}" : \ '--no-capture[don'\''t capture stdout/stderr of tests]' \ '--bypass-ignore-backends[Ignore \`//@ ignore-backends\` directives]' \ '--no-doc[Deprecated. Use \`--all-targets\` or \`--tests\` instead]' \ +'--record[Record all the failed tests in a file in the build directory]' \ +'--rerun[Rerun tests that previously failed, and stored with \`--record\`]' \ '(-q --quiet)*-v[use verbose output (-vv for very verbose)]' \ '(-q --quiet)*--verbose[use verbose output (-vv for very verbose)]' \ '(-v --verbose)-q[use quiet output]' \ @@ -609,6 +611,8 @@ _arguments "${_arguments_options[@]}" : \ '--no-capture[don'\''t capture stdout/stderr of tests]' \ '--bypass-ignore-backends[Ignore \`//@ ignore-backends\` directives]' \ '--no-doc[Deprecated. Use \`--all-targets\` or \`--tests\` instead]' \ +'--record[Record all the failed tests in a file in the build directory]' \ +'--rerun[Rerun tests that previously failed, and stored with \`--record\`]' \ '(-q --quiet)*-v[use verbose output (-vv for very verbose)]' \ '(-q --quiet)*--verbose[use verbose output (-vv for very verbose)]' \ '(-v --verbose)-q[use quiet output]' \ diff --git a/src/etc/completions/x.sh b/src/etc/completions/x.sh index 27b2a45efd53f..5740459a414d2 100644 --- a/src/etc/completions/x.sh +++ b/src/etc/completions/x.sh @@ -4638,7 +4638,7 @@ _x() { return 0 ;; x__test) - opts="-v -q -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --quiet --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -q -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --record --rerun --verbose --quiet --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4856,7 +4856,7 @@ _x() { return 0 ;; x__test) - opts="-v -q -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --verbose --quiet --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -q -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --all-targets --doc --tests --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose-run-make-subprocess-output --test-codegen-backend --bypass-ignore-backends --no-doc --record --rerun --verbose --quiet --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh index 8382f900d021e..31d9e43ef8e89 100644 --- a/src/etc/completions/x.zsh +++ b/src/etc/completions/x.zsh @@ -544,6 +544,8 @@ _arguments "${_arguments_options[@]}" : \ '--no-capture[don'\''t capture stdout/stderr of tests]' \ '--bypass-ignore-backends[Ignore \`//@ ignore-backends\` directives]' \ '--no-doc[Deprecated. Use \`--all-targets\` or \`--tests\` instead]' \ +'--record[Record all the failed tests in a file in the build directory]' \ +'--rerun[Rerun tests that previously failed, and stored with \`--record\`]' \ '(-q --quiet)*-v[use verbose output (-vv for very verbose)]' \ '(-q --quiet)*--verbose[use verbose output (-vv for very verbose)]' \ '(-v --verbose)-q[use quiet output]' \ @@ -609,6 +611,8 @@ _arguments "${_arguments_options[@]}" : \ '--no-capture[don'\''t capture stdout/stderr of tests]' \ '--bypass-ignore-backends[Ignore \`//@ ignore-backends\` directives]' \ '--no-doc[Deprecated. Use \`--all-targets\` or \`--tests\` instead]' \ +'--record[Record all the failed tests in a file in the build directory]' \ +'--rerun[Rerun tests that previously failed, and stored with \`--record\`]' \ '(-q --quiet)*-v[use verbose output (-vv for very verbose)]' \ '(-q --quiet)*--verbose[use verbose output (-vv for very verbose)]' \ '(-v --verbose)-q[use quiet output]' \ diff --git a/tests/codegen-llvm/bpf-alu32.rs b/tests/codegen-llvm/bpf-alu32.rs index 13a7b658cecce..7fef7e4101eed 100644 --- a/tests/codegen-llvm/bpf-alu32.rs +++ b/tests/codegen-llvm/bpf-alu32.rs @@ -1,11 +1,18 @@ -//@ only-bpf +//@ add-minicore +//@ compile-flags: --target=bpfel-unknown-none -C opt-level=0 +//@ needs-llvm-components: bpf #![crate_type = "lib"] -#![feature(bpf_target_feature)] +#![feature(bpf_target_feature, no_core)] +#![no_core] #![no_std] +extern crate minicore; +use minicore::*; + #[no_mangle] #[target_feature(enable = "alu32")] -// CHECK: define i8 @foo(i8 returned %arg) unnamed_addr #0 +// CHECK: define {{.*}}i8 @foo(i8 {{.*}}%arg) unnamed_addr #0 +// CHECK: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+alu32{{.*}} } pub unsafe fn foo(arg: u8) -> u8 { arg } diff --git a/tests/coverage/assert.coverage b/tests/coverage/assert.coverage index 8b0d337980bcb..29a5b48c0566a 100644 --- a/tests/coverage/assert.coverage +++ b/tests/coverage/assert.coverage @@ -27,7 +27,7 @@ LL| |// 3. Notably, the `assert` macros *do not* generate `TerminatorKind::Assert`. The macros produce LL| |// conditional expressions, `TerminatorKind::SwitchInt` branches, and a possible call to LL| |// `begin_panic_fmt()` (that begins a panic unwind, if the assertion test fails). - LL| |// 4. `TerminatoKind::Assert` is, however, also present in the MIR generated for this test + LL| |// 4. `TerminatorKind::Assert` is, however, also present in the MIR generated for this test LL| |// (and in many other coverage tests). The `Assert` terminator is typically generated by the LL| |// Rust compiler to check for runtime failures, such as numeric overflows. diff --git a/tests/coverage/assert.rs b/tests/coverage/assert.rs index bb7741bedbb5c..30d511f8f7a89 100644 --- a/tests/coverage/assert.rs +++ b/tests/coverage/assert.rs @@ -27,6 +27,6 @@ fn main() -> Result<(), u8> { // 3. Notably, the `assert` macros *do not* generate `TerminatorKind::Assert`. The macros produce // conditional expressions, `TerminatorKind::SwitchInt` branches, and a possible call to // `begin_panic_fmt()` (that begins a panic unwind, if the assertion test fails). -// 4. `TerminatoKind::Assert` is, however, also present in the MIR generated for this test +// 4. `TerminatorKind::Assert` is, however, also present in the MIR generated for this test // (and in many other coverage tests). The `Assert` terminator is typically generated by the // Rust compiler to check for runtime failures, such as numeric overflows. diff --git a/tests/ui/argument-suggestions/exotic-calls.rs b/tests/ui/argument-suggestions/exotic-calls.rs index 765b4bc536c3a..782e6c4e4777c 100644 --- a/tests/ui/argument-suggestions/exotic-calls.rs +++ b/tests/ui/argument-suggestions/exotic-calls.rs @@ -1,4 +1,4 @@ -//! Checks variations of E0057, which is the incorrect number of agruments passed into a closure +//! Checks variations of E0057, which is the incorrect number of arguments passed into a closure //@ check-fail diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs index 8b9dac0e29b0b..bbbc242afc15e 100644 --- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs @@ -9,27 +9,27 @@ fn option(i: i32) -> impl Sized { } fn tuple() -> impl Sized { - //~^ ERROR + //~^ ERROR cannot resolve opaque type (tuple(),) } fn array() -> impl Sized { - //~^ ERROR + //~^ ERROR cannot resolve opaque type [array()] } fn ptr() -> impl Sized { - //~^ ERROR + //~^ ERROR cannot resolve opaque type &ptr() as *const _ } fn fn_ptr() -> impl Sized { - //~^ ERROR + //~^ ERROR cannot resolve opaque type fn_ptr as fn() -> _ } fn closure_capture() -> impl Sized { - //~^ ERROR + //~^ ERROR cannot resolve opaque type let x = closure_capture(); move || { x; @@ -37,7 +37,7 @@ fn closure_capture() -> impl Sized { } fn closure_ref_capture() -> impl Sized { - //~^ ERROR + //~^ ERROR cannot resolve opaque type let x = closure_ref_capture(); move || { &x; @@ -45,17 +45,18 @@ fn closure_ref_capture() -> impl Sized { } fn closure_sig() -> impl Sized { - //~^ ERROR + //~^ ERROR cannot resolve opaque type || closure_sig() } fn coroutine_sig() -> impl Sized { - //~^ ERROR - || coroutine_sig() + //~^ ERROR cannot resolve opaque type + #[coroutine] + || yield coroutine_sig() } fn coroutine_capture() -> impl Sized { - //~^ ERROR + //~^ ERROR cannot resolve opaque type let x = coroutine_capture(); #[coroutine] @@ -66,7 +67,7 @@ fn coroutine_capture() -> impl Sized { } fn substs_change() -> impl Sized { - //~^ ERROR + //~^ ERROR cannot resolve opaque type (substs_change::<&T>(),) } @@ -76,12 +77,12 @@ fn use_fn_ptr() -> impl Sized { } fn mutual_recursion() -> impl Sync { - //~^ ERROR + //~^ ERROR cannot resolve opaque type mutual_recursion_b() } fn mutual_recursion_b() -> impl Sized { - //~^ ERROR + //~^ ERROR cannot resolve opaque type mutual_recursion() } diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr index af84375c74766..7aa07709c7223 100644 --- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr @@ -53,19 +53,19 @@ LL | fn coroutine_sig() -> impl Sized { | ^^^^^^^^^^ error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:57:27 + --> $DIR/recursive-impl-trait-type-indirect.rs:58:27 | LL | fn coroutine_capture() -> impl Sized { | ^^^^^^^^^^ error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:68:35 + --> $DIR/recursive-impl-trait-type-indirect.rs:69:35 | LL | fn substs_change() -> impl Sized { | ^^^^^^^^^^ error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:78:26 + --> $DIR/recursive-impl-trait-type-indirect.rs:79:26 | LL | fn mutual_recursion() -> impl Sync { | ^^^^^^^^^ recursive opaque type @@ -77,7 +77,7 @@ LL | fn mutual_recursion_b() -> impl Sized { | ---------- returning this opaque type `impl Sized` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:83:28 + --> $DIR/recursive-impl-trait-type-indirect.rs:84:28 | LL | fn mutual_recursion() -> impl Sync { | --------- returning this opaque type `impl Sync`