diff options
| author | bors <bors@rust-lang.org> | 2024-02-17 05:44:08 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-02-17 05:44:08 +0000 |
| commit | bbfce9196f1c2fb224cbccd7474f8f8623eebbf9 (patch) | |
| tree | 4bdb17aaad138aa83a9464e32a25528bd360f020 /src | |
| parent | d2a4ef39ca8d83bbfc277b98133c11828dd5b16e (diff) | |
| parent | d523cab910d6b89b01dad9b283a67fb2256bc41e (diff) | |
| download | rust-bbfce9196f1c2fb224cbccd7474f8f8623eebbf9.tar.gz rust-bbfce9196f1c2fb224cbccd7474f8f8623eebbf9.zip | |
Auto merge of #3303 - rust-lang:rustup-2024-02-17, r=saethlin
Automatic Rustup
Diffstat (limited to 'src')
25 files changed, 719 insertions, 365 deletions
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 64bef2d3015..9d7f88a9d42 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1039,7 +1039,7 @@ impl Step for Rustc { pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection, stage: u32) { cargo .arg("--features") - .arg(builder.rustc_features(builder.kind)) + .arg(builder.rustc_features(builder.kind, target)) .arg("--manifest-path") .arg(builder.src.join("compiler/rustc/Cargo.toml")); @@ -1096,7 +1096,7 @@ pub fn rustc_cargo_env( cargo.env("CFG_OMIT_GIT_HASH", "1"); } - if let Some(backend) = builder.config.default_codegen_backend() { + if let Some(backend) = builder.config.default_codegen_backend(target) { cargo.env("CFG_DEFAULT_CODEGEN_BACKEND", backend); } @@ -1137,7 +1137,7 @@ pub fn rustc_cargo_env( // build. If we are in a check build we still go ahead here presuming we've // detected that LLVM is already built and good to go which helps prevent // busting caches (e.g. like #71152). - if builder.config.llvm_enabled() { + if builder.config.llvm_enabled(target) { let building_is_expensive = crate::core::build_steps::llvm::prebuilt_llvm_config(builder, target).is_err(); // `top_stage == stage` might be false for `check --stage 1`, if we are building the stage 1 compiler @@ -1281,7 +1281,7 @@ pub(crate) const CODEGEN_BACKEND_PREFIX: &str = "rustc_codegen_"; fn is_codegen_cfg_needed(path: &TaskPath, run: &RunConfig<'_>) -> bool { if path.path.to_str().unwrap().contains(&CODEGEN_BACKEND_PREFIX) { let mut needs_codegen_backend_config = true; - for &backend in &run.builder.config.rust_codegen_backends { + for &backend in run.builder.config.codegen_backends(run.target) { if path .path .to_str() @@ -1318,7 +1318,7 @@ impl Step for CodegenBackend { return; } - for &backend in &run.builder.config.rust_codegen_backends { + for &backend in run.builder.config.codegen_backends(run.target) { if backend == "llvm" { continue; // Already built as part of rustc } @@ -1425,7 +1425,7 @@ fn copy_codegen_backends_to_sysroot( return; } - for backend in builder.config.rust_codegen_backends.iter() { + for backend in builder.config.codegen_backends(target) { if backend == "llvm" { continue; // Already built as part of rustc } @@ -1732,7 +1732,7 @@ impl Step for Assemble { // to not fail while linking the artifacts. build_compiler.stage = actual_stage; - for &backend in builder.config.rust_codegen_backends.iter() { + for &backend in builder.config.codegen_backends(target_compiler.host) { if backend == "llvm" { continue; // Already built as part of rustc } @@ -1817,7 +1817,7 @@ impl Step for Assemble { } } - if builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) { + if builder.config.llvm_enabled(target_compiler.host) { let llvm::LlvmResult { llvm_config, .. } = builder.ensure(llvm::Llvm { target: target_compiler.host }); if !builder.config.dry_run() && builder.config.llvm_tools_enabled { diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index f50026368da..6d56492e41b 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1278,7 +1278,7 @@ impl Step for CodegenBackend { } fn make_run(run: RunConfig<'_>) { - for &backend in &run.builder.config.rust_codegen_backends { + for &backend in run.builder.config.codegen_backends(run.target) { if backend == "llvm" { continue; // Already built as part of rustc } @@ -1302,7 +1302,7 @@ impl Step for CodegenBackend { return None; } - if !builder.config.rust_codegen_backends.contains(&self.backend) { + if !builder.config.codegen_backends(self.compiler.host).contains(&self.backend) { return None; } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 1dbda405128..0c7e751c8da 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1798,7 +1798,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let mut llvm_components_passed = false; let mut copts_passed = false; - if builder.config.llvm_enabled() { + if builder.config.llvm_enabled(compiler.host) { let llvm::LlvmResult { llvm_config, .. } = builder.ensure(llvm::Llvm { target: builder.config.build }); if !builder.config.dry_run() { @@ -3121,7 +3121,8 @@ impl Step for CodegenCranelift { return; } - if !builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("cranelift")) { + if !builder.config.codegen_backends(run.target).contains(&INTERNER.intern_str("cranelift")) + { builder.info("cranelift not in rust.codegen-backends. skipping"); return; } @@ -3245,7 +3246,7 @@ impl Step for CodegenGCC { return; } - if !builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("gcc")) { + if !builder.config.codegen_backends(run.target).contains(&INTERNER.intern_str("gcc")) { builder.info("gcc not in rust.codegen-backends. skipping"); return; } diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index b21ffe868e1..2c4013d78bf 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1229,7 +1229,7 @@ impl<'a> Builder<'a> { /// Note that this returns `None` if LLVM is disabled, or if we're in a /// check build or dry-run, where there's no need to build all of LLVM. fn llvm_config(&self, target: TargetSelection) -> Option<PathBuf> { - if self.config.llvm_enabled() && self.kind != Kind::Check && !self.config.dry_run() { + if self.config.llvm_enabled(target) && self.kind != Kind::Check && !self.config.dry_run() { let llvm::LlvmResult { llvm_config, .. } = self.ensure(llvm::Llvm { target }); if llvm_config.is_file() { return Some(llvm_config); @@ -1991,7 +1991,8 @@ impl<'a> Builder<'a> { }; if let Some(limit) = limit { - if stage == 0 || self.config.default_codegen_backend().unwrap_or_default() == "llvm" + if stage == 0 + || self.config.default_codegen_backend(target).unwrap_or_default() == "llvm" { rustflags.arg(&format!("-Cllvm-args=-import-instr-limit={limit}")); } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 4c64850c0e0..05b9c734018 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -577,6 +577,7 @@ pub struct Target { pub wasi_root: Option<PathBuf>, pub qemu_rootfs: Option<PathBuf>, pub no_std: bool, + pub codegen_backends: Option<Vec<Interned<String>>>, } impl Target { @@ -1135,6 +1136,7 @@ define_config! { wasi_root: Option<String> = "wasi-root", qemu_rootfs: Option<String> = "qemu-rootfs", no_std: Option<bool> = "no-std", + codegen_backends: Option<Vec<String>> = "codegen-backends", } } @@ -1840,6 +1842,24 @@ impl Config { target.profiler = cfg.profiler; target.rpath = cfg.rpath; + if let Some(ref backends) = cfg.codegen_backends { + let available_backends = vec!["llvm", "cranelift", "gcc"]; + + target.codegen_backends = Some(backends.iter().map(|s| { + if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) { + if available_backends.contains(&backend) { + panic!("Invalid value '{s}' for 'target.{triple}.codegen-backends'. Instead, please use '{backend}'."); + } else { + println!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \ + Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ + In this case, it would be referred to as '{backend}'."); + } + } + + INTERNER.intern_str(s) + }).collect()); + } + config.target_config.insert(TargetSelection::from_user(&triple), target); } } @@ -2222,8 +2242,8 @@ impl Config { self.target_config.get(&target).map(|t| t.rpath).flatten().unwrap_or(self.rust_rpath) } - pub fn llvm_enabled(&self) -> bool { - self.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) + pub fn llvm_enabled(&self, target: TargetSelection) -> bool { + self.codegen_backends(target).contains(&INTERNER.intern_str("llvm")) } pub fn llvm_libunwind(&self, target: TargetSelection) -> LlvmLibunwind { @@ -2242,8 +2262,15 @@ impl Config { self.submodules.unwrap_or(rust_info.is_managed_git_subrepository()) } - pub fn default_codegen_backend(&self) -> Option<Interned<String>> { - self.rust_codegen_backends.get(0).cloned() + pub fn codegen_backends(&self, target: TargetSelection) -> &[Interned<String>] { + self.target_config + .get(&target) + .and_then(|cfg| cfg.codegen_backends.as_deref()) + .unwrap_or(&self.rust_codegen_backends) + } + + pub fn default_codegen_backend(&self, target: TargetSelection) -> Option<Interned<String>> { + self.codegen_backends(target).get(0).cloned() } pub fn git_config(&self) -> GitConfig<'_> { diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 5f1ca5de74a..1dce8d8ac71 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -16,7 +16,6 @@ use std::path::PathBuf; use std::process::Command; use crate::core::config::Target; -use crate::utils::cache::INTERNER; use crate::utils::helpers::output; use crate::Build; @@ -88,19 +87,19 @@ pub fn check(build: &mut Build) { } // We need cmake, but only if we're actually building LLVM or sanitizers. - let building_llvm = build.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) - && build - .hosts - .iter() - .map(|host| { - build + let building_llvm = build + .hosts + .iter() + .map(|host| { + build.config.llvm_enabled(*host) + && build .config .target_config .get(host) .map(|config| config.llvm_config.is_none()) .unwrap_or(true) - }) - .any(|build_llvm_ourselves| build_llvm_ourselves); + }) + .any(|build_llvm_ourselves| build_llvm_ourselves); let need_cmake = building_llvm || build.config.any_sanitizers_to_build(); if need_cmake && cmd_finder.maybe_have("cmake").is_none() { @@ -190,13 +189,16 @@ than building it. if !build.config.dry_run() { cmd_finder.must_have(build.cxx(*host).unwrap()); } - } - if build.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) { - // Externally configured LLVM requires FileCheck to exist - let filecheck = build.llvm_filecheck(build.build); - if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests { - panic!("FileCheck executable {filecheck:?} does not exist"); + if build.config.llvm_enabled(*host) { + // Externally configured LLVM requires FileCheck to exist + let filecheck = build.llvm_filecheck(build.build); + if !filecheck.starts_with(&build.out) + && !filecheck.exists() + && build.config.codegen_tests + { + panic!("FileCheck executable {filecheck:?} does not exist"); + } } } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 0e9a9791fb2..121ed88c92f 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -731,12 +731,12 @@ impl Build { } /// Gets the space-separated set of activated features for the compiler. - fn rustc_features(&self, kind: Kind) -> String { + fn rustc_features(&self, kind: Kind, target: TargetSelection) -> String { let mut features = vec![]; if self.config.jemalloc { features.push("jemalloc"); } - if self.config.llvm_enabled() || kind == Kind::Check { + if self.config.llvm_enabled(target) || kind == Kind::Check { features.push("llvm"); } // keep in sync with `bootstrap/compile.rs:rustc_cargo_env` @@ -1561,7 +1561,8 @@ impl Build { || target .map(|t| self.config.profiler_enabled(t)) .unwrap_or_else(|| self.config.any_profiler_enabled())) - && (dep != "rustc_codegen_llvm" || self.config.llvm_enabled()) + && (dep != "rustc_codegen_llvm" + || self.config.hosts.iter().any(|host| self.config.llvm_enabled(*host))) { list.push(*dep); } diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 0d5e2600b73..ec62f9f1f8c 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -114,4 +114,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "A new `optimized-compiler-builtins` option has been introduced. Whether to build llvm's `compiler-rt` from source is no longer implicitly controlled by git state. See the PR for more details.", }, + ChangeInfo { + change_id: 120348, + severity: ChangeSeverity::Info, + summary: "New option `target.<triple>.codegen-backends` added to config.toml.", + }, ]; diff --git a/src/doc/unstable-book/src/language-features/intrinsics.md b/src/doc/unstable-book/src/language-features/intrinsics.md index 8fa8f567d7e..9d07ae6fc67 100644 --- a/src/doc/unstable-book/src/language-features/intrinsics.md +++ b/src/doc/unstable-book/src/language-features/intrinsics.md @@ -2,13 +2,60 @@ The tracking issue for this feature is: None. -Intrinsics are never intended to be stable directly, but intrinsics are often +Intrinsics are rarely intended to be stable directly, but are usually exported in some sort of stable manner. Prefer using the stable interfaces to the intrinsic directly when you can. ------------------------ +## Intrinsics with fallback logic + +Many intrinsics can be written in pure rust, albeit inefficiently or without supporting +some features that only exist on some backends. Backends can simply not implement those +intrinsics without causing any code miscompilations or failures to compile. + +```rust +#![feature(rustc_attrs, effects)] +#![allow(internal_features)] + +#[rustc_intrinsic] +const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} +``` + +Since these are just regular functions, it is perfectly ok to create the intrinsic twice: + +```rust +#![feature(rustc_attrs, effects)] +#![allow(internal_features)] + +#[rustc_intrinsic] +const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} + +mod foo { + #[rustc_intrinsic] + const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) { + panic!("noisy const dealloc") + } +} + +``` + +The behaviour on backends that override the intrinsic is exactly the same. On other +backends, the intrinsic behaviour depends on which implementation is called, just like +with any regular function. + +## Intrinsics lowered to MIR instructions + +Various intrinsics have native MIR operations that they correspond to. Instead of requiring +backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass +will convert the calls to the MIR operation. Backends do not need to know about these intrinsics +at all. + +## Intrinsics without fallback logic + +These must be implemented by all backends. + These are imported as if they were FFI functions, with the special `rust-intrinsic` ABI. For example, if one was in a freestanding context, but wished to be able to `transmute` between types, and @@ -27,4 +74,5 @@ extern "rust-intrinsic" { } ``` -As with any other FFI functions, these are always `unsafe` to call. +As with any other FFI functions, these are by default always `unsafe` to call. +You can add `#[rustc_safe_intrinsic]` to the intrinsic to make it safe to call. diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 85e7a915c53..30cadfe7dac 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -643,7 +643,7 @@ impl Item { let abi = tcx.fn_sig(def_id).skip_binder().abi(); hir::FnHeader { unsafety: if abi == Abi::RustIntrinsic { - intrinsic_operation_unsafety(tcx, self.def_id().unwrap()) + intrinsic_operation_unsafety(tcx, def_id.expect_local()) } else { hir::Unsafety::Unsafe }, diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 8d5bcd665ad..47195fcc17b 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -335,7 +335,7 @@ fn check_terminator<'tcx>( // within const fns. `transmute` is allowed in all other const contexts. // This won't really scale to more intrinsics or functions. Let's allow const // transmutes in const fn before we add more hacks to this. - if tcx.is_intrinsic(fn_def_id) && tcx.item_name(fn_def_id) == sym::transmute { + if matches!(tcx.intrinsic(fn_def_id), Some(sym::transmute)) { return Err(( span, "can only call `transmute` from const items, not `const fn`".into(), diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index daec3914145..4ceb8a646e0 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -6,6 +6,7 @@ use std::io::BufReader; use std::path::{Path, PathBuf}; use std::process::Command; +use regex::Regex; use tracing::*; use crate::common::{Config, Debugger, FailMode, Mode, PassMode}; @@ -46,18 +47,32 @@ impl EarlyProps { pub fn from_reader<R: Read>(config: &Config, testfile: &Path, rdr: R) -> Self { let mut props = EarlyProps::default(); - iter_header(testfile, rdr, &mut |_, ln, _| { - config.push_name_value_directive(ln, directives::AUX_BUILD, &mut props.aux, |r| { - r.trim().to_string() - }); - config.push_name_value_directive( - ln, - directives::AUX_CRATE, - &mut props.aux_crate, - Config::parse_aux_crate, - ); - config.parse_and_update_revisions(ln, &mut props.revisions); - }); + let mut poisoned = false; + iter_header( + config.mode, + &config.suite, + &mut poisoned, + testfile, + rdr, + &mut |_, _, ln, _| { + config.push_name_value_directive(ln, directives::AUX_BUILD, &mut props.aux, |r| { + r.trim().to_string() + }); + config.push_name_value_directive( + ln, + directives::AUX_CRATE, + &mut props.aux_crate, + Config::parse_aux_crate, + ); + config.parse_and_update_revisions(ln, &mut props.revisions); + }, + ); + + if poisoned { + eprintln!("errors encountered during EarlyProps parsing: {}", testfile.display()); + panic!("errors encountered during EarlyProps parsing"); + } + return props; } } @@ -306,205 +321,233 @@ impl TestProps { if !testfile.is_dir() { let file = File::open(testfile).unwrap(); - iter_header(testfile, file, &mut |revision, ln, _| { - if revision.is_some() && revision != cfg { - return; - } + let mut poisoned = false; - use directives::*; + iter_header( + config.mode, + &config.suite, + &mut poisoned, + testfile, + file, + &mut |revision, _, ln, _| { + if revision.is_some() && revision != cfg { + return; + } - config.push_name_value_directive( - ln, - ERROR_PATTERN, - &mut self.error_patterns, - |r| r, - ); - config.push_name_value_directive( - ln, - REGEX_ERROR_PATTERN, - &mut self.regex_error_patterns, - |r| r, - ); + use directives::*; + + config.push_name_value_directive( + ln, + ERROR_PATTERN, + &mut self.error_patterns, + |r| r, + ); + config.push_name_value_directive( + ln, + REGEX_ERROR_PATTERN, + &mut self.regex_error_patterns, + |r| r, + ); - fn split_flags(flags: &str) -> Vec<String> { - // Individual flags can be single-quoted to preserve spaces; see - // <https://github.com/rust-lang/rust/pull/115948/commits/957c5db6>. - flags - .split("'") - .enumerate() - .flat_map( - |(i, f)| { + fn split_flags(flags: &str) -> Vec<String> { + // Individual flags can be single-quoted to preserve spaces; see + // <https://github.com/rust-lang/rust/pull/115948/commits/957c5db6>. + flags + .split("'") + .enumerate() + .flat_map(|(i, f)| { if i % 2 == 1 { vec![f] } else { f.split_whitespace().collect() } - }, - ) - .map(move |s| s.to_owned()) - .collect::<Vec<_>>() - } + }) + .map(move |s| s.to_owned()) + .collect::<Vec<_>>() + } - if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) { - self.compile_flags.extend(split_flags(&flags)); - } - if config.parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS).is_some() { - panic!("`compiler-flags` directive should be spelled `compile-flags`"); - } + if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) { + self.compile_flags.extend(split_flags(&flags)); + } + if config.parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS).is_some() { + panic!("`compiler-flags` directive should be spelled `compile-flags`"); + } - if let Some(edition) = config.parse_edition(ln) { - self.compile_flags.push(format!("--edition={}", edition.trim())); - has_edition = true; - } + if let Some(edition) = config.parse_edition(ln) { + self.compile_flags.push(format!("--edition={}", edition.trim())); + has_edition = true; + } - config.parse_and_update_revisions(ln, &mut self.revisions); + config.parse_and_update_revisions(ln, &mut self.revisions); - config.set_name_value_directive(ln, RUN_FLAGS, &mut self.run_flags, |r| r); + config.set_name_value_directive(ln, RUN_FLAGS, &mut self.run_flags, |r| r); - if self.pp_exact.is_none() { - self.pp_exact = config.parse_pp_exact(ln, testfile); - } + if self.pp_exact.is_none() { + self.pp_exact = config.parse_pp_exact(ln, testfile); + } - config.set_name_directive(ln, SHOULD_ICE, &mut self.should_ice); - config.set_name_directive(ln, BUILD_AUX_DOCS, &mut self.build_aux_docs); - config.set_name_directive(ln, FORCE_HOST, &mut self.force_host); - config.set_name_directive(ln, CHECK_STDOUT, &mut self.check_stdout); - config.set_name_directive(ln, CHECK_RUN_RESULTS, &mut self.check_run_results); - config.set_name_directive( - ln, - DONT_CHECK_COMPILER_STDOUT, - &mut self.dont_check_compiler_stdout, - ); - config.set_name_directive( - ln, - DONT_CHECK_COMPILER_STDERR, - &mut self.dont_check_compiler_stderr, - ); - config.set_name_directive(ln, NO_PREFER_DYNAMIC, &mut self.no_prefer_dynamic); - config.set_name_directive(ln, PRETTY_EXPANDED, &mut self.pretty_expanded); + config.set_name_directive(ln, SHOULD_ICE, &mut self.should_ice); + config.set_name_directive(ln, BUILD_AUX_DOCS, &mut self.build_aux_docs); + config.set_name_directive(ln, FORCE_HOST, &mut self.force_host); + config.set_name_directive(ln, CHECK_STDOUT, &mut self.check_stdout); + config.set_name_directive(ln, CHECK_RUN_RESULTS, &mut self.check_run_results); + config.set_name_directive( + ln, + DONT_CHECK_COMPILER_STDOUT, + &mut self.dont_check_compiler_stdout, + ); + config.set_name_directive( + ln, + DONT_CHECK_COMPILER_STDERR, + &mut self.dont_check_compiler_stderr, + ); + config.set_name_directive(ln, NO_PREFER_DYNAMIC, &mut self.no_prefer_dynamic); + config.set_name_directive(ln, PRETTY_EXPANDED, &mut self.pretty_expanded); - if let Some(m) = config.parse_name_value_directive(ln, PRETTY_MODE) { - self.pretty_mode = m; - } + if let Some(m) = config.parse_name_value_directive(ln, PRETTY_MODE) { + self.pretty_mode = m; + } - config.set_name_directive(ln, PRETTY_COMPARE_ONLY, &mut self.pretty_compare_only); - config.push_name_value_directive(ln, AUX_BUILD, &mut self.aux_builds, |r| { - r.trim().to_string() - }); - config.push_name_value_directive( - ln, - AUX_CRATE, - &mut self.aux_crates, - Config::parse_aux_crate, - ); - config.push_name_value_directive( - ln, - EXEC_ENV, - &mut self.exec_env, - Config::parse_env, - ); - config.push_name_value_directive( - ln, - UNSET_EXEC_ENV, - &mut self.unset_exec_env, - |r| r, - ); - config.push_name_value_directive( - ln, - RUSTC_ENV, - &mut self.rustc_env, - Config::parse_env, - ); - config.push_name_value_directive( - ln, - UNSET_RUSTC_ENV, - &mut self.unset_rustc_env, - |r| r, - ); - config.push_name_value_directive(ln, FORBID_OUTPUT, &mut self.forbid_output, |r| r); - config.set_name_directive( - ln, - CHECK_TEST_LINE_NUMBERS_MATCH, - &mut self.check_test_line_numbers_match, - ); + config.set_name_directive( + ln, + PRETTY_COMPARE_ONLY, + &mut self.pretty_compare_only, + ); + config.push_name_value_directive(ln, AUX_BUILD, &mut self.aux_builds, |r| { + r.trim().to_string() + }); + config.push_name_value_directive( + ln, + AUX_CRATE, + &mut self.aux_crates, + Config::parse_aux_crate, + ); + config.push_name_value_directive( + ln, + EXEC_ENV, + &mut self.exec_env, + Config::parse_env, + ); + config.push_name_value_directive( + ln, + UNSET_EXEC_ENV, + &mut self.unset_exec_env, + |r| r, + ); + config.push_name_value_directive( + ln, + RUSTC_ENV, + &mut self.rustc_env, + Config::parse_env, + ); + config.push_name_value_directive( + ln, + UNSET_RUSTC_ENV, + &mut self.unset_rustc_env, + |r| r, + ); + config.push_name_value_directive( + ln, + FORBID_OUTPUT, + &mut self.forbid_output, + |r| r, + ); + config.set_name_directive( + ln, + CHECK_TEST_LINE_NUMBERS_MATCH, + &mut self.check_test_line_numbers_match, + ); - self.update_pass_mode(ln, cfg, config); - self.update_fail_mode(ln, config); + self.update_pass_mode(ln, cfg, config); + self.update_fail_mode(ln, config); - config.set_name_directive(ln, IGNORE_PASS, &mut self.ignore_pass); + config.set_name_directive(ln, IGNORE_PASS, &mut self.ignore_pass); - if let Some(rule) = config.parse_custom_normalization(ln, "normalize-stdout") { - self.normalize_stdout.push(rule); - } - if let Some(rule) = config.parse_custom_normalization(ln, "normalize-stderr") { - self.normalize_stderr.push(rule); - } + if let Some(rule) = config.parse_custom_normalization(ln, "normalize-stdout") { + self.normalize_stdout.push(rule); + } + if let Some(rule) = config.parse_custom_normalization(ln, "normalize-stderr") { + self.normalize_stderr.push(rule); + } - if let Some(code) = config - .parse_name_value_directive(ln, FAILURE_STATUS) - .and_then(|code| code.trim().parse::<i32>().ok()) - { - self.failure_status = Some(code); - } + if let Some(code) = config + .parse_name_value_directive(ln, FAILURE_STATUS) + .and_then(|code| code.trim().parse::<i32>().ok()) + { + self.failure_status = Some(code); + } - config.set_name_directive( - ln, - DONT_CHECK_FAILURE_STATUS, - &mut self.dont_check_failure_status, - ); + config.set_name_directive( + ln, + DONT_CHECK_FAILURE_STATUS, + &mut self.dont_check_failure_status, + ); - config.set_name_directive(ln, RUN_RUSTFIX, &mut self.run_rustfix); - config.set_name_directive( - ln, - RUSTFIX_ONLY_MACHINE_APPLICABLE, - &mut self.rustfix_only_machine_applicable, - ); - config.set_name_value_directive( - ln, - ASSEMBLY_OUTPUT, - &mut self.assembly_output, - |r| r.trim().to_string(), - ); - config.set_name_directive(ln, STDERR_PER_BITWIDTH, &mut self.stderr_per_bitwidth); - config.set_name_directive(ln, INCREMENTAL, &mut self.incremental); - - // Unlike the other `name_value_directive`s this needs to be handled manually, - // because it sets a `bool` flag. - if let Some(known_bug) = config.parse_name_value_directive(ln, KNOWN_BUG) { - let known_bug = known_bug.trim(); - if known_bug == "unknown" - || known_bug.split(',').all(|issue_ref| { - issue_ref - .trim() - .split_once('#') - .filter(|(_, number)| { - number.chars().all(|digit| digit.is_numeric()) - }) - .is_some() - }) - { - self.known_bug = true; - } else { + config.set_name_directive(ln, RUN_RUSTFIX, &mut self.run_rustfix); + config.set_name_directive( + ln, + RUSTFIX_ONLY_MACHINE_APPLICABLE, + &mut self.rustfix_only_machine_applicable, + ); + config.set_name_value_directive( + ln, + ASSEMBLY_OUTPUT, + &mut self.assembly_output, + |r| r.trim().to_string(), + ); + config.set_name_directive( + ln, + STDERR_PER_BITWIDTH, + &mut self.stderr_per_bitwidth, + ); + config.set_name_directive(ln, INCREMENTAL, &mut self.incremental); + + // Unlike the other `name_value_directive`s this needs to be handled manually, + // because it sets a `bool` flag. + if let Some(known_bug) = config.parse_name_value_directive(ln, KNOWN_BUG) { + let known_bug = known_bug.trim(); + if known_bug == "unknown" + || known_bug.split(',').all(|issue_ref| { + issue_ref + .trim() + .split_once('#') + .filter(|(_, number)| { + number.chars().all(|digit| digit.is_numeric()) + }) + .is_some() + }) + { + self.known_bug = true; + } else { + panic!( + "Invalid known-bug value: {known_bug}\nIt requires comma-separated issue references (`#000` or `chalk#000`) or `known-bug: unknown`." + ); + } + } else if config.parse_name_directive(ln, KNOWN_BUG) { panic!( - "Invalid known-bug value: {known_bug}\nIt requires comma-separated issue references (`#000` or `chalk#000`) or `known-bug: unknown`." + "Invalid known-bug attribute, requires comma-separated issue references (`#000` or `chalk#000`) or `known-bug: unknown`." ); } - } else if config.parse_name_directive(ln, KNOWN_BUG) { - panic!( - "Invalid known-bug attribute, requires comma-separated issue references (`#000` or `chalk#000`) or `known-bug: unknown`." + + config.set_name_value_directive( + ln, + MIR_UNIT_TEST, + &mut self.mir_unit_test, + |s| s.trim().to_string(), + ); + config.set_name_directive(ln, REMAP_SRC_BASE, &mut self.remap_src_base); + config.set_name_directive( + ln, + COMPARE_OUTPUT_LINES_BY_SUBSET, + &mut self.compare_output_lines_by_subset, ); - } - config.set_name_value_directive(ln, MIR_UNIT_TEST, &mut self.mir_unit_test, |s| { - s.trim().to_string() - }); - config.set_name_directive(ln, REMAP_SRC_BASE, &mut self.remap_src_base); - config.set_name_directive( - ln, - COMPARE_OUTPUT_LINES_BY_SUBSET, - &mut self.compare_output_lines_by_subset, - ); + if let Some(flags) = config.parse_name_value_directive(ln, LLVM_COV_FLAGS) { + self.llvm_cov_flags.extend(split_flags(&flags)); + } + }, + ); - if let Some(flags) = config.parse_name_value_directive(ln, LLVM_COV_FLAGS) { - self.llvm_cov_flags.extend(split_flags(&flags)); - } - }); + if poisoned { + eprintln!("errors encountered during TestProps parsing: {}", testfile.display()); + panic!("errors encountered during TestProps parsing"); + } } if self.should_ice { @@ -628,15 +671,143 @@ pub fn line_directive<'line>( } } -fn iter_header<R: Read>(testfile: &Path, rdr: R, it: &mut dyn FnMut(Option<&str>, &str, usize)) { - iter_header_extra(testfile, rdr, &[], it) +fn iter_header<R: Read>( + mode: Mode, + suite: &str, + poisoned: &mut bool, + testfile: &Path, + rdr: R, + it: &mut dyn FnMut(Option<&str>, &str, &str, usize), +) { + iter_header_extra(mode, suite, poisoned, testfile, rdr, &[], it) } +/// This is generated by collecting directives from ui tests and then extracting their directive +/// names. This is **not** an exhaustive list of all possible directives. Instead, this is a +/// best-effort approximation for diagnostics. +const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[ + "aux-build", + "aux-crate", + "build-fail", + "build-pass", + "check-fail", + "check-pass", + "check-run-results", + "check-stdout", + "compile-flags", + "dont-check-compiler-stderr", + "dont-check-compiler-stdout", + "dont-check-failure-status", + "edition", + "error-pattern", + "exec-env", + "failure-status", + "forbid-output", + "force-host", + "ignore-32bit", + "ignore-64bit", + "ignore-aarch64", + "ignore-aarch64-unknown-linux-gnu", + "ignore-android", + "ignore-arm", + "ignore-compare-mode-next-solver", + "ignore-compare-mode-polonius", + "ignore-cross-compile", + "ignore-debug", + "ignore-emscripten", + "ignore-endian-big", + "ignore-freebsd", + "ignore-fuchsia", + "ignore-gnu", + "ignore-haiku", + "ignore-horizon", + "ignore-i686-pc-windows-msvc", + "ignore-ios", + "ignore-llvm-version", + "ignore-macos", + "ignore-msvc", + "ignore-musl", + "ignore-netbsd", + "ignore-nightly", + "ignore-nto", + "ignore-nvptx64", + "ignore-openbsd", + "ignore-pass", + "ignore-sgx", + "ignore-spirv", + "ignore-test", + "ignore-thumbv8m.base-none-eabi", + "ignore-thumbv8m.main-none-eabi", + "ignore-uwp", + "ignore-vxworks", + "ignore-wasm", + "ignore-wasm32", + "ignore-wasm32-bare", + "ignore-windows", + "ignore-x86", + "incremental", + "known-bug", + "min-llvm-version", + "needs-asm-support", + "needs-dlltool", + "needs-dynamic-linking", + "needs-llvm-components", + "needs-profiler-support", + "needs-relocation-model-pic", + "needs-run-enabled", + "needs-sanitizer-address", + "needs-sanitizer-cfi", + "needs-sanitizer-hwaddress", + "needs-sanitizer-leak", + "needs-sanitizer-memory", + "needs-sanitizer-support", + "needs-sanitizer-thread", + "needs-unwind", + "needs-xray", + "no-prefer-dynamic", + "normalize-stderr-32bit", + "normalize-stderr-64bit", + "normalize-stderr-test", + "normalize-stdout-test", + "only-32bit", + "only-64bit", + "only-aarch64", + "only-gnu", + "only-i686-pc-windows-msvc", + "only-linux", + "only-macos", + "only-msvc", + "only-nightly", + "only-wasm32", + "only-windows", + "only-x86", + "only-x86_64", + "only-x86_64-pc-windows-msvc", + "only-x86_64-unknown-linux-gnu", + "pp-exact", + "pretty-expanded", + "regex-error-pattern", + "remap-src-base", + "revisions", + "run-fail", + "run-flags", + "run-pass", + "run-rustfix", + "rustc-env", + "rustfix-only-machine-applicable", + "should-fail", + "stderr-per-bitwidth", + "unset-rustc-env", +]; + fn iter_header_extra( + mode: Mode, + suite: &str, + poisoned: &mut bool, testfile: &Path, rdr: impl Read, extra_directives: &[&str], - it: &mut dyn FnMut(Option<&str>, &str, usize), + it: &mut dyn FnMut(Option<&str>, &str, &str, usize), ) { if testfile.is_dir() { return; @@ -645,15 +816,21 @@ fn iter_header_extra( // Process any extra directives supplied by the caller (e.g. because they // are implied by the test mode), with a dummy line number of 0. for directive in extra_directives { - it(None, directive, 0); + it(None, directive, directive, 0); } - let comment = if testfile.extension().is_some_and(|e| e == "rs") { "//" } else { "#" }; + let comment = if testfile.extension().is_some_and(|e| e == "rs") { + if mode == Mode::Ui && suite == "ui" { "//@" } else { "//" } + } else { + "#" + }; let mut rdr = BufReader::with_capacity(1024, rdr); let mut ln = String::new(); let mut line_number = 0; + let revision_magic_comment = Regex::new("//(\\[.*\\])?~.*").unwrap(); + loop { line_number += 1; ln.clear(); @@ -664,11 +841,56 @@ fn iter_header_extra( // Assume that any directives will be found before the first // module or function. This doesn't seem to be an optimization // with a warm page cache. Maybe with a cold one. + let orig_ln = &ln; let ln = ln.trim(); if ln.starts_with("fn") || ln.starts_with("mod") { return; + + // First try to accept `ui_test` style comments } else if let Some((lncfg, ln)) = line_directive(comment, ln) { - it(lncfg, ln, line_number); + it(lncfg, orig_ln, ln, line_number); + } else if mode == Mode::Ui && suite == "ui" && !revision_magic_comment.is_match(ln) { + let Some((_, rest)) = line_directive("//", ln) else { + continue; + }; + + if rest.trim_start().starts_with(':') { + // This is likely a markdown link: + // `[link_name]: https://example.org` + continue; + } + + let rest = rest.trim_start(); + + for candidate in DIAGNOSTICS_DIRECTIVE_NAMES.iter() { + if rest.starts_with(candidate) { + let Some(prefix_removed) = rest.strip_prefix(candidate) else { + // We have a comment that's *successfully* parsed as an legacy-style + // directive. We emit an error here to warn the user. + *poisoned = true; + eprintln!( + "error: detected legacy-style directives in ui test: {}:{}, please use `ui_test`-style directives `//@` instead:{:#?}", + testfile.display(), + line_number, + line_directive("//", ln), + ); + return; + }; + + if prefix_removed.starts_with([' ', ':']) { + // We have a comment that's *successfully* parsed as an legacy-style + // directive. We emit an error here to warn the user. + *poisoned = true; + eprintln!( + "error: detected legacy-style directives in ui test: {}:{}, please use `ui_test`-style directives `//@` instead:{:#?}", + testfile.display(), + line_number, + line_directive("//", ln), + ); + return; + } + } + } } } } @@ -946,49 +1168,77 @@ pub fn make_test_description<R: Read>( _ => &[], }; - iter_header_extra(path, src, extra_directives, &mut |revision, ln, line_number| { - if revision.is_some() && revision != cfg { - return; - } + let mut local_poisoned = false; + + iter_header_extra( + config.mode, + &config.suite, + &mut local_poisoned, + path, + src, + extra_directives, + &mut |revision, og_ln, ln, line_number| { + if revision.is_some() && revision != cfg { + return; + } - macro_rules! decision { - ($e:expr) => { - match $e { - IgnoreDecision::Ignore { reason } => { - ignore = true; - // The ignore reason must be a &'static str, so we have to leak memory to - // create it. This is fine, as the header is parsed only at the start of - // compiletest so it won't grow indefinitely. - ignore_message = Some(&*Box::leak(Box::<str>::from(reason))); + macro_rules! decision { + ($e:expr) => { + match $e { + IgnoreDecision::Ignore { reason } => { + ignore = true; + // The ignore reason must be a &'static str, so we have to leak memory to + // create it. This is fine, as the header is parsed only at the start of + // compiletest so it won't grow indefinitely. + ignore_message = Some(&*Box::leak(Box::<str>::from(reason))); + } + IgnoreDecision::Error { message } => { + eprintln!("error: {}:{line_number}: {message}", path.display()); + *poisoned = true; + return; + } + IgnoreDecision::Continue => {} } - IgnoreDecision::Error { message } => { - eprintln!("error: {}:{line_number}: {message}", path.display()); - *poisoned = true; - return; - } - IgnoreDecision::Continue => {} + }; + } + + if let Some((_, post)) = og_ln.trim_start().split_once("//") { + let post = post.trim_start(); + if post.starts_with("ignore-tidy") + && config.mode == Mode::Ui + && config.suite == "ui" + { + // not handled by compiletest under the ui test mode and ui test suite. + } else { + decision!(cfg::handle_ignore(config, ln)); } - }; - } + } else { + decision!(cfg::handle_ignore(config, ln)); + } - decision!(cfg::handle_ignore(config, ln)); - decision!(cfg::handle_only(config, ln)); - decision!(needs::handle_needs(&cache.needs, config, ln)); - decision!(ignore_llvm(config, ln)); - decision!(ignore_cdb(config, ln)); - decision!(ignore_gdb(config, ln)); - decision!(ignore_lldb(config, ln)); - - if config.target == "wasm32-unknown-unknown" { - if config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS) { - decision!(IgnoreDecision::Ignore { - reason: "ignored when checking the run results on WASM".into(), - }); + decision!(cfg::handle_only(config, ln)); + decision!(needs::handle_needs(&cache.needs, config, ln)); + decision!(ignore_llvm(config, ln)); + decision!(ignore_cdb(config, ln)); + decision!(ignore_gdb(config, ln)); + decision!(ignore_lldb(config, ln)); + + if config.target == "wasm32-unknown-unknown" { + if config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS) { + decision!(IgnoreDecision::Ignore { + reason: "ignored when checking the run results on WASM".into(), + }); + } } - } - should_fail |= config.parse_name_directive(ln, "should-fail"); - }); + should_fail |= config.parse_name_directive(ln, "should-fail"); + }, + ); + + if local_poisoned { + eprintln!("errors encountered when trying to make test description: {}", path.display()); + panic!("errors encountered when trying to make test description"); + } // The `should-fail` annotation doesn't apply to pretty tests, // since we run the pretty printer across all tests by default. diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index c859e8acade..274006ae8c1 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -210,7 +210,7 @@ fn should_fail() { let d = make_test_description(&config, tn.clone(), p, std::io::Cursor::new(""), None); assert_eq!(d.should_panic, test::ShouldPanic::No); - let d = make_test_description(&config, tn, p, std::io::Cursor::new("// should-fail"), None); + let d = make_test_description(&config, tn, p, std::io::Cursor::new("//@ should-fail"), None); assert_eq!(d.should_panic, test::ShouldPanic::Yes); } @@ -218,7 +218,7 @@ fn should_fail() { fn revisions() { let config: Config = cfg().build(); - assert_eq!(parse_rs(&config, "// revisions: a b c").revisions, vec!["a", "b", "c"],); + assert_eq!(parse_rs(&config, "//@ revisions: a b c").revisions, vec!["a", "b", "c"],); assert_eq!( parse_makefile(&config, "# revisions: hello there").revisions, vec!["hello", "there"], @@ -233,8 +233,8 @@ fn aux_build() { parse_rs( &config, r" - // aux-build: a.rs - // aux-build: b.rs + //@ aux-build: a.rs + //@ aux-build: b.rs " ) .aux, @@ -245,128 +245,128 @@ fn aux_build() { #[test] fn llvm_version() { let config: Config = cfg().llvm_version("8.1.2").build(); - assert!(check_ignore(&config, "// min-llvm-version: 9.0")); + assert!(check_ignore(&config, "//@ min-llvm-version: 9.0")); let config: Config = cfg().llvm_version("9.0.1").build(); - assert!(check_ignore(&config, "// min-llvm-version: 9.2")); + assert!(check_ignore(&config, "//@ min-llvm-version: 9.2")); let config: Config = cfg().llvm_version("9.3.1").build(); - assert!(!check_ignore(&config, "// min-llvm-version: 9.2")); + assert!(!check_ignore(&config, "//@ min-llvm-version: 9.2")); let config: Config = cfg().llvm_version("10.0.0").build(); - assert!(!check_ignore(&config, "// min-llvm-version: 9.0")); + assert!(!check_ignore(&config, "//@ min-llvm-version: 9.0")); } #[test] fn system_llvm_version() { let config: Config = cfg().system_llvm(true).llvm_version("17.0.0").build(); - assert!(check_ignore(&config, "// min-system-llvm-version: 18.0")); + assert!(check_ignore(&config, "//@ min-system-llvm-version: 18.0")); let config: Config = cfg().system_llvm(true).llvm_version("18.0.0").build(); - assert!(!check_ignore(&config, "// min-system-llvm-version: 18.0")); + assert!(!check_ignore(&config, "//@ min-system-llvm-version: 18.0")); let config: Config = cfg().llvm_version("17.0.0").build(); - assert!(!check_ignore(&config, "// min-system-llvm-version: 18.0")); + assert!(!check_ignore(&config, "//@ min-system-llvm-version: 18.0")); } #[test] fn ignore_target() { let config: Config = cfg().target("x86_64-unknown-linux-gnu").build(); - assert!(check_ignore(&config, "// ignore-x86_64-unknown-linux-gnu")); - assert!(check_ignore(&config, "// ignore-x86_64")); - assert!(check_ignore(&config, "// ignore-linux")); - assert!(check_ignore(&config, "// ignore-gnu")); - assert!(check_ignore(&config, "// ignore-64bit")); + assert!(check_ignore(&config, "//@ ignore-x86_64-unknown-linux-gnu")); + assert!(check_ignore(&config, "//@ ignore-x86_64")); + assert!(check_ignore(&config, "//@ ignore-linux")); + assert!(check_ignore(&config, "//@ ignore-gnu")); + assert!(check_ignore(&config, "//@ ignore-64bit")); - assert!(!check_ignore(&config, "// ignore-x86")); - assert!(!check_ignore(&config, "// ignore-windows")); - assert!(!check_ignore(&config, "// ignore-msvc")); - assert!(!check_ignore(&config, "// ignore-32bit")); + assert!(!check_ignore(&config, "//@ ignore-x86")); + assert!(!check_ignore(&config, "//@ ignore-windows")); + assert!(!check_ignore(&config, "//@ ignore-msvc")); + assert!(!check_ignore(&config, "//@ ignore-32bit")); } #[test] fn only_target() { let config: Config = cfg().target("x86_64-pc-windows-gnu").build(); - assert!(check_ignore(&config, "// only-x86")); - assert!(check_ignore(&config, "// only-linux")); - assert!(check_ignore(&config, "// only-msvc")); - assert!(check_ignore(&config, "// only-32bit")); + assert!(check_ignore(&config, "//@ only-x86")); + assert!(check_ignore(&config, "//@ only-linux")); + assert!(check_ignore(&config, "//@ only-msvc")); + assert!(check_ignore(&config, "//@ only-32bit")); - assert!(!check_ignore(&config, "// only-x86_64-pc-windows-gnu")); - assert!(!check_ignore(&config, "// only-x86_64")); - assert!(!check_ignore(&config, "// only-windows")); - assert!(!check_ignore(&config, "// only-gnu")); - assert!(!check_ignore(&config, "// only-64bit")); + assert!(!check_ignore(&config, "//@ only-x86_64-pc-windows-gnu")); + assert!(!check_ignore(&config, "//@ only-x86_64")); + assert!(!check_ignore(&config, "//@ only-windows")); + assert!(!check_ignore(&config, "//@ only-gnu")); + assert!(!check_ignore(&config, "//@ only-64bit")); } #[test] fn stage() { let config: Config = cfg().stage_id("stage1-x86_64-unknown-linux-gnu").build(); - assert!(check_ignore(&config, "// ignore-stage1")); - assert!(!check_ignore(&config, "// ignore-stage2")); + assert!(check_ignore(&config, "//@ ignore-stage1")); + assert!(!check_ignore(&config, "//@ ignore-stage2")); } #[test] fn cross_compile() { let config: Config = cfg().host("x86_64-apple-darwin").target("wasm32-unknown-unknown").build(); - assert!(check_ignore(&config, "// ignore-cross-compile")); + assert!(check_ignore(&config, "//@ ignore-cross-compile")); let config: Config = cfg().host("x86_64-apple-darwin").target("x86_64-apple-darwin").build(); - assert!(!check_ignore(&config, "// ignore-cross-compile")); + assert!(!check_ignore(&config, "//@ ignore-cross-compile")); } #[test] fn debugger() { let mut config = cfg().build(); config.debugger = None; - assert!(!check_ignore(&config, "// ignore-cdb")); + assert!(!check_ignore(&config, "//@ ignore-cdb")); config.debugger = Some(Debugger::Cdb); - assert!(check_ignore(&config, "// ignore-cdb")); + assert!(check_ignore(&config, "//@ ignore-cdb")); config.debugger = Some(Debugger::Gdb); - assert!(check_ignore(&config, "// ignore-gdb")); + assert!(check_ignore(&config, "//@ ignore-gdb")); config.debugger = Some(Debugger::Lldb); - assert!(check_ignore(&config, "// ignore-lldb")); + assert!(check_ignore(&config, "//@ ignore-lldb")); } #[test] fn git_hash() { let config: Config = cfg().git_hash(false).build(); - assert!(check_ignore(&config, "// needs-git-hash")); + assert!(check_ignore(&config, "//@ needs-git-hash")); let config: Config = cfg().git_hash(true).build(); - assert!(!check_ignore(&config, "// needs-git-hash")); + assert!(!check_ignore(&config, "//@ needs-git-hash")); } #[test] fn sanitizers() { // Target that supports all sanitizers: let config: Config = cfg().target("x86_64-unknown-linux-gnu").build(); - assert!(!check_ignore(&config, "// needs-sanitizer-address")); - assert!(!check_ignore(&config, "// needs-sanitizer-leak")); - assert!(!check_ignore(&config, "// needs-sanitizer-memory")); - assert!(!check_ignore(&config, "// needs-sanitizer-thread")); + assert!(!check_ignore(&config, "//@ needs-sanitizer-address")); + assert!(!check_ignore(&config, "//@ needs-sanitizer-leak")); + assert!(!check_ignore(&config, "//@ needs-sanitizer-memory")); + assert!(!check_ignore(&config, "//@ needs-sanitizer-thread")); // Target that doesn't support sanitizers: let config: Config = cfg().target("wasm32-unknown-emscripten").build(); - assert!(check_ignore(&config, "// needs-sanitizer-address")); - assert!(check_ignore(&config, "// needs-sanitizer-leak")); - assert!(check_ignore(&config, "// needs-sanitizer-memory")); - assert!(check_ignore(&config, "// needs-sanitizer-thread")); + assert!(check_ignore(&config, "//@ needs-sanitizer-address")); + assert!(check_ignore(&config, "//@ needs-sanitizer-leak")); + assert!(check_ignore(&config, "//@ needs-sanitizer-memory")); + assert!(check_ignore(&config, "//@ needs-sanitizer-thread")); } #[test] fn profiler_support() { let config: Config = cfg().profiler_support(false).build(); - assert!(check_ignore(&config, "// needs-profiler-support")); + assert!(check_ignore(&config, "//@ needs-profiler-support")); let config: Config = cfg().profiler_support(true).build(); - assert!(!check_ignore(&config, "// needs-profiler-support")); + assert!(!check_ignore(&config, "//@ needs-profiler-support")); } #[test] @@ -382,7 +382,7 @@ fn asm_support() { for (target, has_asm) in asms { let config = cfg().target(target).build(); assert_eq!(config.has_asm_support(), has_asm); - assert_eq!(check_ignore(&config, "// needs-asm-support"), !has_asm) + assert_eq!(check_ignore(&config, "//@ needs-asm-support"), !has_asm) } } @@ -390,13 +390,13 @@ fn asm_support() { fn channel() { let config: Config = cfg().channel("beta").build(); - assert!(check_ignore(&config, "// ignore-beta")); - assert!(check_ignore(&config, "// only-nightly")); - assert!(check_ignore(&config, "// only-stable")); + assert!(check_ignore(&config, "//@ ignore-beta")); + assert!(check_ignore(&config, "//@ only-nightly")); + assert!(check_ignore(&config, "//@ only-stable")); - assert!(!check_ignore(&config, "// only-beta")); - assert!(!check_ignore(&config, "// ignore-nightly")); - assert!(!check_ignore(&config, "// ignore-stable")); + assert!(!check_ignore(&config, "//@ only-beta")); + assert!(!check_ignore(&config, "//@ ignore-nightly")); + assert!(!check_ignore(&config, "//@ ignore-stable")); } #[test] @@ -418,7 +418,7 @@ fn test_extract_version_range() { #[should_panic(expected = "Duplicate revision: `rpass1` in line ` rpass1 rpass1`")] fn test_duplicate_revisions() { let config: Config = cfg().build(); - parse_rs(&config, "// revisions: rpass1 rpass1"); + parse_rs(&config, "//@ revisions: rpass1 rpass1"); } #[test] @@ -432,7 +432,7 @@ fn ignore_arch() { for (target, arch) in archs { let config: Config = cfg().target(target).build(); assert!(config.matches_arch(arch), "{target} {arch}"); - assert!(check_ignore(&config, &format!("// ignore-{arch}"))); + assert!(check_ignore(&config, &format!("//@ ignore-{arch}"))); } } @@ -447,7 +447,7 @@ fn matches_os() { for (target, os) in oss { let config = cfg().target(target).build(); assert!(config.matches_os(os), "{target} {os}"); - assert!(check_ignore(&config, &format!("// ignore-{os}"))); + assert!(check_ignore(&config, &format!("//@ ignore-{os}"))); } } @@ -461,7 +461,7 @@ fn matches_env() { for (target, env) in envs { let config: Config = cfg().target(target).build(); assert!(config.matches_env(env), "{target} {env}"); - assert!(check_ignore(&config, &format!("// ignore-{env}"))); + assert!(check_ignore(&config, &format!("//@ ignore-{env}"))); } } @@ -475,7 +475,7 @@ fn matches_abi() { for (target, abi) in abis { let config: Config = cfg().target(target).build(); assert!(config.matches_abi(abi), "{target} {abi}"); - assert!(check_ignore(&config, &format!("// ignore-{abi}"))); + assert!(check_ignore(&config, &format!("//@ ignore-{abi}"))); } } @@ -491,7 +491,7 @@ fn is_big_endian() { for (target, is_big) in endians { let config = cfg().target(target).build(); assert_eq!(config.is_big_endian(), is_big, "{target} {is_big}"); - assert_eq!(check_ignore(&config, "// ignore-endian-big"), is_big); + assert_eq!(check_ignore(&config, "//@ ignore-endian-big"), is_big); } } @@ -506,9 +506,9 @@ fn pointer_width() { for (target, width) in widths { let config: Config = cfg().target(target).build(); assert_eq!(config.get_pointer_width(), width, "{target} {width}"); - assert_eq!(check_ignore(&config, "// ignore-16bit"), width == 16); - assert_eq!(check_ignore(&config, "// ignore-32bit"), width == 32); - assert_eq!(check_ignore(&config, "// ignore-64bit"), width == 64); + assert_eq!(check_ignore(&config, "//@ ignore-16bit"), width == 16); + assert_eq!(check_ignore(&config, "//@ ignore-32bit"), width == 32); + assert_eq!(check_ignore(&config, "//@ ignore-64bit"), width == 64); } } @@ -534,7 +534,7 @@ fn wasm_special() { for (target, pattern, ignore) in ignores { let config: Config = cfg().target(target).build(); assert_eq!( - check_ignore(&config, &format!("// ignore-{pattern}")), + check_ignore(&config, &format!("//@ ignore-{pattern}")), ignore, "{target} {pattern}" ); @@ -555,8 +555,8 @@ fn families() { assert!(config.matches_family(family)); let other = if family == "windows" { "unix" } else { "windows" }; assert!(!config.matches_family(other)); - assert!(check_ignore(&config, &format!("// ignore-{family}"))); - assert!(!check_ignore(&config, &format!("// ignore-{other}"))); + assert!(check_ignore(&config, &format!("//@ ignore-{family}"))); + assert!(!check_ignore(&config, &format!("//@ ignore-{other}"))); } } @@ -566,10 +566,17 @@ fn ignore_mode() { // Indicate profiler support so that "coverage-run" tests aren't skipped. let config: Config = cfg().mode(mode).profiler_support(true).build(); let other = if mode == "coverage-run" { "coverage-map" } else { "coverage-run" }; + assert_ne!(mode, other); assert_eq!(config.mode, Mode::from_str(mode).unwrap()); assert_ne!(config.mode, Mode::from_str(other).unwrap()); - assert!(check_ignore(&config, &format!("// ignore-mode-{mode}"))); - assert!(!check_ignore(&config, &format!("// ignore-mode-{other}"))); + + if mode == "ui" { + assert!(check_ignore(&config, &format!("//@ ignore-mode-{mode}"))); + assert!(!check_ignore(&config, &format!("//@ ignore-mode-{other}"))); + } else { + assert!(check_ignore(&config, &format!("// ignore-mode-{mode}"))); + assert!(!check_ignore(&config, &format!("// ignore-mode-{other}"))); + } } } diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 2115e482c64..ab6f899cd3a 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -0f806a9812b62c36bdab08d33c14cf2d3ecf4355 +4316d0c6252cb1f833e582dfa68adb98efd5ddfb diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 9319877472e..db4c4a28deb 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -1,3 +1,4 @@ +#![feature(generic_nonzero)] #![feature(rustc_private, stmt_expr_attributes)] #![allow( clippy::manual_range_contains, @@ -19,7 +20,7 @@ extern crate rustc_session; extern crate tracing; use std::env::{self, VarError}; -use std::num::NonZeroU64; +use std::num::NonZero; use std::path::PathBuf; use std::str::FromStr; @@ -524,7 +525,7 @@ fn main() { } } } else if let Some(param) = arg.strip_prefix("-Zmiri-track-alloc-id=") { - let ids: Vec<miri::AllocId> = match parse_comma_list::<NonZeroU64>(param) { + let ids: Vec<miri::AllocId> = match parse_comma_list::<NonZero<u64>>(param) { Ok(ids) => ids.into_iter().map(miri::AllocId).collect(), Err(err) => show_error!( diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index f50aaa292fd..711323b51c2 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -1,6 +1,6 @@ use std::cell::RefCell; use std::fmt; -use std::num::NonZeroU64; +use std::num::NonZero; use smallvec::SmallVec; @@ -12,22 +12,22 @@ use crate::*; pub mod stacked_borrows; pub mod tree_borrows; -pub type CallId = NonZeroU64; +pub type CallId = NonZero<u64>; /// Tracking pointer provenance #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct BorTag(NonZeroU64); +pub struct BorTag(NonZero<u64>); impl BorTag { pub fn new(i: u64) -> Option<Self> { - NonZeroU64::new(i).map(BorTag) + NonZero::new(i).map(BorTag) } pub fn get(&self) -> u64 { self.0.get() } - pub fn inner(&self) -> NonZeroU64 { + pub fn inner(&self) -> NonZero<u64> { self.0 } @@ -183,7 +183,7 @@ impl GlobalStateInner { borrow_tracker_method, next_ptr_tag: BorTag::one(), base_ptr_tags: FxHashMap::default(), - next_call_id: NonZeroU64::new(1).unwrap(), + next_call_id: NonZero::new(1).unwrap(), protected_tags: FxHashMap::default(), tracked_pointer_tags, tracked_call_ids, @@ -205,7 +205,7 @@ impl GlobalStateInner { if self.tracked_call_ids.contains(&call_id) { machine.emit_diagnostic(NonHaltingDiagnostic::CreatedCallId(call_id)); } - self.next_call_id = NonZeroU64::new(call_id.get() + 1).unwrap(); + self.next_call_id = NonZero::new(call_id.get() + 1).unwrap(); FrameState { call_id, protected_tags: SmallVec::new() } } diff --git a/src/tools/miri/src/concurrency/init_once.rs b/src/tools/miri/src/concurrency/init_once.rs index 9a848d50341..35dcfecbbe3 100644 --- a/src/tools/miri/src/concurrency/init_once.rs +++ b/src/tools/miri/src/concurrency/init_once.rs @@ -1,5 +1,4 @@ use std::collections::VecDeque; -use std::num::NonZeroU32; use rustc_index::Idx; use rustc_middle::ty::layout::TyAndLayout; diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index 68631190325..956a02ded0f 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -1,5 +1,4 @@ use std::collections::{hash_map::Entry, VecDeque}; -use std::num::NonZeroU32; use std::ops::Not; use rustc_data_structures::fx::FxHashMap; @@ -24,12 +23,12 @@ macro_rules! declare_id { /// 0 is used to indicate that the id was not yet assigned and, /// therefore, is not a valid identifier. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] - pub struct $name(NonZeroU32); + pub struct $name(std::num::NonZero<u32>); impl SyncId for $name { // Panics if `id == 0`. fn from_u32(id: u32) -> Self { - Self(NonZeroU32::new(id).unwrap()) + Self(std::num::NonZero::new(id).unwrap()) } fn to_u32(&self) -> u32 { self.0.get() @@ -42,11 +41,11 @@ macro_rules! declare_id { // therefore, need to shift by one when converting from an index // into a vector. let shifted_idx = u32::try_from(idx).unwrap().checked_add(1).unwrap(); - $name(NonZeroU32::new(shifted_idx).unwrap()) + $name(std::num::NonZero::new(shifted_idx).unwrap()) } fn index(self) -> usize { // See the comment in `Self::new`. - // (This cannot underflow because self is NonZeroU32.) + // (This cannot underflow because `self.0` is `NonZero<u32>`.) usize::try_from(self.0.get() - 1).unwrap() } } diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 7825673db00..d47f446716b 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -1,5 +1,5 @@ use std::fmt::{self, Write}; -use std::num::NonZeroU64; +use std::num::NonZero; use rustc_errors::{DiagnosticBuilder, DiagnosticMessage, Level}; use rustc_span::{SpanData, Symbol, DUMMY_SP}; @@ -110,7 +110,7 @@ pub enum NonHaltingDiagnostic { /// (new_tag, new_perm, (alloc_id, base_offset, orig_tag)) /// /// new_perm is `None` for base tags. - CreatedPointerTag(NonZeroU64, Option<String>, Option<(AllocId, AllocRange, ProvenanceExtra)>), + CreatedPointerTag(NonZero<u64>, Option<String>, Option<(AllocId, AllocRange, ProvenanceExtra)>), /// This `Item` was popped from the borrow stack. The string explains the reason. PoppedPointerTag(Item, String), CreatedCallId(CallId), diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 932a35d9bf0..d9b4363d604 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1,6 +1,6 @@ use std::cmp; use std::iter; -use std::num::NonZeroUsize; +use std::num::NonZero; use std::time::Duration; use rustc_apfloat::ieee::{Double, Single}; @@ -572,7 +572,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn visit_union( &mut self, _v: &MPlaceTy<'tcx, Provenance>, - _fields: NonZeroUsize, + _fields: NonZero<usize>, ) -> InterpResult<'tcx> { bug!("we should have already handled unions in `visit_value`") } diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index adc547aa6cd..c567949102f 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -1,6 +1,7 @@ #![feature(rustc_private)] #![feature(cell_update)] #![feature(float_gamma)] +#![feature(generic_nonzero)] #![feature(map_try_insert)] #![feature(never_type)] #![feature(try_blocks)] diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index f4d69055344..0645c1f176e 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -475,7 +475,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let [id, show_unnamed] = this.check_shim(abi, Abi::Rust, link_name, args)?; let id = this.read_scalar(id)?.to_u64()?; let show_unnamed = this.read_scalar(show_unnamed)?.to_bool()?; - if let Some(id) = std::num::NonZeroU64::new(id) { + if let Some(id) = std::num::NonZero::new(id) { this.print_borrow_state(AllocId(id), show_unnamed)?; } } diff --git a/src/tools/miri/tests/pass/intrinsics.rs b/src/tools/miri/tests/pass/intrinsics.rs index 8e46bd7ad48..0dda5aadce2 100644 --- a/src/tools/miri/tests/pass/intrinsics.rs +++ b/src/tools/miri/tests/pass/intrinsics.rs @@ -37,7 +37,7 @@ fn main() { let mut saw_false = false; for _ in 0..50 { - if unsafe { intrinsics::is_val_statically_known(0) } { + if intrinsics::is_val_statically_known(0) { saw_true = true; } else { saw_false = true; diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 8b0e80a94b0..a8aae6f5bc9 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -55,11 +55,14 @@ const ANNOTATIONS_TO_IGNORE: &[&str] = &[ "// CHECK", "// EMIT_MIR", "// compile-flags", + "//@ compile-flags", "// error-pattern", + "//@ error-pattern", "// gdb", "// lldb", "// cdb", "// normalize-stderr-test", + "//@ normalize-stderr-test", ]; // Intentionally written in decimal rather than hex @@ -128,7 +131,15 @@ fn should_ignore(line: &str) -> bool { // This mirrors the regex in src/tools/compiletest/src/runtest.rs, please // update both if either are changed. let re = Regex::new("\\s*//(\\[.*\\])?~.*").unwrap(); - re.is_match(line) || ANNOTATIONS_TO_IGNORE.iter().any(|a| line.contains(a)) + // For `ui_test`-style UI test directives, also ignore + // - `//@[rev] compile-flags` + // - `//@[rev] normalize-stderr-test` + let ui_test_long_directives = + Regex::new("\\s*//@(\\[.*\\]) (compile-flags|normalize-stderr-test|error-pattern).*") + .unwrap(); + re.is_match(line) + || ANNOTATIONS_TO_IGNORE.iter().any(|a| line.contains(a)) + || ui_test_long_directives.is_match(line) } /// Returns `true` if `line` is allowed to be longer than the normal limit. diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 1dbd221fde5..5517b9fdcec 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -14,8 +14,9 @@ use std::path::{Path, PathBuf}; // #73494. const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. + const ISSUES_ENTRY_LIMIT: usize = 1781; -const ROOT_ENTRY_LIMIT: usize = 870; +const ROOT_ENTRY_LIMIT: usize = 871; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files |
