diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml index 31e075f45d6..de31c28cc90 100644 --- a/.github/workflows/post-merge.yml +++ b/.github/workflows/post-merge.yml @@ -35,8 +35,13 @@ jobs: cd src/ci/citool - echo "Post-merge analysis result" > output.log + printf "*This is an experimental post-merge analysis report. You can ignore it.*\n\n" > output.log + printf "
\nPost-merge report\n\n" >> output.log + cargo run --release post-merge-report ${PARENT_COMMIT} ${{ github.sha }} >> output.log + + printf "
\n" >> output.log + cat output.log gh pr comment ${HEAD_PR} -F output.log diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c7d37e2704d..df671cf4b86 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1516,7 +1516,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] { self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind { PatKind::Ident(_, ident, _) => self.lower_ident(ident), - _ => Ident::new(kw::Empty, self.lower_span(param.pat.span)), + PatKind::Wild => Ident::new(kw::Underscore, self.lower_span(param.pat.span)), + _ => { + self.dcx().span_delayed_bug( + param.pat.span, + "non-ident/wild param pat must trigger an error", + ); + Ident::new(kw::Empty, self.lower_span(param.pat.span)) + } })) } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index e78801dd601..be726c042da 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -411,14 +411,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Applicability::MachineApplicable, ); if !is_dyn_compatible { - diag.note(format!("`{trait_name}` it is dyn-incompatible, so it can't be `dyn`")); + diag.note(format!( + "`{trait_name}` is dyn-incompatible, otherwise a trait object could be used" + )); } else { // No ampersand in suggestion if it's borrowed already let (dyn_str, paren_dyn_str) = if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") }; let sugg = if let hir::TyKind::TraitObject([_, _, ..], _) = self_ty.kind { - // There are more than one trait bound, we need surrounding parentheses. + // There is more than one trait bound, we need surrounding parentheses. vec![ (self_ty.span.shrink_to_lo(), paren_dyn_str.to_string()), (self_ty.span.shrink_to_hi(), ")".to_string()), diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 3067766fb4d..1409310339a 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2148,9 +2148,11 @@ impl<'a> State<'a> { s.print_implicit_self(&decl.implicit_self); } else { if let Some(arg_name) = arg_names.get(i) { - s.word(arg_name.to_string()); - s.word(":"); - s.space(); + if arg_name.name != kw::Empty { + s.word(arg_name.to_string()); + s.word(":"); + s.space(); + } } else if let Some(body_id) = body_id { s.ann.nested(s, Nested::BodyParamPat(body_id, i)); s.word(":"); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 7c6bb495be3..7e8e4e3a561 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2060,7 +2060,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // struct-like enums (yet...), but it's definitely not // a bug to have constructed one. if adt_kind != AdtKind::Enum { - tcx.check_stability(v_field.did, Some(expr.hir_id), field.span, None); + tcx.check_stability(v_field.did, Some(field.hir_id), field.span, None); } self.field_ty(field.span, v_field, args) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index b8517701667..96d0a0fc6de 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -19,7 +19,7 @@ use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::Session; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Ident, Span, kw, sym}; use rustc_trait_selection::error_reporting::infer::{FailureCode, ObligationCauseExt}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt, SelectionContext}; @@ -2679,7 +2679,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { params.get(is_method as usize..params.len() - sig.decl.c_variadic as usize)?; debug_assert_eq!(params.len(), fn_inputs.len()); Some(( - fn_inputs.zip(params.iter().map(|param| FnParam::Name(param))).collect(), + fn_inputs.zip(params.iter().map(|¶m| FnParam::Name(param))).collect(), generics, )) } @@ -2710,23 +2710,14 @@ impl<'tcx> Visitor<'tcx> for FindClosureArg<'tcx> { #[derive(Clone, Copy)] enum FnParam<'hir> { Param(&'hir hir::Param<'hir>), - Name(&'hir Ident), + Name(Ident), } + impl FnParam<'_> { fn span(&self) -> Span { match self { - Self::Param(x) => x.span, - Self::Name(x) => x.span, - } - } - - fn name(&self) -> Option { - match self { - Self::Param(x) if let hir::PatKind::Binding(_, _, ident, _) = x.pat.kind => { - Some(ident.name) - } - Self::Name(x) if x.name != kw::Empty => Some(x.name), - _ => None, + Self::Param(param) => param.span, + Self::Name(ident) => ident.span, } } @@ -2734,8 +2725,23 @@ impl FnParam<'_> { struct D<'a>(FnParam<'a>, usize); impl fmt::Display for D<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(name) = self.0.name() { - write!(f, "`{name}`") + // A "unique" param name is one that (a) exists, and (b) is guaranteed to be unique + // among the parameters, i.e. `_` does not count. + let unique_name = match self.0 { + FnParam::Param(param) + if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind => + { + Some(ident.name) + } + FnParam::Name(ident) + if ident.name != kw::Empty && ident.name != kw::Underscore => + { + Some(ident.name) + } + _ => None, + }; + if let Some(unique_name) = unique_name { + write!(f, "`{unique_name}`") } else { write!(f, "parameter #{}", self.1 + 1) } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 7e6973259fe..3d1c61a9c34 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1422,7 +1422,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.check_stability( variant.fields[FieldIdx::from_usize(i)].did, - Some(pat.hir_id), + Some(subpat.hir_id), subpat.span, None, ); @@ -1686,7 +1686,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .get(&ident) .map(|(i, f)| { self.write_field_index(field.hir_id, *i); - self.tcx.check_stability(f.did, Some(pat.hir_id), span, None); + self.tcx.check_stability(f.did, Some(field.hir_id), span, None); self.field_ty(span, f, args) }) .unwrap_or_else(|| { diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 722779d3268..9e4fdd2b3ce 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -274,18 +274,13 @@ impl NonSnakeCase { let ident = ident.trim_start_matches('\''); let ident = ident.trim_matches('_'); - let mut allow_underscore = true; - ident.chars().all(|c| { - allow_underscore = match c { - '_' if !allow_underscore => return false, - '_' => false, - // It would be more obvious to use `c.is_lowercase()`, - // but some characters do not have a lowercase form - c if !c.is_uppercase() => true, - _ => return false, - }; - true - }) + if ident.contains("__") { + return false; + } + + // This correctly handles letters in languages with and without + // cases, as well as numbers and underscores. + !ident.chars().any(char::is_uppercase) } let name = ident.name.as_str(); diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 73c0af84a9f..c61c7a4fb02 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -281,8 +281,9 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn hir_body_param_names(self, id: BodyId) -> impl Iterator { - self.hir_body(id).params.iter().map(|arg| match arg.pat.kind { + self.hir_body(id).params.iter().map(|param| match param.pat.kind { PatKind::Binding(_, _, ident, _) => ident, + PatKind::Wild => Ident::new(kw::Underscore, param.pat.span), _ => Ident::empty(), }) } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 9b2d562a69e..0774324eae7 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2588,7 +2588,8 @@ impl<'a> Parser<'a> { } /// Parses the condition of a `if` or `while` expression. - fn parse_expr_cond(&mut self) -> PResult<'a, P> { + // Public because it is used in rustfmt forks such as https://github.com/tucant/rustfmt/blob/30c83df9e1db10007bdd16dafce8a86b404329b2/src/parse/macros/html.rs#L57 for custom if expressions. + pub fn parse_expr_cond(&mut self) -> PResult<'a, P> { let attrs = self.parse_outer_attributes()?; let (mut cond, _) = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, attrs)?; diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 6d3b6608ea2..a32b42a6fe3 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -603,13 +603,18 @@ static CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start ("d", Unstable(sym::loongarch_target_feature), &["f"]), + ("div32", Unstable(sym::loongarch_target_feature), &[]), ("f", Unstable(sym::loongarch_target_feature), &[]), ("frecipe", Unstable(sym::loongarch_target_feature), &[]), + ("lam-bh", Unstable(sym::loongarch_target_feature), &[]), + ("lamcas", Unstable(sym::loongarch_target_feature), &[]), ("lasx", Unstable(sym::loongarch_target_feature), &["lsx"]), ("lbt", Unstable(sym::loongarch_target_feature), &[]), + ("ld-seq-sa", Unstable(sym::loongarch_target_feature), &[]), ("lsx", Unstable(sym::loongarch_target_feature), &["d"]), ("lvz", Unstable(sym::loongarch_target_feature), &[]), ("relax", Unstable(sym::loongarch_target_feature), &[]), + ("scq", Unstable(sym::loongarch_target_feature), &[]), ("ual", Unstable(sym::loongarch_target_feature), &[]), // tidy-alphabetical-end ]; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index dce85b43df1..9383b82ff3c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1998,7 +1998,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .iter() .enumerate() .map(|(i, ident)| { - if ident.name.is_empty() || ident.name == kw::SelfLower { + if ident.name.is_empty() + || ident.name == kw::Underscore + || ident.name == kw::SelfLower + { format!("arg{i}") } else { format!("{ident}") diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index c393eb55c62..2354fe1ebaf 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2481,7 +2481,7 @@ impl Step for Gcc { fn run(self, builder: &Builder<'_>) -> Self::Output { let tarball = Tarball::new(builder, "gcc", &self.target.triple); let output = builder.ensure(super::gcc::Gcc { target: self.target }); - tarball.add_file(output.libgccjit, ".", 0o644); + tarball.add_file(output.libgccjit, "lib", 0o644); tarball.generate() } } diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index 5a4bc9bdbcb..0aa2a332531 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -63,11 +63,7 @@ impl Step for Gcc { } build_gcc(&metadata, builder, target); - - let lib_alias = metadata.install_dir.join("lib/libgccjit.so.0"); - if !lib_alias.exists() { - t!(builder.symlink_file(&libgccjit_path, lib_alias)); - } + create_lib_alias(builder, &libgccjit_path); t!(metadata.stamp.write()); @@ -75,6 +71,15 @@ impl Step for Gcc { } } +/// Creates a libgccjit.so.0 alias next to libgccjit.so if it does not +/// already exist +fn create_lib_alias(builder: &Builder<'_>, libgccjit: &PathBuf) { + let lib_alias = libgccjit.parent().unwrap().join("libgccjit.so.0"); + if !lib_alias.exists() { + t!(builder.symlink_file(libgccjit, lib_alias)); + } +} + pub struct Meta { stamp: BuildStamp, out_dir: PathBuf, @@ -109,8 +114,10 @@ fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option PathBuf { } fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) { + if builder.build.cc_tool(target).is_like_clang() + || builder.build.cxx_tool(target).is_like_clang() + { + panic!( + "Attempting to build GCC using Clang, which is known to misbehave. Please use GCC as the host C/C++ compiler. " + ); + } + let Meta { stamp: _, out_dir, install_dir, root } = metadata; t!(fs::create_dir_all(out_dir)); @@ -203,18 +218,13 @@ fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) { let mut configure_cmd = command(src_dir.join("configure")); configure_cmd .current_dir(out_dir) - // On CI, we compile GCC with Clang. - // The -Wno-everything flag is needed to make GCC compile with Clang 19. - // `-g -O2` are the default flags that are otherwise used by Make. - // FIXME(kobzol): change the flags once we have [gcc] configuration in config.toml. - .env("CXXFLAGS", "-Wno-everything -g -O2") - .env("CFLAGS", "-Wno-everything -g -O2") .arg("--enable-host-shared") - .arg("--enable-languages=jit") + .arg("--enable-languages=c,jit,lto") .arg("--enable-checking=release") .arg("--disable-bootstrap") .arg("--disable-multilib") .arg(format!("--prefix={}", install_dir.display())); + let cc = builder.build.cc(target).display().to_string(); let cc = builder .build diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 8dfd1bbfd60..91574f8bf5d 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -27,6 +27,7 @@ use std::{env, fs, io, str}; use build_helper::ci::gha; use build_helper::exit; +use cc::Tool; use termcolor::{ColorChoice, StandardStream, WriteColor}; use utils::build_stamp::BuildStamp; use utils::channel::GitInfo; @@ -1218,6 +1219,16 @@ Executed at: {executed_at}"#, self.cc.borrow()[&target].path().into() } + /// Returns the internal `cc::Tool` for the C compiler. + fn cc_tool(&self, target: TargetSelection) -> Tool { + self.cc.borrow()[&target].clone() + } + + /// Returns the internal `cc::Tool` for the C++ compiler. + fn cxx_tool(&self, target: TargetSelection) -> Tool { + self.cxx.borrow()[&target].clone() + } + /// Returns C flags that `cc-rs` thinks should be enabled for the /// specified target by default. fn cc_handled_clags(&self, target: TargetSelection, c: CLang) -> Vec { diff --git a/src/ci/citool/src/merge_report.rs b/src/ci/citool/src/merge_report.rs index 17e42d49286..62daa2e6853 100644 --- a/src/ci/citool/src/merge_report.rs +++ b/src/ci/citool/src/merge_report.rs @@ -1,8 +1,8 @@ -use std::cmp::Reverse; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; +use std::path::PathBuf; use anyhow::Context; -use build_helper::metrics::{JsonRoot, TestOutcome}; +use build_helper::metrics::{JsonRoot, TestOutcome, TestSuiteMetadata}; use crate::jobs::JobDatabase; use crate::metrics::get_test_suites; @@ -13,8 +13,10 @@ type JobName = String; /// Computes a post merge CI analysis report between the `parent` and `current` commits. pub fn post_merge_report(job_db: JobDatabase, parent: Sha, current: Sha) -> anyhow::Result<()> { let jobs = download_all_metrics(&job_db, &parent, ¤t)?; - let diffs = aggregate_test_diffs(&jobs)?; - report_test_changes(diffs); + let aggregated_test_diffs = aggregate_test_diffs(&jobs)?; + + println!("Comparing {parent} (base) -> {current} (this PR)\n"); + report_test_diffs(aggregated_test_diffs); Ok(()) } @@ -54,7 +56,16 @@ Maybe it was newly added?"#, Ok(jobs) } +/// Downloads job metrics of the given job for the given commit. +/// Caches the result on the local disk. fn download_job_metrics(job_name: &str, sha: &str) -> anyhow::Result { + let cache_path = PathBuf::from(".citool-cache").join(sha).join(job_name).join("metrics.json"); + if let Some(cache_entry) = + std::fs::read_to_string(&cache_path).ok().and_then(|data| serde_json::from_str(&data).ok()) + { + return Ok(cache_entry); + } + let url = get_metrics_url(job_name, sha); let mut response = ureq::get(&url).call()?; if !response.status().is_success() { @@ -68,6 +79,13 @@ fn download_job_metrics(job_name: &str, sha: &str) -> anyhow::Result { .body_mut() .read_json() .with_context(|| anyhow::anyhow!("cannot deserialize metrics from {url}"))?; + + // Ignore errors if cache cannot be created + if std::fs::create_dir_all(cache_path.parent().unwrap()).is_ok() { + if let Ok(serialized) = serde_json::to_string(&data) { + let _ = std::fs::write(&cache_path, &serialized); + } + } Ok(data) } @@ -76,72 +94,30 @@ fn get_metrics_url(job_name: &str, sha: &str) -> String { format!("https://ci-artifacts.rust-lang.org/rustc-builds{suffix}/{sha}/metrics-{job_name}.json") } +/// Represents a difference in the outcome of tests between a base and a current commit. +/// Maps test diffs to jobs that contained them. +#[derive(Debug)] +struct AggregatedTestDiffs { + diffs: HashMap>, +} + fn aggregate_test_diffs( jobs: &HashMap, -) -> anyhow::Result> { - let mut job_diffs = vec![]; +) -> anyhow::Result { + let mut diffs: HashMap> = HashMap::new(); // Aggregate test suites for (name, metrics) in jobs { if let Some(parent) = &metrics.parent { let tests_parent = aggregate_tests(parent); let tests_current = aggregate_tests(&metrics.current); - let test_diffs = calculate_test_diffs(tests_parent, tests_current); - if !test_diffs.is_empty() { - job_diffs.push((name.clone(), test_diffs)); + for diff in calculate_test_diffs(tests_parent, tests_current) { + diffs.entry(diff).or_default().push(name.to_string()); } } } - // Aggregate jobs with the same diff, as often the same diff will appear in many jobs - let job_diffs: HashMap, Vec> = - job_diffs.into_iter().fold(HashMap::new(), |mut acc, (job, diffs)| { - acc.entry(diffs).or_default().push(job); - acc - }); - - Ok(job_diffs - .into_iter() - .map(|(test_diffs, jobs)| AggregatedTestDiffs { jobs, test_diffs }) - .collect()) -} - -fn calculate_test_diffs( - reference: TestSuiteData, - current: TestSuiteData, -) -> Vec<(Test, TestOutcomeDiff)> { - let mut diffs = vec![]; - for (test, outcome) in ¤t.tests { - match reference.tests.get(test) { - Some(before) => { - if before != outcome { - diffs.push(( - test.clone(), - TestOutcomeDiff::ChangeOutcome { - before: before.clone(), - after: outcome.clone(), - }, - )); - } - } - None => diffs.push((test.clone(), TestOutcomeDiff::Added(outcome.clone()))), - } - } - for (test, outcome) in &reference.tests { - if !current.tests.contains_key(test) { - diffs.push((test.clone(), TestOutcomeDiff::Missing { before: outcome.clone() })); - } - } - - diffs -} - -/// Represents a difference in the outcome of tests between a base and a current commit. -#[derive(Debug)] -struct AggregatedTestDiffs { - /// All jobs that had the exact same test diffs. - jobs: Vec, - test_diffs: Vec<(Test, TestOutcomeDiff)>, + Ok(AggregatedTestDiffs { diffs }) } #[derive(Eq, PartialEq, Hash, Debug)] @@ -151,6 +127,47 @@ enum TestOutcomeDiff { Added(TestOutcome), } +#[derive(Eq, PartialEq, Hash, Debug)] +struct TestDiff { + test: Test, + diff: TestOutcomeDiff, +} + +fn calculate_test_diffs(parent: TestSuiteData, current: TestSuiteData) -> HashSet { + let mut diffs = HashSet::new(); + for (test, outcome) in ¤t.tests { + match parent.tests.get(test) { + Some(before) => { + if before != outcome { + diffs.insert(TestDiff { + test: test.clone(), + diff: TestOutcomeDiff::ChangeOutcome { + before: before.clone(), + after: outcome.clone(), + }, + }); + } + } + None => { + diffs.insert(TestDiff { + test: test.clone(), + diff: TestOutcomeDiff::Added(outcome.clone()), + }); + } + } + } + for (test, outcome) in &parent.tests { + if !current.tests.contains_key(test) { + diffs.insert(TestDiff { + test: test.clone(), + diff: TestOutcomeDiff::Missing { before: outcome.clone() }, + }); + } + } + + diffs +} + /// Aggregates test suite executions from all bootstrap invocations in a given CI job. #[derive(Default)] struct TestSuiteData { @@ -160,6 +177,7 @@ struct TestSuiteData { #[derive(Hash, PartialEq, Eq, Debug, Clone)] struct Test { name: String, + is_doctest: bool, } /// Extracts all tests from the passed metrics and map them to their outcomes. @@ -168,7 +186,10 @@ fn aggregate_tests(metrics: &JsonRoot) -> TestSuiteData { let test_suites = get_test_suites(&metrics); for suite in test_suites { for test in &suite.tests { - let test_entry = Test { name: normalize_test_name(&test.name) }; + // Poor man's detection of doctests based on the "(line XYZ)" suffix + let is_doctest = matches!(suite.metadata, TestSuiteMetadata::CargoPackage { .. }) + && test.name.contains("(line"); + let test_entry = Test { name: normalize_test_name(&test.name), is_doctest }; tests.insert(test_entry, test.outcome.clone()); } } @@ -181,16 +202,13 @@ fn normalize_test_name(name: &str) -> String { } /// Prints test changes in Markdown format to stdout. -fn report_test_changes(mut diffs: Vec) { +fn report_test_diffs(diff: AggregatedTestDiffs) { println!("## Test differences"); - if diffs.is_empty() { + if diff.diffs.is_empty() { println!("No test diffs found"); return; } - // Sort diffs in decreasing order by diff count - diffs.sort_by_key(|entry| Reverse(entry.test_diffs.len())); - fn format_outcome(outcome: &TestOutcome) -> String { match outcome { TestOutcome::Passed => "pass".to_string(), @@ -219,36 +237,79 @@ fn report_test_changes(mut diffs: Vec) { } } - let max_diff_count = 10; - let max_job_count = 5; - let max_test_count = 10; + fn format_job_group(group: u64) -> String { + format!("**J{group}**") + } - for diff in diffs.iter().take(max_diff_count) { - let mut jobs = diff.jobs.clone(); - jobs.sort(); + // It would be quite noisy to repeat the jobs that contained the test changes after/next to + // every test diff. At the same time, grouping the test diffs by + // [unique set of jobs that contained them] also doesn't work well, because the test diffs + // would have to be duplicated several times. + // Instead, we create a set of unique job groups, and then print a job group after each test. + // We then print the job groups at the end, as a sort of index. + let mut grouped_diffs: Vec<(&TestDiff, u64)> = vec![]; + let mut job_list_to_group: HashMap<&[JobName], u64> = HashMap::new(); + let mut job_index: Vec<&[JobName]> = vec![]; - let jobs = jobs.iter().take(max_job_count).map(|j| format!("`{j}`")).collect::>(); + let original_diff_count = diff.diffs.len(); + let diffs = diff + .diffs + .into_iter() + .filter(|(diff, _)| !diff.test.is_doctest) + .map(|(diff, mut jobs)| { + jobs.sort(); + (diff, jobs) + }) + .collect::>(); + let doctest_count = original_diff_count.saturating_sub(diffs.len()); - let extra_jobs = diff.jobs.len().saturating_sub(max_job_count); - let suffix = if extra_jobs > 0 { - format!(" (and {extra_jobs} {})", pluralize("other", extra_jobs)) - } else { - String::new() + let max_diff_count = 100; + for (diff, jobs) in diffs.iter().take(max_diff_count) { + let jobs = &*jobs; + let job_group = match job_list_to_group.get(jobs.as_slice()) { + Some(id) => *id, + None => { + let id = job_index.len() as u64; + job_index.push(jobs); + job_list_to_group.insert(jobs, id); + id + } }; - println!("- {}{suffix}", jobs.join(",")); + grouped_diffs.push((diff, job_group)); + } - let extra_tests = diff.test_diffs.len().saturating_sub(max_test_count); - for (test, outcome_diff) in diff.test_diffs.iter().take(max_test_count) { - println!(" - {}: {}", test.name, format_diff(&outcome_diff)); - } - if extra_tests > 0 { - println!(" - (and {extra_tests} additional {})", pluralize("tests", extra_tests)); - } + // Sort diffs by job group and test name + grouped_diffs.sort_by(|(d1, g1), (d2, g2)| g1.cmp(&g2).then(d1.test.name.cmp(&d2.test.name))); + + for (diff, job_group) in grouped_diffs { + println!( + "- `{}`: {} ({})", + diff.test.name, + format_diff(&diff.diff), + format_job_group(job_group) + ); } let extra_diffs = diffs.len().saturating_sub(max_diff_count); if extra_diffs > 0 { - println!("\n(and {extra_diffs} additional {})", pluralize("diff", extra_diffs)); + println!("\n(and {extra_diffs} additional {})", pluralize("test diff", extra_diffs)); + } + + if doctest_count > 0 { + println!( + "\nAdditionally, {doctest_count} doctest {} were found. These are ignored, as they are noisy.", + pluralize("diff", doctest_count) + ); + } + + // Now print the job group index + println!("\n**Job group index**\n"); + for (group, jobs) in job_index.into_iter().enumerate() { + println!( + "- {}: {}", + format_job_group(group as u64), + jobs.iter().map(|j| format!("`{j}`")).collect::>().join(", ") + ); } } diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index f54ecef1e30..ae5bf8946dd 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -101,7 +101,9 @@ ENV SCRIPT python3 ../x.py build --set rust.debug=true opt-dist && \ ./build/$HOSTS/stage0-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \ --host $HOSTS --target $HOSTS \ --include-default-paths \ - build-manifest bootstrap gcc + build-manifest bootstrap && \ + # Use GCC for building GCC, as it seems to behave badly when built with Clang + CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist gcc ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang # This is the only builder which will create source tarballs diff --git a/src/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh index 4a42f5da29f..ad21836253b 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh @@ -41,8 +41,6 @@ cd netbsd mkdir -p /x-tools/x86_64-unknown-netbsd/sysroot -# URL=https://ci-mirrors.rust-lang.org/rustc - # Hashes come from https://cdn.netbsd.org/pub/NetBSD/security/hashes/NetBSD-9.0_hashes.asc SRC_SHA=2c791ae009a6929c6fc893ec5df7e62910ee8207e0b2159d6937309c03efe175b6ae1e445829a13d041b6851334ad35c521f2fa03c97675d4a05f1fafe58ede0 GNUSRC_SHA=3710085a73feecf6a843415271ec794c90146b03f6bbd30f07c9e0c79febf8995d557e40194f1e05db655e4f5ef2fae97563f8456fceaae65d4ea98857a83b1c @@ -51,22 +49,16 @@ SYSSRC_SHA=60b9ddf4cc6402256473e2e1eefeabd9001aa4e205208715ecc6d6fc3f5b400e46994 BASE_SHA=b5926b107cebf40c3c19b4f6cd039b610987dd7f819e7cdde3bd1e5230a856906e7930b15ab242d52ced9f0bda01d574be59488b8dbb95fa5df2987d0a70995f COMP_SHA=38ea54f30d5fc2afea87e5096f06873e00182789e8ad9cec0cb3e9f7c538c1aa4779e63fd401a36ba02676158e83fa5c95e8e87898db59c1914fb206aecd82d2 -# FIXME: the archive URL is being used temporarily while the CDN is down. -# We should serve this from our own CDN -# SOURCE_URL=https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/source/sets -SOURCE_URL=http://archive.netbsd.org/pub/NetBSD-archive/NetBSD-9.0/source/sets -download src.tgz "$SOURCE_URL/src.tgz" "$SRC_SHA" tar xzf src.tgz -download gnusrc.tgz "$SOURCE_URL/gnusrc.tgz" "$GNUSRC_SHA" tar xzf gnusrc.tgz -download sharesrc.tgz "$SOURCE_URL/sharesrc.tgz" "$SHARESRC_SHA" tar xzf sharesrc.tgz -download syssrc.tgz "$SOURCE_URL/syssrc.tgz" "$SYSSRC_SHA" tar xzf syssrc.tgz +SOURCE_URL=https://ci-mirrors.rust-lang.org/rustc/2025-03-14-netbsd-9.0-src +download src.tgz "$SOURCE_URL-src.tgz" "$SRC_SHA" tar xzf src.tgz +download gnusrc.tgz "$SOURCE_URL-gnusrc.tgz" "$GNUSRC_SHA" tar xzf gnusrc.tgz +download sharesrc.tgz "$SOURCE_URL-sharesrc.tgz" "$SHARESRC_SHA" tar xzf sharesrc.tgz +download syssrc.tgz "$SOURCE_URL-syssrc.tgz" "$SYSSRC_SHA" tar xzf syssrc.tgz -# FIXME: the archive URL is being used temporarily while the CDN is down. -# We should serve this from our own CDN -# BINARY_URL=https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/amd64/binary/sets -BINARY_URL=http://archive.netbsd.org/pub/NetBSD-archive/NetBSD-9.0/amd64/binary/sets -download base.tar.xz "$BINARY_URL/base.tar.xz" "$BASE_SHA" \ +BINARY_URL=https://ci-mirrors.rust-lang.org/rustc/2025-03-14-netbsd-9.0-amd64-binary +download base.tar.xz "$BINARY_URL-base.tar.xz" "$BASE_SHA" \ tar xJf base.tar.xz -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib ./lib -download comp.tar.xz "$BINARY_URL/comp.tar.xz" "$COMP_SHA" \ +download comp.tar.xz "$BINARY_URL-comp.tar.xz" "$COMP_SHA" \ tar xJf comp.tar.xz -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib cd usr/src diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs index 8b3bd77141b..c8759bb6ff6 100644 --- a/src/tools/opt-dist/src/tests.rs +++ b/src/tools/opt-dist/src/tests.rs @@ -1,3 +1,5 @@ +use std::path::Path; + use anyhow::Context; use camino::{Utf8Path, Utf8PathBuf}; @@ -86,36 +88,57 @@ llvm-config = "{llvm_config}" log::info!("Using following `config.toml` for running tests:\n{config_content}"); // Simulate a stage 0 compiler with the extracted optimized dist artifacts. - std::fs::write("config.toml", config_content)?; + with_backed_up_file(Path::new("config.toml"), &config_content, || { + let x_py = env.checkout_path().join("x.py"); + let mut args = vec![ + env.python_binary(), + x_py.as_str(), + "test", + "--build", + env.host_tuple(), + "--stage", + "0", + "tests/assembly", + "tests/codegen", + "tests/codegen-units", + "tests/incremental", + "tests/mir-opt", + "tests/pretty", + "tests/run-make/glibc-symbols-x86_64-unknown-linux-gnu", + "tests/ui", + "tests/crashes", + ]; + for test_path in env.skipped_tests() { + args.extend(["--skip", test_path]); + } + cmd(&args) + .env("COMPILETEST_FORCE_STAGE0", "1") + // Also run dist-only tests + .env("COMPILETEST_ENABLE_DIST_TESTS", "1") + .run() + .context("Cannot execute tests") + }) +} - let x_py = env.checkout_path().join("x.py"); - let mut args = vec![ - env.python_binary(), - x_py.as_str(), - "test", - "--build", - env.host_tuple(), - "--stage", - "0", - "tests/assembly", - "tests/codegen", - "tests/codegen-units", - "tests/incremental", - "tests/mir-opt", - "tests/pretty", - "tests/run-make/glibc-symbols-x86_64-unknown-linux-gnu", - "tests/ui", - "tests/crashes", - ]; - for test_path in env.skipped_tests() { - args.extend(["--skip", test_path]); +/// Backup `path` (if it exists), then write `contents` into it, and then restore the original +/// contents of the file. +fn with_backed_up_file(path: &Path, contents: &str, func: F) -> anyhow::Result<()> +where + F: FnOnce() -> anyhow::Result<()>, +{ + let original_contents = + if path.is_file() { Some(std::fs::read_to_string(path)?) } else { None }; + + // Overwrite it with new contents + std::fs::write(path, contents)?; + + let ret = func(); + + if let Some(original_contents) = original_contents { + std::fs::write(path, original_contents)?; } - cmd(&args) - .env("COMPILETEST_FORCE_STAGE0", "1") - // Also run dist-only tests - .env("COMPILETEST_ENABLE_DIST_TESTS", "1") - .run() - .context("Cannot execute tests") + + ret } /// Tries to find the version of the dist artifacts (either nightly, beta, or 1.XY.Z). diff --git a/tests/pretty/hir-fn-params.pp b/tests/pretty/hir-fn-params.pp new file mode 100644 index 00000000000..3799c8a3c3b --- /dev/null +++ b/tests/pretty/hir-fn-params.pp @@ -0,0 +1,38 @@ +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:hir-fn-params.pp + +// This tests the pretty-printing of various kinds of function parameters. + +//--------------------------------------------------------------------------- +// Normal functions and methods. + +fn normal_fn(_: u32, a: u32) { } + +struct S; +impl S { + fn method(_: u32, a: u32) { } +} + +//--------------------------------------------------------------------------- +// More exotic forms, which get a different pretty-printing path. In the past, +// anonymous params and `_` params printed incorrectly, e.g. `fn(u32, _: u32)` +// was printed as `fn(: u32, : u32)`. +// +// Ideally we would also test invalid patterns, e.g. `fn(1: u32, &a: u32)`, +// because they had similar problems. But the pretty-printing tests currently +// can't contain compile errors. + +fn bare_fn(x: fn(u32, _: u32, a: u32)) { } + +extern "C" { + unsafe fn foreign_fn(_: u32, a: u32); +} + +trait T { + fn trait_fn(u32, _: u32, a: u32); +} diff --git a/tests/pretty/hir-fn-params.rs b/tests/pretty/hir-fn-params.rs new file mode 100644 index 00000000000..5ace5289d08 --- /dev/null +++ b/tests/pretty/hir-fn-params.rs @@ -0,0 +1,34 @@ +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:hir-fn-params.pp + +// This tests the pretty-printing of various kinds of function parameters. + +//--------------------------------------------------------------------------- +// Normal functions and methods. + +fn normal_fn(_: u32, a: u32) {} + +struct S; +impl S { + fn method(_: u32, a: u32) {} +} + +//--------------------------------------------------------------------------- +// More exotic forms, which get a different pretty-printing path. In the past, +// anonymous params and `_` params printed incorrectly, e.g. `fn(u32, _: u32)` +// was printed as `fn(: u32, : u32)`. +// +// Ideally we would also test invalid patterns, e.g. `fn(1: u32, &a: u32)`, +// because they had similar problems. But the pretty-printing tests currently +// can't contain compile errors. + +fn bare_fn(x: fn(u32, _: u32, a: u32)) {} + +extern "C" { + fn foreign_fn(_: u32, a: u32); +} + +trait T { + fn trait_fn(u32, _: u32, a: u32); +} diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index 01d90717107..64e65ece85d 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -40,6 +40,7 @@ //@ revisions: loongarch64 //@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu //@[loongarch64] needs-llvm-components: loongarch +//@[loongarch64] min-llvm-version: 20 //FIXME: wasm is disabled due to . //FIXME @ revisions: wasm //FIXME @[wasm] compile-flags: --target wasm32-unknown-unknown diff --git a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr index 0e544119650..c88f3af7642 100644 --- a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr +++ b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr @@ -1,35 +1,35 @@ error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:22:18 + --> $DIR/bad-reg.rs:23:18 | LL | asm!("", out("$r0") _); | ^^^^^^^^^^^^ error: invalid register `$tp`: reserved for TLS - --> $DIR/bad-reg.rs:24:18 + --> $DIR/bad-reg.rs:25:18 | LL | asm!("", out("$tp") _); | ^^^^^^^^^^^^ error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:26:18 + --> $DIR/bad-reg.rs:27:18 | LL | asm!("", out("$sp") _); | ^^^^^^^^^^^^ error: invalid register `$r21`: reserved by the ABI - --> $DIR/bad-reg.rs:28:18 + --> $DIR/bad-reg.rs:29:18 | LL | asm!("", out("$r21") _); | ^^^^^^^^^^^^^ error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:30:18 + --> $DIR/bad-reg.rs:31:18 | LL | asm!("", out("$fp") _); | ^^^^^^^^^^^^ error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:32:18 + --> $DIR/bad-reg.rs:33:18 | LL | asm!("", out("$r31") _); | ^^^^^^^^^^^^^ diff --git a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr index 6d0410dc6a1..cb8e55a9722 100644 --- a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr +++ b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr @@ -1,59 +1,59 @@ error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:22:18 + --> $DIR/bad-reg.rs:23:18 | LL | asm!("", out("$r0") _); | ^^^^^^^^^^^^ error: invalid register `$tp`: reserved for TLS - --> $DIR/bad-reg.rs:24:18 + --> $DIR/bad-reg.rs:25:18 | LL | asm!("", out("$tp") _); | ^^^^^^^^^^^^ error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:26:18 + --> $DIR/bad-reg.rs:27:18 | LL | asm!("", out("$sp") _); | ^^^^^^^^^^^^ error: invalid register `$r21`: reserved by the ABI - --> $DIR/bad-reg.rs:28:18 + --> $DIR/bad-reg.rs:29:18 | LL | asm!("", out("$r21") _); | ^^^^^^^^^^^^^ error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:30:18 + --> $DIR/bad-reg.rs:31:18 | LL | asm!("", out("$fp") _); | ^^^^^^^^^^^^ error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:32:18 + --> $DIR/bad-reg.rs:33:18 | LL | asm!("", out("$r31") _); | ^^^^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:36:26 + --> $DIR/bad-reg.rs:37:26 | LL | asm!("/* {} */", in(freg) f); | ^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:38:26 + --> $DIR/bad-reg.rs:39:26 | LL | asm!("/* {} */", out(freg) _); | ^^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:40:26 + --> $DIR/bad-reg.rs:41:26 | LL | asm!("/* {} */", in(freg) d); | ^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:42:26 + --> $DIR/bad-reg.rs:43:26 | LL | asm!("/* {} */", out(freg) d); | ^^^^^^^^^^^ diff --git a/tests/ui/asm/loongarch/bad-reg.rs b/tests/ui/asm/loongarch/bad-reg.rs index 685b460bc92..db1c778e5a2 100644 --- a/tests/ui/asm/loongarch/bad-reg.rs +++ b/tests/ui/asm/loongarch/bad-reg.rs @@ -1,6 +1,7 @@ //@ add-core-stubs //@ needs-asm-support //@ revisions: loongarch64_lp64d loongarch64_lp64s +//@ min-llvm-version: 20 //@[loongarch64_lp64d] compile-flags: --target loongarch64-unknown-linux-gnu //@[loongarch64_lp64d] needs-llvm-components: loongarch //@[loongarch64_lp64s] compile-flags: --target loongarch64-unknown-none-softfloat diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index 5b82d3f539f..a9d67481ba1 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -60,6 +60,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `d32` `deflate-conversion` `dit` +`div32` `doloop` `dotprod` `dpb` @@ -133,8 +134,11 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `jsconv` `kl` `lahfsahf` +`lam-bh` +`lamcas` `lasx` `lbt` +`ld-seq-sa` `leoncasa` `lor` `lse` @@ -190,6 +194,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `reserve-x18` `rtm` `sb` +`scq` `sha` `sha2` `sha3` diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.new.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.new.stderr index 87207d607e2..4c4cb45293f 100644 --- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.new.stderr +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.new.stderr @@ -4,7 +4,7 @@ error[E0782]: expected a type, found a trait LL | fn id(f: Copy) -> usize { | ^^^^ | - = note: `Copy` it is dyn-incompatible, so it can't be `dyn` + = note: `Copy` is dyn-incompatible, otherwise a trait object could be used help: use a new generic type parameter, constrained by `Copy` | LL - fn id(f: Copy) -> usize { diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.new.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.new.stderr index 6075e313f4e..d3208d07e91 100644 --- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.new.stderr +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.new.stderr @@ -4,7 +4,7 @@ error[E0782]: expected a type, found a trait LL | trait A { fn g(b: B) -> B; } | ^ | - = note: `B` it is dyn-incompatible, so it can't be `dyn` + = note: `B` is dyn-incompatible, otherwise a trait object could be used help: use a new generic type parameter, constrained by `B` | LL - trait A { fn g(b: B) -> B; } @@ -32,7 +32,7 @@ error[E0782]: expected a type, found a trait LL | trait B { fn f(a: A) -> A; } | ^ | - = note: `A` it is dyn-incompatible, so it can't be `dyn` + = note: `A` is dyn-incompatible, otherwise a trait object could be used help: use a new generic type parameter, constrained by `A` | LL - trait B { fn f(a: A) -> A; } diff --git a/tests/ui/pattern/check-struct-pat-fields-stability-issue-138319.rs b/tests/ui/pattern/check-struct-pat-fields-stability-issue-138319.rs new file mode 100644 index 00000000000..b951c6d92ee --- /dev/null +++ b/tests/ui/pattern/check-struct-pat-fields-stability-issue-138319.rs @@ -0,0 +1,12 @@ +//@ check-pass +struct Point { + #[deprecated = "x is deprecated"] + _x: i32, + _y: i32, +} + +fn main() { + let p = Point { _x: 1, _y: 2 }; //~ WARNING use of deprecated field `Point::_x` + // Before fix, it report an warning + let Point { #[expect(deprecated)]_x, .. } = p; +} diff --git a/tests/ui/pattern/check-struct-pat-fields-stability-issue-138319.stderr b/tests/ui/pattern/check-struct-pat-fields-stability-issue-138319.stderr new file mode 100644 index 00000000000..707eb58e547 --- /dev/null +++ b/tests/ui/pattern/check-struct-pat-fields-stability-issue-138319.stderr @@ -0,0 +1,10 @@ +warning: use of deprecated field `Point::_x`: x is deprecated + --> $DIR/check-struct-pat-fields-stability-issue-138319.rs:9:21 + | +LL | let p = Point { _x: 1, _y: 2 }; + | ^^^^^ + | + = note: `#[warn(deprecated)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rust-2021/ice-return-unsized-can-impl-2.stderr b/tests/ui/rust-2021/ice-return-unsized-can-impl-2.stderr index f2942820e28..75718c94b19 100644 --- a/tests/ui/rust-2021/ice-return-unsized-can-impl-2.stderr +++ b/tests/ui/rust-2021/ice-return-unsized-can-impl-2.stderr @@ -4,7 +4,7 @@ error[E0782]: expected a type, found a trait LL | fn concrete(b: B) -> B; | ^ | - = note: `B` it is dyn-incompatible, so it can't be `dyn` + = note: `B` is dyn-incompatible, otherwise a trait object could be used help: use a new generic type parameter, constrained by `B` | LL - fn concrete(b: B) -> B; @@ -32,7 +32,7 @@ error[E0782]: expected a type, found a trait LL | fn f(a: A) -> A; | ^ | - = note: `A` it is dyn-incompatible, so it can't be `dyn` + = note: `A` is dyn-incompatible, otherwise a trait object could be used help: use a new generic type parameter, constrained by `A` | LL - fn f(a: A) -> A; diff --git a/tests/ui/rust-2021/ice-return-unsized-can-impl.stderr b/tests/ui/rust-2021/ice-return-unsized-can-impl.stderr index cfee506e29b..284232cf4f4 100644 --- a/tests/ui/rust-2021/ice-return-unsized-can-impl.stderr +++ b/tests/ui/rust-2021/ice-return-unsized-can-impl.stderr @@ -4,7 +4,7 @@ error[E0782]: expected a type, found a trait LL | fn g(new: B) -> B; | ^ | - = note: `B` it is dyn-incompatible, so it can't be `dyn` + = note: `B` is dyn-incompatible, otherwise a trait object could be used help: use a new generic type parameter, constrained by `B` | LL - fn g(new: B) -> B; diff --git a/tests/ui/rust-2021/ice-unsized-fn-params-2.stderr b/tests/ui/rust-2021/ice-unsized-fn-params-2.stderr index 7f837bbe50f..630bbc2b905 100644 --- a/tests/ui/rust-2021/ice-unsized-fn-params-2.stderr +++ b/tests/ui/rust-2021/ice-unsized-fn-params-2.stderr @@ -4,7 +4,7 @@ error[E0782]: expected a type, found a trait LL | fn guard(_s: Copy) -> bool { | ^^^^ | - = note: `Copy` it is dyn-incompatible, so it can't be `dyn` + = note: `Copy` is dyn-incompatible, otherwise a trait object could be used help: use a new generic type parameter, constrained by `Copy` | LL - fn guard(_s: Copy) -> bool { diff --git a/tests/ui/rust-2021/ice-unsized-fn-params.stderr b/tests/ui/rust-2021/ice-unsized-fn-params.stderr index 4d900711ed6..57708031d6b 100644 --- a/tests/ui/rust-2021/ice-unsized-fn-params.stderr +++ b/tests/ui/rust-2021/ice-unsized-fn-params.stderr @@ -4,7 +4,7 @@ error[E0782]: expected a type, found a trait LL | fn g(b: B) -> B; | ^ | - = note: `B` it is dyn-incompatible, so it can't be `dyn` + = note: `B` is dyn-incompatible, otherwise a trait object could be used help: use a new generic type parameter, constrained by `B` | LL - fn g(b: B) -> B; @@ -32,7 +32,7 @@ error[E0782]: expected a type, found a trait LL | fn f(a: A) -> A; | ^ | - = note: `A` it is dyn-incompatible, so it can't be `dyn` + = note: `A` is dyn-incompatible, otherwise a trait object could be used help: use a new generic type parameter, constrained by `A` | LL - fn f(a: A) -> A; diff --git a/tests/ui/stability-attribute/check-stability-issue-138319.rs b/tests/ui/stability-attribute/check-stability-issue-138319.rs new file mode 100644 index 00000000000..5440e0cad94 --- /dev/null +++ b/tests/ui/stability-attribute/check-stability-issue-138319.rs @@ -0,0 +1,39 @@ +//@ check-pass +fn _foo() { + _Bar { //~ WARNING use of deprecated struct `_Bar`: reason + #[expect(deprecated)] + foo: 0, + }; +} + +#[deprecated = "reason"] +struct _Bar { + foo: u32, +} + +fn _foo2() { + #[expect(deprecated)] + _Bar2 { + foo2: 0, + }; +} + +#[deprecated = "reason"] +struct _Bar2 { + foo2: u32, +} + +fn _foo3() { + _Bar3 { + #[expect(deprecated)] + foo3: 0, + }; +} + +struct _Bar3 { + #[deprecated = "reason"] + foo3: u32, +} + + +fn main() {} diff --git a/tests/ui/stability-attribute/check-stability-issue-138319.stderr b/tests/ui/stability-attribute/check-stability-issue-138319.stderr new file mode 100644 index 00000000000..4a2c3554a1e --- /dev/null +++ b/tests/ui/stability-attribute/check-stability-issue-138319.stderr @@ -0,0 +1,10 @@ +warning: use of deprecated struct `_Bar`: reason + --> $DIR/check-stability-issue-138319.rs:3:5 + | +LL | _Bar { + | ^^^^ + | + = note: `#[warn(deprecated)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr index 20aa227d10f..7b0fd979991 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr @@ -4,7 +4,7 @@ error[E0782]: expected a type, found a trait LL | fn f(a: A) -> A; | ^ | - = note: `A` it is dyn-incompatible, so it can't be `dyn` + = note: `A` is dyn-incompatible, otherwise a trait object could be used help: use a new generic type parameter, constrained by `A` | LL - fn f(a: A) -> A; @@ -32,7 +32,7 @@ error[E0782]: expected a type, found a trait LL | fn f(b: B) -> B; | ^ | - = note: `B` it is dyn-incompatible, so it can't be `dyn` + = note: `B` is dyn-incompatible, otherwise a trait object could be used help: use a new generic type parameter, constrained by `B` | LL - fn f(b: B) -> B; @@ -60,7 +60,7 @@ error[E0782]: expected a type, found a trait LL | fn f(&self, c: C) -> C; | ^ | - = note: `C` it is dyn-incompatible, so it can't be `dyn` + = note: `C` is dyn-incompatible, otherwise a trait object could be used help: use a new generic type parameter, constrained by `C` | LL - fn f(&self, c: C) -> C; diff --git a/tests/ui/typeck/cyclic_type_ice.stderr b/tests/ui/typeck/cyclic_type_ice.stderr index 4dc02a53c02..645766becbf 100644 --- a/tests/ui/typeck/cyclic_type_ice.stderr +++ b/tests/ui/typeck/cyclic_type_ice.stderr @@ -23,7 +23,7 @@ LL | let f = |_, _| (); help: provide the argument | LL - f(f); -LL + f(/* */, /* */); +LL + f(/* _ */, /* _ */); | error: aborting due to 2 previous errors