From 3b57db4d87ea589ec05e2c7543fb6ad2df41795f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 1 Jul 2025 06:59:49 +0000 Subject: Give some UI tests more apropriate names Prepare for rework done by the rest of RUST-142440. Co-authored-by: Kivooeo --- src/tools/tidy/src/issues.txt | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/tools') diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 18da874dbef..0966c3d7935 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -276,7 +276,6 @@ ui/auto-traits/issue-23080-2.rs ui/auto-traits/issue-23080.rs ui/auto-traits/issue-83857-ub.rs ui/auto-traits/issue-84075.rs -ui/auxiliary/issue-16822.rs ui/bench/issue-32062.rs ui/binding/issue-40402-1.rs ui/binding/issue-40402-2.rs @@ -1368,9 +1367,6 @@ ui/infinite/issue-41731-infinite-macro-println.rs ui/intrinsics/issue-28575.rs ui/intrinsics/issue-84297-reifying-copy.rs ui/invalid/issue-114435-layout-type-err.rs -ui/issue-15924.rs -ui/issue-16822.rs -ui/issues-71798.rs ui/issues/auxiliary/issue-11224.rs ui/issues/auxiliary/issue-11508.rs ui/issues/auxiliary/issue-11529.rs -- cgit 1.4.1-3-g733a5 From 7405e2a9154268955de216840ef4dd7e975b0cd5 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 4 Jul 2025 19:20:09 +0800 Subject: Improve compiletest config documentation Including a bunch of FIXMEs. --- src/tools/compiletest/src/common.rs | 395 ++++++++++++++++++++----- src/tools/compiletest/src/debuggers.rs | 2 + src/tools/compiletest/src/executor.rs | 12 +- src/tools/compiletest/src/lib.rs | 11 + src/tools/compiletest/src/runtest.rs | 22 +- src/tools/compiletest/src/runtest/debuginfo.rs | 4 + 6 files changed, 353 insertions(+), 93 deletions(-) (limited to 'src/tools') diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index cdce5d941d0..7122746fa87 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -172,207 +172,422 @@ pub enum Sanitizer { Hwaddress, } -/// Configuration for compiletest +/// Configuration for `compiletest` *per invocation*. +/// +/// In terms of `bootstrap`, this means that `./x test tests/ui tests/run-make` actually correspond +/// to *two* separate invocations of `compiletest`. +/// +/// FIXME: this `Config` struct should be broken up into smaller logically contained sub-config +/// structs, it's too much of a "soup" of everything at the moment. +/// +/// # Configuration sources +/// +/// Configuration values for `compiletest` comes from several sources: +/// +/// - CLI args passed from `bootstrap` while running the `compiletest` binary. +/// - Env vars. +/// - Discovery (e.g. trying to identify a suitable debugger based on filesystem discovery). +/// - Cached output of running the `rustc` under test (e.g. output of `rustc` print requests). +/// +/// FIXME: make sure we *clearly* account for sources of *all* config options. +/// +/// FIXME: audit these options to make sure we are not hashing less than necessary for build stamp +/// (for changed test detection). #[derive(Debug, Default, Clone)] pub struct Config { - /// `true` to overwrite stderr/stdout files instead of complaining about changes in output. + /// Some test [`Mode`]s support [snapshot testing], where a *reference snapshot* of outputs (of + /// `stdout`, `stderr`, or other form of artifacts) can be compared to the *actual output*. + /// + /// This option can be set to `true` to update the *reference snapshots* in-place, otherwise + /// `compiletest` will only try to compare. + /// + /// [snapshot testing]: https://jestjs.io/docs/snapshot-testing pub bless: bool, - /// Stop as soon as possible after any test fails. - /// May run a few more tests before stopping, due to threading. + /// Attempt to stop as soon as possible after any test fails. We may still run a few more tests + /// before stopping when multiple test threads are used. pub fail_fast: bool, - /// The library paths required for running the compiler. + /// Path to libraries needed to run the *staged* `rustc`-under-test on the **host** platform. + /// + /// FIXME: maybe rename this to reflect (1) which target platform (host, not target), and (2) + /// which `rustc` (the `rustc`-under-test, not the stage 0 `rustc` unless forced). pub compile_lib_path: Utf8PathBuf, - /// The library paths required for running compiled programs. + /// Path to libraries needed to run the compiled executable for the **target** platform. This + /// corresponds to the **target** sysroot libraries, including the **target** standard library. + /// + /// FIXME: maybe rename this to reflect (1) which target platform (target, not host), and (2) + /// what "run libraries" are against. + /// + /// FIXME: this is very under-documented in conjunction with the `remote-test-client` scheme and + /// `RUNNER` scheme to actually run the target executable under the target platform environment, + /// cf. [`Self::remote_test_client`] and [`Self::runner`]. pub run_lib_path: Utf8PathBuf, - /// The rustc executable. + /// Path to the *staged* `rustc`-under-test. Unless forced, this `rustc` is *staged*, and must + /// not be confused with [`Self::stage0_rustc_path`]. + /// + /// FIXME: maybe rename this to reflect that this is the `rustc`-under-test. pub rustc_path: Utf8PathBuf, - /// The cargo executable. + /// Path to a *staged* **host** platform cargo executable (unless stage 0 is forced). This + /// staged `cargo` is only used within `run-make` test recipes during recipe run time (and is + /// *not* used to compile the test recipes), and so must be staged as there may be differences + /// between e.g. beta `cargo` vs in-tree `cargo`. + /// + /// FIXME: maybe rename this to reflect that this is a *staged* host cargo. + /// + /// FIXME(#134109): split `run-make` into two test suites, a test suite *with* staged cargo, and + /// another test suite *without*. pub cargo_path: Option, - /// Rustc executable used to compile run-make recipes. + /// Path to the stage 0 `rustc` used to build `run-make` recipes. This must not be confused with + /// [`Self::rustc_path`]. pub stage0_rustc_path: Option, - /// The rustdoc executable. + /// Path to the `rustdoc`-under-test. Like [`Self::rustc_path`], this `rustdoc` is *staged*. pub rustdoc_path: Option, - /// The coverage-dump executable. + /// Path to the `src/tools/coverage-dump/` bootstrap tool executable. pub coverage_dump_path: Option, - /// The Python executable to use for LLDB and htmldocck. + /// Path to the Python 3 executable to use for LLDB and htmldocck. + /// + /// FIXME: the `lldb` setup currently requires I believe Python 3.10 **exactly**, it can't even + /// be Python 3.11 or 3.9... pub python: String, - /// The jsondocck executable. + /// Path to the `src/tools/jsondocck/` bootstrap tool executable. pub jsondocck_path: Option, - /// The jsondoclint executable. + /// Path to the `src/tools/jsondoclint/` bootstrap tool executable. pub jsondoclint_path: Option, - /// The LLVM `FileCheck` binary path. + /// Path to a host LLVM `FileCheck` executable. pub llvm_filecheck: Option, - /// Path to LLVM's bin directory. + /// Path to a host LLVM bintools directory. pub llvm_bin_dir: Option, - /// The path to the Clang executable to run Clang-based tests with. If - /// `None` then these tests will be ignored. + /// The path to the **target** `clang` executable to run `clang`-based tests with. If `None`, + /// then these tests will be ignored. pub run_clang_based_tests_with: Option, - /// The directory containing the sources. + /// Path to the directory containing the sources. This corresponds to the root folder of a + /// `rust-lang/rust` checkout. + /// + /// FIXME: this name is confusing, because this is actually `$checkout_root`, **not** the + /// `$checkout_root/src/` folder. pub src_root: Utf8PathBuf, - /// The directory containing the test suite sources. Must be a subdirectory of `src_root`. + + /// Path to the directory containing the test suites sources. This corresponds to the + /// `$src_root/tests/` folder. + /// + /// Must be an immediate subdirectory of [`Self::src_root`]. + /// + /// FIXME: this name is also confusing, maybe just call it `tests_root`. pub src_test_suite_root: Utf8PathBuf, - /// Root build directory (e.g. `build/`). + /// Path to the build directory (e.g. `build/`). pub build_root: Utf8PathBuf, - /// Test suite specific build directory (e.g. `build/host/test/ui/`). + + /// Path to the test suite specific build directory (e.g. `build/host/test/ui/`). + /// + /// Must be a subdirectory of [`Self::build_root`]. pub build_test_suite_root: Utf8PathBuf, - /// The directory containing the compiler sysroot + /// Path to the directory containing the sysroot of the `rustc`-under-test. + /// + /// When stage 0 is forced, this will correspond to the sysroot *of* that specified stage 0 + /// `rustc`. + /// + /// FIXME: this name is confusing, because it doesn't specify *which* compiler this sysroot + /// corresponds to. It's actually the `rustc`-under-test, and not the bootstrap `rustc`, unless + /// stage 0 is forced and no custom stage 0 `rustc` was otherwise specified (so that it + /// *happens* to run against the bootstrap `rustc`, but this non-custom bootstrap `rustc` case + /// is not really supported). pub sysroot_base: Utf8PathBuf, /// The number of the stage under test. pub stage: u32, + /// The id of the stage under test (stage1-xxx, etc). + /// + /// FIXME: reconsider this string; this is hashed for test build stamp. pub stage_id: String, - /// The test mode, e.g. ui or debuginfo. + /// The test [`Mode`]. E.g. [`Mode::Ui`]. Each test mode can correspond to one or more test + /// suites. + /// + /// FIXME: stop using stringly-typed test suites! pub mode: Mode, - /// The test suite (essentially which directory is running, but without the - /// directory prefix such as tests) + /// The test suite. + /// + /// Example: `tests/ui/` is the "UI" test *suite*, which happens to also be of the [`Mode::Ui`] + /// test *mode*. + /// + /// Note that the same test directory (e.g. `tests/coverage/`) may correspond to multiple test + /// modes, e.g. `tests/coverage/` can be run under both [`Mode::CoverageRun`] and + /// [`Mode::CoverageMap`]. + /// + /// FIXME: stop using stringly-typed test suites! pub suite: String, - /// The debugger to use in debuginfo mode. Unset otherwise. + /// When specified, **only** the specified [`Debugger`] will be used to run against the + /// `tests/debuginfo` test suite. When unspecified, `compiletest` will attempt to find all three + /// of {`lldb`, `cdb`, `gdb`} implicitly, and then try to run the `debuginfo` test suite against + /// all three debuggers. + /// + /// FIXME: this implicit behavior is really nasty, in that it makes it hard for the user to + /// control *which* debugger(s) are available and used to run the debuginfo test suite. We + /// should have `bootstrap` allow the user to *explicitly* configure the debuggers, and *not* + /// try to implicitly discover some random debugger from the user environment. This makes the + /// debuginfo test suite particularly hard to work with. pub debugger: Option, - /// Run ignored tests + /// Run ignored tests *unconditionally*, overriding their ignore reason. + /// + /// FIXME: this is wired up through the test execution logic, but **not** accessible from + /// `bootstrap` directly; `compiletest` exposes this as `--ignored`. I.e. you'd have to use `./x + /// test $test_suite -- --ignored=true`. pub run_ignored: bool, - /// Whether rustc was built with debug assertions. + /// Whether *staged* `rustc`-under-test was built with debug assertions. + /// + /// FIXME: make it clearer that this refers to the staged `rustc`-under-test, not stage 0 + /// `rustc`. pub with_rustc_debug_assertions: bool, - /// Whether std was built with debug assertions. + /// Whether *staged* `std` was built with debug assertions. + /// + /// FIXME: make it clearer that this refers to the staged `std`, not stage 0 `std`. pub with_std_debug_assertions: bool, - /// Only run tests that match these filters + /// Only run tests that match these filters (using `libtest` "test name contains" filter logic). + /// + /// FIXME(#139660): the current hand-rolled test executor intentionally mimics the `libtest` + /// "test name contains" filter matching logic to preserve previous `libtest` executor behavior, + /// but this is often not intuitive. We should consider changing that behavior with an MCP to do + /// test path *prefix* matching which better corresponds to how `compiletest` `tests/` are + /// organized, and how users would intuitively expect the filtering logic to work like. pub filters: Vec, - /// Skip tests matching these substrings. Corresponds to - /// `test::TestOpts::skip`. `filter_exact` does not apply to these flags. + /// Skip tests matching these substrings. The matching logic exactly corresponds to + /// [`Self::filters`] but inverted. + /// + /// FIXME(#139660): ditto on test matching behavior. pub skip: Vec, - /// Exactly match the filter, rather than a substring + /// Exactly match the filter, rather than a substring. + /// + /// FIXME(#139660): ditto on test matching behavior. pub filter_exact: bool, - /// Force the pass mode of a check/build/run-pass test to this mode. + /// Force the pass mode of a check/build/run test to instead use this mode instead. + /// + /// FIXME: make it even more obvious (especially in PR CI where `--pass=check` is used) when a + /// pass mode is forced when the test fails, because it can be very non-obvious when e.g. an + /// error is emitted only when `//@ build-pass` but not `//@ check-pass`. pub force_pass_mode: Option, - /// Explicitly enable or disable running. + /// Explicitly enable or disable running of the target test binary. + /// + /// FIXME: this scheme is a bit confusing, and at times questionable. Re-evaluate this run + /// scheme. + /// + /// FIXME: Currently `--run` is a tri-state, it can be `--run={auto,always,never}`, and when + /// `--run=auto` is specified, it's run if the platform doesn't end with `-fuchsia`. See + /// [`Config::run_enabled`]. pub run: Option, - /// A command line to prefix program execution with, - /// for running under valgrind for example. + /// A command line to prefix target program execution with, for running under valgrind for + /// example, i.e. `$runner target.exe [args..]`. Similar to `CARGO_*_RUNNER` configuration. + /// + /// Note: this is not to be confused with [`Self::remote_test_client`], which is a different + /// scheme. /// - /// Similar to `CARGO_*_RUNNER` configuration. + /// FIXME: the runner scheme is very under-documented. pub runner: Option, - /// Flags to pass to the compiler when building for the host + /// Compiler flags to pass to the *staged* `rustc`-under-test when building for the **host** + /// platform. pub host_rustcflags: Vec, - /// Flags to pass to the compiler when building for the target + /// Compiler flags to pass to the *staged* `rustc`-under-test when building for the **target** + /// platform. pub target_rustcflags: Vec, - /// Whether the compiler and stdlib has been built with randomized struct layouts + /// Whether the *staged* `rustc`-under-test and the associated *staged* `std` has been built + /// with randomized struct layouts. pub rust_randomized_layout: bool, - /// Whether tests should be optimized by default. Individual test-suites and test files may - /// override this setting. + /// Whether tests should be optimized by default (`-O`). Individual test suites and test files + /// may override this setting. + /// + /// FIXME: this flag / config option is somewhat misleading. For instance, in ui tests, it's + /// *only* applied to the [`PassMode::Run`] test crate and not its auxiliaries. pub optimize_tests: bool, - /// Target system to be tested + /// Target platform tuple. pub target: String, - /// Host triple for the compiler being invoked + /// Host platform tuple. pub host: String, - /// Path to / name of the Microsoft Console Debugger (CDB) executable + /// Path to / name of the Microsoft Console Debugger (CDB) executable. + /// + /// FIXME: this is an *opt-in* "override" option. When this isn't provided, we try to conjure a + /// cdb by looking at the user's program files on Windows... See `debuggers::find_cdb`. pub cdb: Option, - /// Version of CDB + /// Version of CDB. + /// + /// FIXME: `cdb_version` is *derived* from cdb, but it's *not* technically a config! + /// + /// FIXME: audit cdb version gating. pub cdb_version: Option<[u16; 4]>, - /// Path to / name of the GDB executable + /// Path to / name of the GDB executable. + /// + /// FIXME: the fallback path when `gdb` isn't provided tries to find *a* `gdb` or `gdb.exe` from + /// `PATH`, which is... arguably questionable. + /// + /// FIXME: we are propagating a python from `PYTHONPATH`, not from an explicit config for gdb + /// debugger script. pub gdb: Option, /// Version of GDB, encoded as ((major * 1000) + minor) * 1000 + patch + /// + /// FIXME: this gdb version gating scheme is possibly questionable -- gdb does not use semver, + /// only its major version is likely materially meaningful, cf. + /// . Even the major version I'm not sure + /// is super meaningful. Maybe min gdb `major.minor` version gating is sufficient for the + /// purposes of debuginfo tests? + /// + /// FIXME: `gdb_version` is *derived* from gdb, but it's *not* technically a config! pub gdb_version: Option, - /// Version of LLDB + /// Version of LLDB. + /// + /// FIXME: `lldb_version` is *derived* from lldb, but it's *not* technically a config! pub lldb_version: Option, - /// Version of LLVM + /// Version of LLVM. + /// + /// FIXME: Audit the fallback derivation of + /// [`crate::directives::extract_llvm_version_from_binary`], that seems very questionable? pub llvm_version: Option, - /// Is LLVM a system LLVM + /// Is LLVM a system LLVM. pub system_llvm: bool, - /// Path to the android tools + /// Path to the android tools. + /// + /// Note: this is only used for android gdb debugger script in the debuginfo test suite. + /// + /// FIXME: take a look at this; this is piggy-backing off of gdb code paths but only for + /// `arm-linux-androideabi` target. pub android_cross_path: Utf8PathBuf, - /// Extra parameter to run adb on arm-linux-androideabi + /// Extra parameter to run adb on `arm-linux-androideabi`. + /// + /// FIXME: is this *only* `arm-linux-androideabi`, or is it also for other Tier 2/3 android + /// targets? + /// + /// FIXME: take a look at this; this is piggy-backing off of gdb code paths but only for + /// `arm-linux-androideabi` target. pub adb_path: String, - /// Extra parameter to run test suite on arm-linux-androideabi + /// Extra parameter to run test suite on `arm-linux-androideabi`. + /// + /// FIXME: is this *only* `arm-linux-androideabi`, or is it also for other Tier 2/3 android + /// targets? + /// + /// FIXME: take a look at this; this is piggy-backing off of gdb code paths but only for + /// `arm-linux-androideabi` target. pub adb_test_dir: String, - /// status whether android device available or not + /// Status whether android device available or not. When unavailable, this will cause tests to + /// panic when the test binary is attempted to be run. + /// + /// FIXME: take a look at this; this also influences adb in gdb code paths in a strange way. pub adb_device_status: bool, - /// the path containing LLDB's Python module + /// Path containing LLDB's Python module. + /// + /// FIXME: `PYTHONPATH` takes precedence over this flag...? See `runtest::run_lldb`. pub lldb_python_dir: Option, - /// Explain what's going on + /// Verbose dump a lot of info. + /// + /// FIXME: this is *way* too coarse; the user can't select *which* info to verbosely dump. pub verbose: bool, - /// Print one character per test instead of one line + /// (Useless) Adjust libtest output format. + /// + /// FIXME: the hand-rolled executor does not support non-JSON output, because `compiletest` need + /// to package test outcome as `libtest`-esque JSON that `bootstrap` can intercept *anyway*. + /// However, now that we don't use the `libtest` executor, this is useless. pub format: OutputFormat, - /// Whether to use colors in test. + /// Whether to use colors in test output. + /// + /// Note: the exact control mechanism is delegated to [`colored`]. pub color: ColorConfig, - /// where to find the remote test client process, if we're using it + /// Where to find the remote test client process, if we're using it. + /// + /// Note: this is *only* used for target platform executables created by `run-make` test + /// recipes. + /// + /// Note: this is not to be confused with [`Self::runner`], which is a different scheme. + /// + /// FIXME: the `remote_test_client` scheme is very under-documented. pub remote_test_client: Option, - /// mode describing what file the actual ui output will be compared to + /// [`CompareMode`] describing what file the actual ui output will be compared to. + /// + /// FIXME: currently, [`CompareMode`] is a mishmash of lot of things (different borrow-checker + /// model, different trait solver, different debugger, etc.). pub compare_mode: Option, /// If true, this will generate a coverage file with UI test files that run `MachineApplicable` /// diagnostics but are missing `run-rustfix` annotations. The generated coverage file is - /// created in `/rustfix_missing_coverage.txt` + /// created in `$test_suite_build_root/rustfix_missing_coverage.txt` pub rustfix_coverage: bool, - /// whether to run `tidy` (html-tidy) when a rustdoc test fails + /// Whether to run `tidy` (html-tidy) when a rustdoc test fails. pub has_html_tidy: bool, - /// whether to run `enzyme` autodiff tests + /// Whether to run `enzyme` autodiff tests. pub has_enzyme: bool, - /// The current Rust channel + /// The current Rust channel info. + /// + /// FIXME: treat this more carefully; "stable", "beta" and "nightly" are definitely valid, but + /// channel might also be "dev" or such, which should be treated as "nightly". pub channel: String, - /// Whether adding git commit information such as the commit hash has been enabled for building + /// Whether adding git commit information such as the commit hash has been enabled for building. + /// + /// FIXME: `compiletest` cannot trust `bootstrap` for this information, because `bootstrap` can + /// have bugs and had bugs on that logic. We need to figure out how to obtain this e.g. directly + /// from CI or via git locally. pub git_hash: bool, - /// The default Rust edition + /// The default Rust edition. + /// + /// FIXME: perform stronger validation for this. There are editions that *definitely* exists, + /// but there might also be "future" edition. pub edition: Option, - // Configuration for various run-make tests frobbing things like C compilers - // or querying about various LLVM component information. + // Configuration for various run-make tests frobbing things like C compilers or querying about + // various LLVM component information. + // + // FIXME: this really should be better packaged together. + // FIXME: these need better docs, e.g. for *host*, or for *target*? pub cc: String, pub cxx: String, pub cflags: String, @@ -382,41 +597,63 @@ pub struct Config { pub host_linker: Option, pub llvm_components: String, - /// Path to a NodeJS executable. Used for JS doctests, emscripten and WASM tests + /// Path to a NodeJS executable. Used for JS doctests, emscripten and WASM tests. pub nodejs: Option, - /// Path to a npm executable. Used for rustdoc GUI tests + /// Path to a npm executable. Used for rustdoc GUI tests. pub npm: Option, /// Whether to rerun tests even if the inputs are unchanged. pub force_rerun: bool, - /// Only rerun the tests that result has been modified according to Git status + /// Only rerun the tests that result has been modified according to `git status`. + /// + /// FIXME: this is undocumented. + /// + /// FIXME: how does this interact with [`Self::force_rerun`]? pub only_modified: bool, + // FIXME: these are really not "config"s, but rather are information derived from + // `rustc`-under-test. This poses an interesting conundrum: if we're testing the + // `rustc`-under-test, can we trust its print request outputs and target cfgs? In theory, this + // itself can break or be unreliable -- ideally, we'd be sharing these kind of information not + // through `rustc`-under-test's execution output. In practice, however, print requests are very + // unlikely to completely break (we also have snapshot ui tests for them). Furthermore, even if + // we share them via some kind of static config, that static config can still be wrong! Who + // tests the tester? Therefore, we make a pragmatic compromise here, and use information derived + // from print requests produced by the `rustc`-under-test. + // + // FIXME: move them out from `Config`, because they are *not* configs. pub target_cfgs: OnceLock, pub builtin_cfg_names: OnceLock>, pub supported_crate_types: OnceLock>, + /// FIXME: this is why we still need to depend on *staged* `std`, it's because we currently rely + /// on `#![feature(internal_output_capture)]` for [`std::io::set_output_capture`] to implement + /// `libtest`-esque `--no-capture`. + /// + /// FIXME: rename this to the more canonical `no_capture`, or better, invert this to `capture` + /// to avoid `!nocapture` double-negatives. pub nocapture: bool, - // Needed both to construct build_helper::git::GitConfig + /// Needed both to construct [`build_helper::git::GitConfig`]. pub nightly_branch: String, pub git_merge_commit_email: String, - /// True if the profiler runtime is enabled for this target. - /// Used by the "needs-profiler-runtime" directive in test files. + /// True if the profiler runtime is enabled for this target. Used by the + /// `needs-profiler-runtime` directive in test files. pub profiler_runtime: bool, /// Command for visual diff display, e.g. `diff-tool --color=always`. pub diff_command: Option, - /// Path to minicore aux library, used for `no_core` tests that need `core` stubs in - /// cross-compilation scenarios that do not otherwise want/need to `-Zbuild-std`. Used in e.g. - /// ABI tests. + /// Path to minicore aux library (`tests/auxiliary/minicore.rs`), used for `no_core` tests that + /// need `core` stubs in cross-compilation scenarios that do not otherwise want/need to + /// `-Zbuild-std`. Used in e.g. ABI tests. pub minicore_path: Utf8PathBuf, } impl Config { + /// FIXME: this run scheme is... confusing. pub fn run_enabled(&self) -> bool { self.run.unwrap_or_else(|| { // Auto-detect whether to run based on the platform. diff --git a/src/tools/compiletest/src/debuggers.rs b/src/tools/compiletest/src/debuggers.rs index c133d7fd4fb..0edc3d82d4f 100644 --- a/src/tools/compiletest/src/debuggers.rs +++ b/src/tools/compiletest/src/debuggers.rs @@ -51,6 +51,7 @@ pub(crate) fn configure_gdb(config: &Config) -> Option> { pub(crate) fn configure_lldb(config: &Config) -> Option> { config.lldb_python_dir.as_ref()?; + // FIXME: this is super old if let Some(350) = config.lldb_version { println!( "WARNING: The used version of LLDB (350) has a \ @@ -78,6 +79,7 @@ fn is_pc_windows_msvc_target(target: &str) -> bool { target.ends_with("-pc-windows-msvc") } +/// FIXME: this is very questionable... fn find_cdb(target: &str) -> Option { if !(cfg!(windows) && is_pc_windows_msvc_target(target)) { return None; diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index 0c4ef36828a..df64f12784f 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -207,9 +207,9 @@ impl TestOutcome { /// /// Adapted from `filter_tests` in libtest. /// -/// FIXME(#139660): After the libtest dependency is removed, redesign the whole -/// filtering system to do a better job of understanding and filtering _paths_, -/// instead of being tied to libtest's substring/exact matching behaviour. +/// FIXME(#139660): After the libtest dependency is removed, redesign the whole filtering system to +/// do a better job of understanding and filtering _paths_, instead of being tied to libtest's +/// substring/exact matching behaviour. fn filter_tests(opts: &Config, tests: Vec) -> Vec { let mut filtered = tests; @@ -235,9 +235,9 @@ fn filter_tests(opts: &Config, tests: Vec) -> Vec /// /// Copied from `get_concurrency` in libtest. /// -/// FIXME(#139660): After the libtest dependency is removed, consider making -/// bootstrap specify the number of threads on the command-line, instead of -/// propagating the `RUST_TEST_THREADS` environment variable. +/// FIXME(#139660): After the libtest dependency is removed, consider making bootstrap specify the +/// number of threads on the command-line, instead of propagating the `RUST_TEST_THREADS` +/// environment variable. fn get_concurrency() -> usize { if let Ok(value) = env::var("RUST_TEST_THREADS") { match value.parse::>().ok() { diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index dfce4b8b408..9819079e284 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -242,9 +242,12 @@ pub fn parse_config(args: Vec) -> Config { let target = opt_str2(matches.opt_str("target")); let android_cross_path = opt_path(matches, "android-cross-path"); + // FIXME: `cdb_version` is *derived* from cdb, but it's *not* technically a config! let (cdb, cdb_version) = debuggers::analyze_cdb(matches.opt_str("cdb"), &target); + // FIXME: `gdb_version` is *derived* from gdb, but it's *not* technically a config! let (gdb, gdb_version) = debuggers::analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path); + // FIXME: `lldb_version` is *derived* from lldb, but it's *not* technically a config! let lldb_version = matches.opt_str("lldb-version").as_deref().and_then(debuggers::extract_lldb_version); let color = match matches.opt_str("color").as_deref() { @@ -253,6 +256,9 @@ pub fn parse_config(args: Vec) -> Config { Some("never") => ColorConfig::NeverColor, Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x), }; + // FIXME: this is very questionable, we really should be obtaining LLVM version info from + // `bootstrap`, and not trying to be figuring out that in `compiletest` by running the + // `FileCheck` binary. let llvm_version = matches.opt_str("llvm-version").as_deref().map(directives::extract_llvm_version).or_else( || directives::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?), @@ -370,6 +376,7 @@ pub fn parse_config(args: Vec) -> Config { mode.parse::() .unwrap_or_else(|_| panic!("unknown `--pass` option `{}` given", mode)) }), + // FIXME: this run scheme is... confusing. run: matches.opt_str("run").and_then(|mode| match mode.as_str() { "auto" => None, "always" => Some(true), @@ -545,6 +552,10 @@ pub fn run_tests(config: Arc) { Some(Debugger::Cdb) => configs.extend(debuggers::configure_cdb(&config)), Some(Debugger::Gdb) => configs.extend(debuggers::configure_gdb(&config)), Some(Debugger::Lldb) => configs.extend(debuggers::configure_lldb(&config)), + // FIXME: the *implicit* debugger discovery makes it really difficult to control + // which {`cdb`, `gdb`, `lldb`} are used. These should **not** be implicitly + // discovered by `compiletest`; these should be explicit `bootstrap` configuration + // options that are passed to `compiletest`! None => { configs.extend(debuggers::configure_cdb(&config)); configs.extend(debuggers::configure_gdb(&config)); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index f8bf4ee3022..0b07bb4da9b 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -121,6 +121,8 @@ pub fn run(config: Arc, testpaths: &TestPaths, revision: Option<&str>) { } _ => { + // FIXME: this logic seems strange as well. + // android has its own gdb handling if config.debugger == Some(Debugger::Gdb) && config.gdb.is_none() { panic!("gdb not available but debuginfo gdb debuginfo test requested"); @@ -1055,18 +1057,20 @@ impl<'test> TestCx<'test> { let proc_res = match &*self.config.target { // This is pretty similar to below, we're transforming: // - // program arg1 arg2 + // ```text + // program arg1 arg2 + // ``` // // into // - // remote-test-client run program 2 support-lib.so support-lib2.so arg1 arg2 + // ```text + // remote-test-client run program 2 support-lib.so support-lib2.so arg1 arg2 + // ``` // - // The test-client program will upload `program` to the emulator - // along with all other support libraries listed (in this case - // `support-lib.so` and `support-lib2.so`. It will then execute - // the program on the emulator with the arguments specified - // (in the environment we give the process) and then report back - // the same result. + // The test-client program will upload `program` to the emulator along with all other + // support libraries listed (in this case `support-lib.so` and `support-lib2.so`. It + // will then execute the program on the emulator with the arguments specified (in the + // environment we give the process) and then report back the same result. _ if self.config.remote_test_client.is_some() => { let aux_dir = self.aux_output_dir_name(); let ProcArgs { prog, args } = self.make_run_args(); @@ -1532,6 +1536,8 @@ impl<'test> TestCx<'test> { )); // Optionally prevent default --sysroot if specified in test compile-flags. + // + // FIXME: I feel like this logic is fairly sus. if !self.props.compile_flags.iter().any(|flag| flag.starts_with("--sysroot")) && !self.config.host_rustcflags.iter().any(|flag| flag == "--sysroot") { diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index d9e1e4dfc8d..471e4a4c819 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -322,6 +322,8 @@ impl TestCx<'_> { &["-quiet".as_ref(), "-batch".as_ref(), "-nx".as_ref(), &debugger_script]; let mut gdb = Command::new(self.config.gdb.as_ref().unwrap()); + + // FIXME: we are propagating `PYTHONPATH` from the environment, not a compiletest flag! let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") { format!("{pp}:{rust_pp_module_abs_path}") } else { @@ -443,6 +445,8 @@ impl TestCx<'_> { fn run_lldb(&self, test_executable: &Utf8Path, debugger_script: &Utf8Path) -> ProcRes { // Prepare the lldb_batchmode which executes the debugger script let lldb_script_path = self.config.src_root.join("src/etc/lldb_batchmode.py"); + + // FIXME: `PYTHONPATH` takes precedence over the flag...? let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") { format!("{pp}:{}", self.config.lldb_python_dir.as_ref().unwrap()) } else { -- cgit 1.4.1-3-g733a5 From 971feb618518d5b53dcdc43dcc873b5f7be3f88c Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 5 Jul 2025 10:17:31 -0500 Subject: tidy: use --bless for tidy spellcheck instead of spellcheck:fix previous behavior was inconsistent with existing extra checks. --- src/tools/tidy/src/ext_tool_checks.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src/tools') diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs index 2904908fd43..f76403711b1 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/ext_tool_checks.rs @@ -72,8 +72,7 @@ fn check_impl( let shell_lint = lint_args.contains(&"shell:lint") || shell_all; let cpp_all = lint_args.contains(&"cpp"); let cpp_fmt = lint_args.contains(&"cpp:fmt") || cpp_all; - let spellcheck_all = lint_args.contains(&"spellcheck"); - let spellcheck_fix = lint_args.contains(&"spellcheck:fix"); + let spellcheck = lint_args.contains(&"spellcheck"); let mut py_path = None; @@ -226,7 +225,7 @@ fn check_impl( shellcheck_runner(&merge_args(&cfg_args, &file_args_shc))?; } - if spellcheck_all || spellcheck_fix { + if spellcheck { let config_path = root_path.join("typos.toml"); // sync target files with .github/workflows/spellcheck.yml let mut args = vec![ @@ -238,11 +237,11 @@ fn check_impl( "./src/librustdoc", ]; - if spellcheck_all { - eprintln!("spellcheck files"); - } else if spellcheck_fix { + if bless { eprintln!("spellcheck files and fix"); args.push("--write-changes"); + } else { + eprintln!("spellcheck files"); } spellcheck_runner(&args)?; } -- cgit 1.4.1-3-g733a5 From c1ed2ac8a27bce8ccc655bd87102752d9d8015d6 Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 5 Jul 2025 10:24:17 -0500 Subject: tidy: add specific error message for trying to use `spellcheck:fix`. --- src/tools/tidy/src/ext_tool_checks.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/tools') diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs index f76403711b1..d2da63a9703 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/ext_tool_checks.rs @@ -65,6 +65,13 @@ fn check_impl( None => vec![], }; + if lint_args.contains(&"spellcheck:fix") { + return Err(Error::Generic( + "`spellcheck:fix` is no longer valid, use `--extra=check=spellcheck --bless`" + .to_string(), + )); + } + let python_all = lint_args.contains(&"py"); let python_lint = lint_args.contains(&"py:lint") || python_all; let python_fmt = lint_args.contains(&"py:fmt") || python_all; -- cgit 1.4.1-3-g733a5 From 9c9c5b041b807ddef7d34d128b15ed10c55e751b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Jul 2025 22:21:23 +0200 Subject: compiletest: print slightly more information on fs::write failure --- src/tools/compiletest/src/runtest.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/tools') diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index f8bf4ee3022..a03dd23b56b 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1918,7 +1918,8 @@ impl<'test> TestCx<'test> { fn dump_output_file(&self, out: &str, extension: &str) { let outfile = self.make_out_name(extension); - fs::write(outfile.as_std_path(), out).unwrap(); + fs::write(outfile.as_std_path(), out) + .unwrap_or_else(|err| panic!("failed to write {outfile}: {err:?}")); } /// Creates a filename for output with the given extension. -- cgit 1.4.1-3-g733a5 From 31ea5f90c77abfe0b687fa74b2b20ee0738f3103 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 6 Jul 2025 00:26:38 +0000 Subject: cargo update compiler & tools dependencies: Locking 6 packages to latest compatible versions Adding io-uring v0.7.8 Updating jsonpath-rust v1.0.2 -> v1.0.3 Updating libffi v4.1.0 -> v4.1.1 Updating libffi-sys v3.3.1 -> v3.3.2 Updating tokio v1.45.1 -> v1.46.1 Updating wasm-component-ld v0.5.14 -> v0.5.15 note: pass `--verbose` to see 41 unchanged dependencies behind latest library dependencies: Locking 0 packages to latest compatible versions note: pass `--verbose` to see 4 unchanged dependencies behind latest rustbook dependencies: Locking 1 package to latest compatible version Updating cc v1.2.27 -> v1.2.29 --- Cargo.lock | 35 +++++++++++++++++++++++++---------- src/tools/rustbook/Cargo.lock | 4 ++-- 2 files changed, 27 insertions(+), 12 deletions(-) (limited to 'src/tools') diff --git a/Cargo.lock b/Cargo.lock index 34fc0860a4b..24e1cc7712f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1947,6 +1947,17 @@ dependencies = [ "unic-langid", ] +[[package]] +name = "io-uring" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + [[package]] name = "ipc-channel" version = "0.19.0" @@ -2058,9 +2069,9 @@ dependencies = [ [[package]] name = "jsonpath-rust" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b37465feaf9d41f74df7da98c6c1c31ca8ea06d11b5bf7869c8f1ccc51a793f" +checksum = "7d057f8fd19e20c3f14d3663983397155739b6bc1148dc5cd4c4a1a5b3130eb0" dependencies = [ "pest", "pest_derive", @@ -2117,9 +2128,9 @@ dependencies = [ [[package]] name = "libffi" -version = "4.1.0" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebfd30a67b482a08116e753d0656cb626548cf4242543e5cc005be7639d99838" +checksum = "e7681c6fab541f799a829e44a445a0666cf8d8a6cfebf89419e6aed52c604e87" dependencies = [ "libc", "libffi-sys", @@ -2127,9 +2138,9 @@ dependencies = [ [[package]] name = "libffi-sys" -version = "3.3.1" +version = "3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f003aa318c9f0ee69eb0ada7c78f5c9d2fedd2ceb274173b5c7ff475eee584a3" +checksum = "7b0d828d367b4450ed08e7d510dc46636cd660055f50d67ac943bfe788767c29" dependencies = [ "cc", ] @@ -5462,13 +5473,17 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.45.1" +version = "1.46.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" dependencies = [ "backtrace", "bytes", + "io-uring", + "libc", + "mio", "pin-project-lite", + "slab", ] [[package]] @@ -5994,9 +6009,9 @@ dependencies = [ [[package]] name = "wasm-component-ld" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b015ec93764aa5517bc8b839efa9941b90be8ce680b1134f8224644ba1e48e3f" +checksum = "6d95124e34fee1316222e03b9bbf41af186ecbae2c8b79f8debe6e21b3ff60c5" dependencies = [ "anyhow", "clap", diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index aeae5b61b95..050ddf47bae 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -156,9 +156,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" -version = "1.2.27" +version = "1.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" dependencies = [ "shlex", ] -- cgit 1.4.1-3-g733a5 From 3fa0ec91d8f3f14f9514d45d93e6fb7fdf1ad89e Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 4 Jul 2025 12:42:33 +0200 Subject: Rewrite empty attribute lint Signed-off-by: Jonathan Brouwer --- .../rustc_attr_data_structures/src/attributes.rs | 4 +- .../src/encode_cross_crate.rs | 2 +- compiler/rustc_attr_data_structures/src/lints.rs | 1 + compiler/rustc_attr_parsing/messages.ftl | 4 + .../src/attributes/codegen_attrs.rs | 4 + compiler/rustc_attr_parsing/src/attributes/repr.rs | 7 +- compiler/rustc_attr_parsing/src/context.rs | 10 ++ compiler/rustc_attr_parsing/src/lints.rs | 6 + .../rustc_attr_parsing/src/session_diagnostics.rs | 7 + .../src/deriving/generic/mod.rs | 2 +- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 2 +- compiler/rustc_hir_analysis/src/check/check.rs | 7 +- compiler/rustc_lint/src/nonstandard_style.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 7 +- compiler/rustc_passes/src/check_attr.rs | 96 +++++-------- src/librustdoc/clean/types.rs | 2 +- .../src/arbitrary_source_item_ordering.rs | 2 +- .../clippy_lints/src/attrs/repr_attributes.rs | 2 +- .../src/default_union_representation.rs | 2 +- src/tools/clippy/clippy_utils/src/lib.rs | 2 +- tests/pretty/hir-lifetimes.pp | 2 +- tests/pretty/hir-pretty-attr.pp | 2 +- tests/ui/attributes/malformed-attrs.rs | 1 + tests/ui/attributes/malformed-attrs.stderr | 148 +++++++++++---------- tests/ui/empty/empty-attributes.stderr | 36 +++-- tests/ui/repr/repr-empty-packed.stderr | 23 ++-- tests/ui/unpretty/exhaustive.hir.stdout | 3 +- 27 files changed, 195 insertions(+), 191 deletions(-) (limited to 'src/tools') diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 6af15da7d08..ba62be676d4 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -67,8 +67,6 @@ pub enum ReprAttr { ReprSimd, ReprTransparent, ReprAlign(Align), - // this one is just so we can emit a lint for it - ReprEmpty, } pub use ReprAttr::*; @@ -304,7 +302,7 @@ pub enum AttributeKind { PubTransparent(Span), /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). - Repr(ThinVec<(ReprAttr, Span)>), + Repr { reprs: ThinVec<(ReprAttr, Span)>, first_span: Span }, /// Represents `#[rustc_layout_scalar_valid_range_end]`. RustcLayoutScalarValidRangeEnd(Box, Span), diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs index 8ebd38a6ba7..b109ebbf47b 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -41,7 +41,7 @@ impl AttributeKind { Optimize(..) => No, PassByValue(..) => Yes, PubTransparent(..) => Yes, - Repr(..) => No, + Repr { .. } => No, RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, RustcObjectLifetimeDefault => No, diff --git a/compiler/rustc_attr_data_structures/src/lints.rs b/compiler/rustc_attr_data_structures/src/lints.rs index e34c54c6d32..60ca4d43ce9 100644 --- a/compiler/rustc_attr_data_structures/src/lints.rs +++ b/compiler/rustc_attr_data_structures/src/lints.rs @@ -12,4 +12,5 @@ pub struct AttributeLint { pub enum AttributeLintKind { UnusedDuplicate { this: Span, other: Span, warning: bool }, IllFormedAttributeInput { suggestions: Vec }, + EmptyAttribute { first_span: Span }, } diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 9ad46a83f50..8a709ea5d20 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -6,6 +6,10 @@ attr_parsing_deprecated_item_suggestion = .help = add `#![feature(deprecated_suggestion)]` to the crate root .note = see #94785 for more details +attr_parsing_empty_attribute = + unused attribute + .suggestion = remove this attribute + attr_parsing_empty_confusables = expected at least one confusable name attr_parsing_expected_one_cfg_pattern = diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 13f560dff38..cb3956d46a0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -298,6 +298,10 @@ impl CombineAttributeParser for TargetFeatureParser { cx.expected_list(cx.attr_span); return features; }; + if list.is_empty() { + cx.warn_empty_attribute(cx.attr_span); + return features; + } for item in list.mixed() { let Some(name_value) = item.meta_item() else { cx.expected_name_value(item.span(), Some(sym::enable)); diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 1c070dc2685..6a45832ed7f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -23,7 +23,8 @@ pub(crate) struct ReprParser; impl CombineAttributeParser for ReprParser { type Item = (ReprAttr, Span); const PATH: &[Symbol] = &[sym::repr]; - const CONVERT: ConvertFn = |items, _| AttributeKind::Repr(items); + const CONVERT: ConvertFn = + |items, first_span| AttributeKind::Repr { reprs: items, first_span }; // FIXME(jdonszelmann): never used const TEMPLATE: AttributeTemplate = template!(List: "C | Rust | align(...) | packed(...) | | transparent"); @@ -40,8 +41,8 @@ impl CombineAttributeParser for ReprParser { }; if list.is_empty() { - // this is so validation can emit a lint - reprs.push((ReprAttr::ReprEmpty, cx.attr_span)); + cx.warn_empty_attribute(cx.attr_span); + return reprs; } for param in list.mixed() { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 2a01ee58493..bcd7b024a9e 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -165,6 +165,7 @@ mod private { #[allow(private_interfaces)] pub trait Stage: Sized + 'static + Sealed { type Id: Copy; + const SHOULD_EMIT_LINTS: bool; fn parsers() -> &'static group_type!(Self); @@ -175,6 +176,7 @@ pub trait Stage: Sized + 'static + Sealed { #[allow(private_interfaces)] impl Stage for Early { type Id = NodeId; + const SHOULD_EMIT_LINTS: bool = false; fn parsers() -> &'static group_type!(Self) { &early::ATTRIBUTE_PARSERS @@ -188,6 +190,7 @@ impl Stage for Early { #[allow(private_interfaces)] impl Stage for Late { type Id = HirId; + const SHOULD_EMIT_LINTS: bool = true; fn parsers() -> &'static group_type!(Self) { &late::ATTRIBUTE_PARSERS @@ -228,6 +231,9 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { /// must be delayed until after HIR is built. This method will take care of the details of /// that. pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) { + if !S::SHOULD_EMIT_LINTS { + return; + } let id = self.target_id; (self.emit_lint)(AttributeLint { id, span, kind: lint }); } @@ -409,6 +415,10 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }, }) } + + pub(crate) fn warn_empty_attribute(&mut self, span: Span) { + self.emit_lint(AttributeLintKind::EmptyAttribute { first_span: span }, span); + } } impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> { diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index fee22293b47..e648ca4fdf8 100644 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -28,5 +28,11 @@ pub fn emit_attribute_lint(lint: &AttributeLint, lint_emi }, ); } + AttributeLintKind::EmptyAttribute { first_span } => lint_emitter.emit_node_span_lint( + rustc_session::lint::builtin::UNUSED_ATTRIBUTES, + *id, + *first_span, + session_diagnostics::EmptyAttributeList { attr_span: *first_span }, + ), } } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 6145f1e1d3e..28f6786f37f 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -473,6 +473,13 @@ pub(crate) struct EmptyConfusables { pub span: Span, } +#[derive(LintDiagnostic)] +#[diag(attr_parsing_empty_attribute)] +pub(crate) struct EmptyAttributeList { + #[suggestion(code = "", applicability = "machine-applicable")] + pub attr_span: Span, +} + #[derive(Diagnostic)] #[diag(attr_parsing_invalid_alignment_value, code = E0589)] pub(crate) struct InvalidAlignmentValue { diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index d201ca196d6..8135f3744f8 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -485,7 +485,7 @@ impl<'a> TraitDef<'a> { Annotatable::Item(item) => { let is_packed = matches!( AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id), - Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(x, _)| matches!(x, ReprPacked(..))) + Some(Attribute::Parsed(AttributeKind::Repr { reprs, .. })) if reprs.iter().any(|(x, _)| matches!(x, ReprPacked(..))) ); let newitem = match &item.kind { diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 2713ec07f97..be63bb8ac59 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -109,7 +109,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if let hir::Attribute::Parsed(p) = attr { match p { - AttributeKind::Repr(reprs) => { + AttributeKind::Repr { reprs, first_span: _ } => { codegen_fn_attrs.alignment = reprs .iter() .filter_map( diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index f4fcb13b1a1..bd89d010a3c 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1395,8 +1395,7 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { let repr = def.repr(); if repr.packed() { - if let Some(reprs) = - attrs::find_attr!(tcx.get_all_attrs(def.did()), attrs::AttributeKind::Repr(r) => r) + if let Some(reprs) = attrs::find_attr!(tcx.get_all_attrs(def.did()), attrs::AttributeKind::Repr { reprs, .. } => reprs) { for (r, _) in reprs { if let ReprPacked(pack) = r @@ -1619,10 +1618,10 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { if def.variants().is_empty() { attrs::find_attr!( tcx.get_all_attrs(def_id), - attrs::AttributeKind::Repr(rs) => { + attrs::AttributeKind::Repr { reprs, first_span } => { struct_span_code_err!( tcx.dcx(), - rs.first().unwrap().1, + reprs.first().map(|repr| repr.1).unwrap_or(*first_span), E0084, "unsupported representation for zero-variant enum" ) diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 97e627f2eb2..ad7686b3e5b 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -168,7 +168,7 @@ impl EarlyLintPass for NonCamelCaseTypes { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { let has_repr_c = matches!( AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id), - Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(r, _)| r == &ReprAttr::ReprC) + Some(Attribute::Parsed(AttributeKind::Repr { reprs, ..})) if reprs.iter().any(|(r, _)| r == &ReprAttr::ReprC) ); if has_repr_c { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f1b16ea54e6..b780b1c5776 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1525,7 +1525,8 @@ impl<'tcx> TyCtxt<'tcx> { field_shuffle_seed ^= user_seed; } - if let Some(reprs) = attr::find_attr!(self.get_all_attrs(did), AttributeKind::Repr(r) => r) + if let Some(reprs) = + attr::find_attr!(self.get_all_attrs(did), AttributeKind::Repr { reprs, .. } => reprs) { for (r, _) in reprs { flags.insert(match *r { @@ -1566,10 +1567,6 @@ impl<'tcx> TyCtxt<'tcx> { max_align = max_align.max(Some(align)); ReprFlags::empty() } - attr::ReprEmpty => { - /* skip these, they're just for diagnostics */ - ReprFlags::empty() - } }); } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 18b3ab12e2d..3fa5cdc36bc 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -160,7 +160,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } Attribute::Parsed(AttributeKind::DocComment { .. }) => { /* `#[doc]` is actually a lot more than just doc comments, so is checked below*/ } - Attribute::Parsed(AttributeKind::Repr(_)) => { /* handled below this loop and elsewhere */ + Attribute::Parsed(AttributeKind::Repr { .. }) => { /* handled below this loop and elsewhere */ } Attribute::Parsed(AttributeKind::RustcObjectLifetimeDefault) => { self.check_object_lifetime_default(hir_id); @@ -1948,7 +1948,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // #[repr(foo)] // #[repr(bar, align(8))] // ``` - let reprs = find_attr!(attrs, AttributeKind::Repr(r) => r.as_slice()).unwrap_or(&[]); + let (reprs, first_attr_span) = find_attr!(attrs, AttributeKind::Repr { reprs, first_span } => (reprs.as_slice(), Some(*first_span))).unwrap_or((&[], None)); let mut int_reprs = 0; let mut is_explicit_rust = false; @@ -2045,31 +2045,30 @@ impl<'tcx> CheckAttrVisitor<'tcx> { continue; } } - // FIXME(jdonszelmann): move the diagnostic for unused repr attrs here, I think - // it's a better place for it. - ReprAttr::ReprEmpty => { - // catch `repr()` with no arguments, applied to an item (i.e. not `#![repr()]`) - if item.is_some() { - match target { - Target::Struct | Target::Union | Target::Enum => continue, - Target::Fn | Target::Method(_) => { - self.dcx().emit_err(errors::ReprAlignShouldBeAlign { - span: *repr_span, - item: target.name(), - }); - } - _ => { - self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { - hint_span: *repr_span, - span, - }); - } - } - } + }; + } - return; + // catch `repr()` with no arguments, applied to an item (i.e. not `#![repr()]`) + if let Some(first_attr_span) = first_attr_span + && reprs.is_empty() + && item.is_some() + { + match target { + Target::Struct | Target::Union | Target::Enum => {} + Target::Fn | Target::Method(_) => { + self.dcx().emit_err(errors::ReprAlignShouldBeAlign { + span: first_attr_span, + item: target.name(), + }); } - }; + _ => { + self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { + hint_span: first_attr_span, + span, + }); + } + } + return; } // Just point at all repr hints if there are any incompatibilities. @@ -2324,43 +2323,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute, style: Option) { - // FIXME(jdonszelmann): deduplicate these checks after more attrs are parsed. This is very - // ugly now but can 100% be removed later. - if let Attribute::Parsed(p) = attr { - match p { - AttributeKind::Repr(reprs) => { - for (r, span) in reprs { - if let ReprAttr::ReprEmpty = r { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - *span, - errors::Unused { - attr_span: *span, - note: errors::UnusedNote::EmptyList { name: sym::repr }, - }, - ); - } - } - return; - } - AttributeKind::TargetFeature(features, span) if features.len() == 0 => { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - *span, - errors::Unused { - attr_span: *span, - note: errors::UnusedNote::EmptyList { name: sym::target_feature }, - }, - ); - return; - } - _ => {} - }; - } - // Warn on useless empty attributes. + // FIXME(jdonszelmann): this lint should be moved to attribute parsing, see `AcceptContext::warn_empty_attribute` let note = if attr.has_any_name(&[ sym::macro_use, sym::allow, @@ -2576,7 +2540,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } fn check_rustc_pub_transparent(&self, attr_span: Span, span: Span, attrs: &[Attribute]) { - if !find_attr!(attrs, AttributeKind::Repr(r) => r.iter().any(|(r, _)| r == &ReprAttr::ReprTransparent)) + if !find_attr!(attrs, AttributeKind::Repr { reprs, .. } => reprs.iter().any(|(r, _)| r == &ReprAttr::ReprTransparent)) .unwrap_or(false) { self.dcx().emit_err(errors::RustcPubTransparent { span, attr_span }); @@ -2852,8 +2816,12 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { ATTRS_TO_CHECK.iter().find(|attr_to_check| attr.has_name(**attr_to_check)) { (attr.span(), *a) - } else if let Attribute::Parsed(AttributeKind::Repr(r)) = attr { - (r.first().unwrap().1, sym::repr) + } else if let Attribute::Parsed(AttributeKind::Repr { + reprs: _, + first_span: first_attr_span, + }) = attr + { + (*first_attr_span, sym::repr) } else { continue; }; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index de920469fdc..a05aab22f1e 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -784,7 +784,7 @@ impl Item { // don't want it it `Item::attrs`. hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => None, // We have separate pretty-printing logic for `#[repr(..)]` attributes. - hir::Attribute::Parsed(AttributeKind::Repr(..)) => None, + hir::Attribute::Parsed(AttributeKind::Repr { .. }) => None, // target_feature is special-cased because cargo-semver-checks uses it hir::Attribute::Parsed(AttributeKind::TargetFeature(features, _)) => { let mut output = String::new(); diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs index b9ae9afe851..8b6bfaebbe5 100644 --- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -266,7 +266,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { .tcx .hir_attrs(item.hir_id()) .iter() - .any(|attr| matches!(attr, Attribute::Parsed(AttributeKind::Repr(..)))) + .any(|attr| matches!(attr, Attribute::Parsed(AttributeKind::Repr{ .. }))) { // Do not lint items with a `#[repr]` attribute as their layout may be imposed by an external API. return; diff --git a/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs index 05d8a8c26d1..3e8808cec61 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs @@ -9,7 +9,7 @@ use clippy_utils::msrvs::{self, Msrv}; use super::REPR_PACKED_WITHOUT_ABI; pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute], msrv: Msrv) { - if let Some(reprs) = find_attr!(attrs, AttributeKind::Repr(r) => r) { + if let Some(reprs) = find_attr!(attrs, AttributeKind::Repr { reprs, .. } => reprs) { let packed_span = reprs .iter() .find(|(r, _)| matches!(r, ReprAttr::ReprPacked(..))) diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs index 615421f3a40..9bf2144e445 100644 --- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs +++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs @@ -99,5 +99,5 @@ fn is_zst<'tcx>(cx: &LateContext<'tcx>, field: &FieldDef, args: ty::GenericArgsR fn has_c_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool { let attrs = cx.tcx.hir_attrs(hir_id); - find_attr!(attrs, AttributeKind::Repr(r) if r.iter().any(|(x, _)| *x == ReprAttr::ReprC)) + find_attr!(attrs, AttributeKind::Repr { reprs, .. } if reprs.iter().any(|(x, _)| *x == ReprAttr::ReprC)) } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index a8b33418c8c..c01f0ffaac9 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1761,7 +1761,7 @@ pub fn has_attr(attrs: &[hir::Attribute], symbol: Symbol) -> bool { } pub fn has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool { - find_attr!(cx.tcx.hir_attrs(hir_id), AttributeKind::Repr(..)) + find_attr!(cx.tcx.hir_attrs(hir_id), AttributeKind::Repr { .. }) } pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool { diff --git a/tests/pretty/hir-lifetimes.pp b/tests/pretty/hir-lifetimes.pp index 4d1ab9d383b..58de6d81915 100644 --- a/tests/pretty/hir-lifetimes.pp +++ b/tests/pretty/hir-lifetimes.pp @@ -69,7 +69,7 @@ type Q<'a> = dyn MyTrait<'a, 'a> + 'a; fn h<'b, F>(f: F, y: Foo<'b>) where F: for<'d> MyTrait<'d, 'b> { } // FIXME(?): attr printing is weird -#[attr = Repr([ReprC])] +#[attr = Repr {reprs: [ReprC]}] struct S<'a>(&'a u32); extern "C" { diff --git a/tests/pretty/hir-pretty-attr.pp b/tests/pretty/hir-pretty-attr.pp index d8cc8c424ca..db7489c1264 100644 --- a/tests/pretty/hir-pretty-attr.pp +++ b/tests/pretty/hir-pretty-attr.pp @@ -6,6 +6,6 @@ extern crate std; //@ pretty-mode:hir //@ pp-exact:hir-pretty-attr.pp -#[attr = Repr([ReprC, ReprPacked(Align(4 bytes)), ReprTransparent])] +#[attr = Repr {reprs: [ReprC, ReprPacked(Align(4 bytes)), ReprTransparent]}] struct Example { } diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs index a09fe86557d..aa52de63a60 100644 --- a/tests/ui/attributes/malformed-attrs.rs +++ b/tests/ui/attributes/malformed-attrs.rs @@ -47,6 +47,7 @@ //~^ ERROR malformed #[repr] //~^ ERROR malformed +//~| ERROR is not supported on function items #[rustc_as_ptr = 5] //~^ ERROR malformed #[inline = 5] diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 9fe4f45b3ef..2f7bf50ead5 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -1,11 +1,11 @@ error: `cfg` is not followed by parentheses - --> $DIR/malformed-attrs.rs:101:1 + --> $DIR/malformed-attrs.rs:102:1 | LL | #[cfg] | ^^^^^^ help: expected syntax is: `cfg(/* predicate */)` error: malformed `cfg_attr` attribute input - --> $DIR/malformed-attrs.rs:103:1 + --> $DIR/malformed-attrs.rs:104:1 | LL | #[cfg_attr] | ^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | #[cfg_attr(condition, attribute, other_attribute, ...)] | ++++++++++++++++++++++++++++++++++++++++++++ error[E0463]: can't find crate for `wloop` - --> $DIR/malformed-attrs.rs:210:1 + --> $DIR/malformed-attrs.rs:211:1 | LL | extern crate wloop; | ^^^^^^^^^^^^^^^^^^^ can't find crate @@ -35,19 +35,19 @@ LL | #![windows_subsystem] | ^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![windows_subsystem = "windows|console"]` error: malformed `crate_name` attribute input - --> $DIR/malformed-attrs.rs:73:1 + --> $DIR/malformed-attrs.rs:74:1 | LL | #[crate_name] | ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]` error: malformed `export_stable` attribute input - --> $DIR/malformed-attrs.rs:80:1 + --> $DIR/malformed-attrs.rs:81:1 | LL | #[export_stable = 1] | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[export_stable]` error: malformed `coverage` attribute input - --> $DIR/malformed-attrs.rs:89:1 + --> $DIR/malformed-attrs.rs:90:1 | LL | #[coverage] | ^^^^^^^^^^^ @@ -60,49 +60,49 @@ LL | #[coverage(on)] | ++++ error: malformed `no_sanitize` attribute input - --> $DIR/malformed-attrs.rs:91:1 + --> $DIR/malformed-attrs.rs:92:1 | LL | #[no_sanitize] | ^^^^^^^^^^^^^^ help: must be of the form: `#[no_sanitize(address, kcfi, memory, thread)]` error: malformed `proc_macro` attribute input - --> $DIR/malformed-attrs.rs:98:1 + --> $DIR/malformed-attrs.rs:99:1 | LL | #[proc_macro = 18] | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]` error: malformed `instruction_set` attribute input - --> $DIR/malformed-attrs.rs:105:1 + --> $DIR/malformed-attrs.rs:106:1 | LL | #[instruction_set] | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[instruction_set(set)]` error: malformed `patchable_function_entry` attribute input - --> $DIR/malformed-attrs.rs:107:1 + --> $DIR/malformed-attrs.rs:108:1 | LL | #[patchable_function_entry] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` error: malformed `coroutine` attribute input - --> $DIR/malformed-attrs.rs:110:5 + --> $DIR/malformed-attrs.rs:111:5 | LL | #[coroutine = 63] || {} | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[coroutine]` error: malformed `proc_macro_attribute` attribute input - --> $DIR/malformed-attrs.rs:115:1 + --> $DIR/malformed-attrs.rs:116:1 | LL | #[proc_macro_attribute = 19] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]` error: malformed `proc_macro_derive` attribute input - --> $DIR/malformed-attrs.rs:122:1 + --> $DIR/malformed-attrs.rs:123:1 | LL | #[proc_macro_derive] | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` error: malformed `must_not_suspend` attribute input - --> $DIR/malformed-attrs.rs:131:1 + --> $DIR/malformed-attrs.rs:132:1 | LL | #[must_not_suspend()] | ^^^^^^^^^^^^^^^^^^^^^ @@ -117,109 +117,109 @@ LL + #[must_not_suspend] | error: malformed `cfi_encoding` attribute input - --> $DIR/malformed-attrs.rs:133:1 + --> $DIR/malformed-attrs.rs:134:1 | LL | #[cfi_encoding] | ^^^^^^^^^^^^^^^ help: must be of the form: `#[cfi_encoding = "encoding"]` error: malformed `type_const` attribute input - --> $DIR/malformed-attrs.rs:142:5 + --> $DIR/malformed-attrs.rs:143:5 | LL | #[type_const = 1] | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[type_const]` error: malformed `marker` attribute input - --> $DIR/malformed-attrs.rs:154:1 + --> $DIR/malformed-attrs.rs:155:1 | LL | #[marker = 3] | ^^^^^^^^^^^^^ help: must be of the form: `#[marker]` error: malformed `fundamental` attribute input - --> $DIR/malformed-attrs.rs:156:1 + --> $DIR/malformed-attrs.rs:157:1 | LL | #[fundamental()] | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[fundamental]` error: malformed `ffi_pure` attribute input - --> $DIR/malformed-attrs.rs:164:5 + --> $DIR/malformed-attrs.rs:165:5 | LL | #[unsafe(ffi_pure = 1)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[ffi_pure]` error: malformed `link_ordinal` attribute input - --> $DIR/malformed-attrs.rs:166:5 + --> $DIR/malformed-attrs.rs:167:5 | LL | #[link_ordinal] | ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_ordinal(ordinal)]` error: malformed `ffi_const` attribute input - --> $DIR/malformed-attrs.rs:170:5 + --> $DIR/malformed-attrs.rs:171:5 | LL | #[unsafe(ffi_const = 1)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[ffi_const]` error: malformed `linkage` attribute input - --> $DIR/malformed-attrs.rs:172:5 + --> $DIR/malformed-attrs.rs:173:5 | LL | #[linkage] | ^^^^^^^^^^ help: must be of the form: `#[linkage = "external|internal|..."]` error: malformed `allow` attribute input - --> $DIR/malformed-attrs.rs:177:1 + --> $DIR/malformed-attrs.rs:178:1 | LL | #[allow] | ^^^^^^^^ help: must be of the form: `#[allow(lint1, lint2, ..., /*opt*/ reason = "...")]` error: malformed `expect` attribute input - --> $DIR/malformed-attrs.rs:179:1 + --> $DIR/malformed-attrs.rs:180:1 | LL | #[expect] | ^^^^^^^^^ help: must be of the form: `#[expect(lint1, lint2, ..., /*opt*/ reason = "...")]` error: malformed `warn` attribute input - --> $DIR/malformed-attrs.rs:181:1 + --> $DIR/malformed-attrs.rs:182:1 | LL | #[warn] | ^^^^^^^ help: must be of the form: `#[warn(lint1, lint2, ..., /*opt*/ reason = "...")]` error: malformed `deny` attribute input - --> $DIR/malformed-attrs.rs:183:1 + --> $DIR/malformed-attrs.rs:184:1 | LL | #[deny] | ^^^^^^^ help: must be of the form: `#[deny(lint1, lint2, ..., /*opt*/ reason = "...")]` error: malformed `forbid` attribute input - --> $DIR/malformed-attrs.rs:185:1 + --> $DIR/malformed-attrs.rs:186:1 | LL | #[forbid] | ^^^^^^^^^ help: must be of the form: `#[forbid(lint1, lint2, ..., /*opt*/ reason = "...")]` error: malformed `debugger_visualizer` attribute input - --> $DIR/malformed-attrs.rs:187:1 + --> $DIR/malformed-attrs.rs:188:1 | LL | #[debugger_visualizer] | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]` error: malformed `automatically_derived` attribute input - --> $DIR/malformed-attrs.rs:190:1 + --> $DIR/malformed-attrs.rs:191:1 | LL | #[automatically_derived = 18] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[automatically_derived]` error: malformed `thread_local` attribute input - --> $DIR/malformed-attrs.rs:202:1 + --> $DIR/malformed-attrs.rs:203:1 | LL | #[thread_local()] | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[thread_local]` error: malformed `no_link` attribute input - --> $DIR/malformed-attrs.rs:206:1 + --> $DIR/malformed-attrs.rs:207:1 | LL | #[no_link()] | ^^^^^^^^^^^^ help: must be of the form: `#[no_link]` error: malformed `macro_use` attribute input - --> $DIR/malformed-attrs.rs:208:1 + --> $DIR/malformed-attrs.rs:209:1 | LL | #[macro_use = 1] | ^^^^^^^^^^^^^^^^ @@ -234,7 +234,7 @@ LL + #[macro_use] | error: malformed `macro_export` attribute input - --> $DIR/malformed-attrs.rs:213:1 + --> $DIR/malformed-attrs.rs:214:1 | LL | #[macro_export = 18] | ^^^^^^^^^^^^^^^^^^^^ @@ -249,31 +249,31 @@ LL + #[macro_export] | error: malformed `allow_internal_unsafe` attribute input - --> $DIR/malformed-attrs.rs:215:1 + --> $DIR/malformed-attrs.rs:216:1 | LL | #[allow_internal_unsafe = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[allow_internal_unsafe]` error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/malformed-attrs.rs:98:1 + --> $DIR/malformed-attrs.rs:99:1 | LL | #[proc_macro = 18] | ^^^^^^^^^^^^^^^^^^ error: the `#[proc_macro_attribute]` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/malformed-attrs.rs:115:1 + --> $DIR/malformed-attrs.rs:116:1 | LL | #[proc_macro_attribute = 19] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/malformed-attrs.rs:122:1 + --> $DIR/malformed-attrs.rs:123:1 | LL | #[proc_macro_derive] | ^^^^^^^^^^^^^^^^^^^^ error[E0658]: allow_internal_unsafe side-steps the unsafe_code lint - --> $DIR/malformed-attrs.rs:215:1 + --> $DIR/malformed-attrs.rs:216:1 | LL | #[allow_internal_unsafe = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -292,7 +292,7 @@ LL | #[doc] = note: `#[deny(ill_formed_attribute_input)]` on by default error: valid forms for the attribute are `#[doc(hidden|inline|...)]` and `#[doc = "string"]` - --> $DIR/malformed-attrs.rs:75:1 + --> $DIR/malformed-attrs.rs:76:1 | LL | #[doc] | ^^^^^^ @@ -301,7 +301,7 @@ LL | #[doc] = note: for more information, see issue #57571 error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]` - --> $DIR/malformed-attrs.rs:82:1 + --> $DIR/malformed-attrs.rs:83:1 | LL | #[link] | ^^^^^^^ @@ -310,7 +310,7 @@ LL | #[link] = note: for more information, see issue #57571 error: invalid argument - --> $DIR/malformed-attrs.rs:187:1 + --> $DIR/malformed-attrs.rs:188:1 | LL | #[debugger_visualizer] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -382,7 +382,7 @@ LL | #[repr] | help: must be of the form: `#[repr(C | Rust | align(...) | packed(...) | | transparent)]` error[E0565]: malformed `rustc_as_ptr` attribute input - --> $DIR/malformed-attrs.rs:50:1 + --> $DIR/malformed-attrs.rs:51:1 | LL | #[rustc_as_ptr = 5] | ^^^^^^^^^^^^^^^---^ @@ -391,7 +391,7 @@ LL | #[rustc_as_ptr = 5] | help: must be of the form: `#[rustc_as_ptr]` error[E0539]: malformed `align` attribute input - --> $DIR/malformed-attrs.rs:55:1 + --> $DIR/malformed-attrs.rs:56:1 | LL | #[align] | ^^^^^^^^ @@ -400,7 +400,7 @@ LL | #[align] | help: must be of the form: `#[align()]` error[E0539]: malformed `optimize` attribute input - --> $DIR/malformed-attrs.rs:57:1 + --> $DIR/malformed-attrs.rs:58:1 | LL | #[optimize] | ^^^^^^^^^^^ @@ -409,7 +409,7 @@ LL | #[optimize] | help: must be of the form: `#[optimize(size|speed|none)]` error[E0565]: malformed `cold` attribute input - --> $DIR/malformed-attrs.rs:59:1 + --> $DIR/malformed-attrs.rs:60:1 | LL | #[cold = 1] | ^^^^^^^---^ @@ -418,13 +418,13 @@ LL | #[cold = 1] | help: must be of the form: `#[cold]` error: valid forms for the attribute are `#[must_use = "reason"]` and `#[must_use]` - --> $DIR/malformed-attrs.rs:61:1 + --> $DIR/malformed-attrs.rs:62:1 | LL | #[must_use()] | ^^^^^^^^^^^^^ error[E0565]: malformed `no_mangle` attribute input - --> $DIR/malformed-attrs.rs:63:1 + --> $DIR/malformed-attrs.rs:64:1 | LL | #[no_mangle = 1] | ^^^^^^^^^^^^---^ @@ -433,7 +433,7 @@ LL | #[no_mangle = 1] | help: must be of the form: `#[no_mangle]` error[E0565]: malformed `naked` attribute input - --> $DIR/malformed-attrs.rs:65:1 + --> $DIR/malformed-attrs.rs:66:1 | LL | #[unsafe(naked())] | ^^^^^^^^^^^^^^--^^ @@ -442,7 +442,7 @@ LL | #[unsafe(naked())] | help: must be of the form: `#[naked]` error[E0565]: malformed `track_caller` attribute input - --> $DIR/malformed-attrs.rs:67:1 + --> $DIR/malformed-attrs.rs:68:1 | LL | #[track_caller()] | ^^^^^^^^^^^^^^--^ @@ -451,13 +451,13 @@ LL | #[track_caller()] | help: must be of the form: `#[track_caller]` error[E0539]: malformed `export_name` attribute input - --> $DIR/malformed-attrs.rs:69:1 + --> $DIR/malformed-attrs.rs:70:1 | LL | #[export_name()] | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[export_name = "name"]` error[E0805]: malformed `used` attribute input - --> $DIR/malformed-attrs.rs:71:1 + --> $DIR/malformed-attrs.rs:72:1 | LL | #[used()] | ^^^^^^--^ @@ -473,7 +473,7 @@ LL + #[used] | error[E0539]: malformed `target_feature` attribute input - --> $DIR/malformed-attrs.rs:78:1 + --> $DIR/malformed-attrs.rs:79:1 | LL | #[target_feature] | ^^^^^^^^^^^^^^^^^ @@ -482,19 +482,19 @@ LL | #[target_feature] | help: must be of the form: `#[target_feature(enable = "feat1, feat2")]` error[E0539]: malformed `link_name` attribute input - --> $DIR/malformed-attrs.rs:85:1 + --> $DIR/malformed-attrs.rs:86:1 | LL | #[link_name] | ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]` error[E0539]: malformed `link_section` attribute input - --> $DIR/malformed-attrs.rs:87:1 + --> $DIR/malformed-attrs.rs:88:1 | LL | #[link_section] | ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]` error[E0565]: malformed `no_implicit_prelude` attribute input - --> $DIR/malformed-attrs.rs:96:1 + --> $DIR/malformed-attrs.rs:97:1 | LL | #[no_implicit_prelude = 23] | ^^^^^^^^^^^^^^^^^^^^^^----^ @@ -503,7 +503,7 @@ LL | #[no_implicit_prelude = 23] | help: must be of the form: `#[no_implicit_prelude]` error[E0539]: malformed `must_use` attribute input - --> $DIR/malformed-attrs.rs:118:1 + --> $DIR/malformed-attrs.rs:119:1 | LL | #[must_use = 1] | ^^^^^^^^^^^^^-^ @@ -520,7 +520,7 @@ LL + #[must_use] | error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input - --> $DIR/malformed-attrs.rs:127:1 + --> $DIR/malformed-attrs.rs:128:1 | LL | #[rustc_layout_scalar_valid_range_start] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -529,7 +529,7 @@ LL | #[rustc_layout_scalar_valid_range_start] | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]` error[E0539]: malformed `rustc_layout_scalar_valid_range_end` attribute input - --> $DIR/malformed-attrs.rs:129:1 + --> $DIR/malformed-attrs.rs:130:1 | LL | #[rustc_layout_scalar_valid_range_end] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -538,7 +538,7 @@ LL | #[rustc_layout_scalar_valid_range_end] | help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]` error[E0565]: malformed `non_exhaustive` attribute input - --> $DIR/malformed-attrs.rs:196:1 + --> $DIR/malformed-attrs.rs:197:1 | LL | #[non_exhaustive = 1] | ^^^^^^^^^^^^^^^^^---^ @@ -558,8 +558,20 @@ LL | | #[coroutine = 63] || {} LL | | } | |_- not a `const fn` +error: `#[repr(align(...))]` is not supported on function items + --> $DIR/malformed-attrs.rs:48:1 + | +LL | #[repr] + | ^^^^^^^ + | +help: use `#[align(...)]` instead + --> $DIR/malformed-attrs.rs:48:1 + | +LL | #[repr] + | ^^^^^^^ + warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/malformed-attrs.rs:148:1 + --> $DIR/malformed-attrs.rs:149:1 | LL | #[diagnostic::do_not_recommend()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -567,7 +579,7 @@ LL | #[diagnostic::do_not_recommend()] = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: missing options for `on_unimplemented` attribute - --> $DIR/malformed-attrs.rs:137:1 + --> $DIR/malformed-attrs.rs:138:1 | LL | #[diagnostic::on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -575,7 +587,7 @@ LL | #[diagnostic::on_unimplemented] = help: at least one of the `message`, `note` and `label` options are expected warning: malformed `on_unimplemented` attribute - --> $DIR/malformed-attrs.rs:139:1 + --> $DIR/malformed-attrs.rs:140:1 | LL | #[diagnostic::on_unimplemented = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -583,7 +595,7 @@ LL | #[diagnostic::on_unimplemented = 1] = help: only `message`, `note` and `label` are allowed as options error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]` - --> $DIR/malformed-attrs.rs:52:1 + --> $DIR/malformed-attrs.rs:53:1 | LL | #[inline = 5] | ^^^^^^^^^^^^^ @@ -592,7 +604,7 @@ LL | #[inline = 5] = note: for more information, see issue #57571 error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` - --> $DIR/malformed-attrs.rs:93:1 + --> $DIR/malformed-attrs.rs:94:1 | LL | #[ignore()] | ^^^^^^^^^^^ @@ -601,7 +613,7 @@ LL | #[ignore()] = note: for more information, see issue #57571 error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` - --> $DIR/malformed-attrs.rs:222:1 + --> $DIR/malformed-attrs.rs:223:1 | LL | #[ignore = 1] | ^^^^^^^^^^^^^ @@ -610,7 +622,7 @@ LL | #[ignore = 1] = note: for more information, see issue #57571 error[E0308]: mismatched types - --> $DIR/malformed-attrs.rs:110:23 + --> $DIR/malformed-attrs.rs:111:23 | LL | fn test() { | - help: a return type might be missing here: `-> _` @@ -618,9 +630,9 @@ LL | #[coroutine = 63] || {} | ^^^^^ expected `()`, found coroutine | = note: expected unit type `()` - found coroutine `{coroutine@$DIR/malformed-attrs.rs:110:23: 110:25}` + found coroutine `{coroutine@$DIR/malformed-attrs.rs:111:23: 111:25}` -error: aborting due to 74 previous errors; 3 warnings emitted +error: aborting due to 75 previous errors; 3 warnings emitted Some errors have detailed explanations: E0308, E0463, E0539, E0565, E0658, E0805. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/empty/empty-attributes.stderr b/tests/ui/empty/empty-attributes.stderr index e86dea10c70..f0be56ddc6a 100644 --- a/tests/ui/empty/empty-attributes.stderr +++ b/tests/ui/empty/empty-attributes.stderr @@ -1,32 +1,16 @@ error: unused attribute - --> $DIR/empty-attributes.rs:9:1 + --> $DIR/empty-attributes.rs:2:1 | -LL | #[repr()] - | ^^^^^^^^^ help: remove this attribute +LL | #![allow()] + | ^^^^^^^^^^^ help: remove this attribute | - = note: attribute `repr` with an empty list has no effect + = note: attribute `allow` with an empty list has no effect note: the lint level is defined here --> $DIR/empty-attributes.rs:1:9 | LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ -error: unused attribute - --> $DIR/empty-attributes.rs:12:1 - | -LL | #[target_feature()] - | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute - | - = note: attribute `target_feature` with an empty list has no effect - -error: unused attribute - --> $DIR/empty-attributes.rs:2:1 - | -LL | #![allow()] - | ^^^^^^^^^^^ help: remove this attribute - | - = note: attribute `allow` with an empty list has no effect - error: unused attribute --> $DIR/empty-attributes.rs:3:1 | @@ -67,5 +51,17 @@ LL | #![feature()] | = note: attribute `feature` with an empty list has no effect +error: unused attribute + --> $DIR/empty-attributes.rs:9:1 + | +LL | #[repr()] + | ^^^^^^^^^ help: remove this attribute + +error: unused attribute + --> $DIR/empty-attributes.rs:12:1 + | +LL | #[target_feature()] + | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute + error: aborting due to 8 previous errors diff --git a/tests/ui/repr/repr-empty-packed.stderr b/tests/ui/repr/repr-empty-packed.stderr index c824c2998b4..6565b2e8c1d 100644 --- a/tests/ui/repr/repr-empty-packed.stderr +++ b/tests/ui/repr/repr-empty-packed.stderr @@ -1,27 +1,26 @@ +error[E0517]: attribute should be applied to a struct or union + --> $DIR/repr-empty-packed.rs:5:8 + | +LL | #[repr(packed)] + | ^^^^^^ +LL | / pub enum Foo { +LL | | Bar, +LL | | Baz(i32), +LL | | } + | |_- not a struct or union + error: unused attribute --> $DIR/repr-empty-packed.rs:4:1 | LL | #[repr()] | ^^^^^^^^^ help: remove this attribute | - = note: attribute `repr` with an empty list has no effect note: the lint level is defined here --> $DIR/repr-empty-packed.rs:2:9 | LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ -error[E0517]: attribute should be applied to a struct or union - --> $DIR/repr-empty-packed.rs:5:8 - | -LL | #[repr(packed)] - | ^^^^^^ -LL | / pub enum Foo { -LL | | Bar, -LL | | Baz(i32), -LL | | } - | |_- not a struct or union - error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0517`. diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 2b8f3b21396..0a983b41ef3 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -64,7 +64,8 @@ mod attributes { #[doc = "outer doc attribute"] #[doc = "macro"] #[allow()] - #[attr = Repr([ReprC])] + #[attr = Repr {reprs: + [ReprC]}] struct Struct; } -- cgit 1.4.1-3-g733a5 From 61cf174dcea9e606d7c3e89c2df69e22ae888728 Mon Sep 17 00:00:00 2001 From: dvdsk Date: Thu, 3 Jul 2025 17:22:37 +0200 Subject: sleep_until: add clock_nanosleep support to Miri The clock_nanosleep support is there to allow code using `sleep_until` to run under Miri. Therefore the implementation is minimal. - Only the clocks REALTIME and MONOTONIC are supported. The first is supported simply because it was trivial to add not because it was needed for sleep_until. - The only supported flag combinations are no flags or TIMER_ABSTIME only. If an unsupported flag combination or clock is passed in this throws unsupported. --- library/std/src/sys/pal/unix/thread.rs | 1 + src/tools/miri/src/shims/time.rs | 57 ++++++++++++ src/tools/miri/src/shims/unix/foreign_items.rs | 11 +++ src/tools/miri/tests/pass-dep/libc/libc-time.rs | 114 ++++++++++++++++++++++++ src/tools/miri/tests/pass/shims/time.rs | 10 +++ 5 files changed, 193 insertions(+) (limited to 'src/tools') diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 3e4585c7187..53f0d1eeda5 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -297,6 +297,7 @@ impl Thread { } // Any unix that has clock_nanosleep + // If this list changes update the MIRI chock_nanosleep shim #[cfg(any( target_os = "freebsd", target_os = "netbsd", diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 28f4ca5bb1b..4d21fd248c8 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -362,6 +362,63 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(Scalar::from_i32(0)) } + fn clock_nanosleep( + &mut self, + clock_id: &OpTy<'tcx>, + flags: &OpTy<'tcx>, + timespec: &OpTy<'tcx>, + rem: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + let clockid_t_size = this.libc_ty_layout("clockid_t").size; + + let clock_id = this.read_scalar(clock_id)?.to_int(clockid_t_size)?; + let timespec = this.deref_pointer_as(timespec, this.libc_ty_layout("timespec"))?; + let flags = this.read_scalar(flags)?.to_i32()?; + let _rem = this.read_pointer(rem)?; // Signal handlers are not supported, so rem will never be written to. + + // The standard lib through sleep_until only needs CLOCK_MONOTONIC + if clock_id != this.eval_libc("CLOCK_MONOTONIC").to_int(clockid_t_size)? { + throw_unsup_format!("clock_nanosleep: only CLOCK_MONOTONIC is supported"); + } + + let duration = match this.read_timespec(×pec)? { + Some(duration) => duration, + None => { + return this.set_last_error_and_return_i32(LibcError("EINVAL")); + } + }; + + let timeout_anchor = if flags == 0 { + // No flags set, the timespec should be interperted as a duration + // to sleep for + TimeoutAnchor::Relative + } else if flags == this.eval_libc_i32("TIMER_ABSTIME") { + // Only flag TIMER_ABSTIME set, the timespec should be interperted as + // an absolute time. + TimeoutAnchor::Absolute + } else { + // The standard lib (through `sleep_until`) only needs TIMER_ABSTIME + throw_unsup_format!( + "`clock_nanosleep` unsupported flags {flags}, only no flags or \ + TIMER_ABSTIME is supported" + ); + }; + + this.block_thread( + BlockReason::Sleep, + Some((TimeoutClock::Monotonic, timeout_anchor, duration)), + callback!( + @capture<'tcx> {} + |_this, unblock: UnblockKind| { + assert_eq!(unblock, UnblockKind::TimedOut); + interp_ok(()) + } + ), + ); + interp_ok(Scalar::from_i32(0)) + } + #[allow(non_snake_case)] fn Sleep(&mut self, timeout: &OpTy<'tcx>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index b3c58397a02..5f3778d967e 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -967,6 +967,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let result = this.nanosleep(req, rem)?; this.write_scalar(result, dest)?; } + "clock_nanosleep" => { + // Currently this function does not exist on all Unixes, e.g. on macOS. + this.check_target_os( + &["freebsd", "linux", "android", "solaris", "illumos"], + link_name, + )?; + let [clock_id, flags, req, rem] = + this.check_shim(abi, CanonAbi::C, link_name, args)?; + let result = this.clock_nanosleep(clock_id, flags, req, rem)?; + this.write_scalar(result, dest)?; + } "sched_getaffinity" => { // Currently this function does not exist on all Unixes, e.g. on macOS. this.check_target_os(&["linux", "freebsd", "android"], link_name)?; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-time.rs b/src/tools/miri/tests/pass-dep/libc/libc-time.rs index e53201e0bc5..e8957846ad5 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-time.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-time.rs @@ -1,5 +1,6 @@ //@ignore-target: windows # no libc time APIs on Windows //@compile-flags: -Zmiri-disable-isolation +use std::time::{Duration, Instant}; use std::{env, mem, ptr}; fn main() { @@ -20,6 +21,19 @@ fn main() { test_localtime_r_future_32b(); #[cfg(target_pointer_width = "64")] test_localtime_r_future_64b(); + + test_nanosleep(); + #[cfg(any( + target_os = "freebsd", + target_os = "linux", + target_os = "android", + target_os = "solaris", + target_os = "illumos" + ))] + { + test_clock_nanosleep::absolute(); + test_clock_nanosleep::relative(); + } } /// Tests whether clock support exists at all @@ -315,3 +329,103 @@ fn test_localtime_r_multiple_calls_deduplication() { NUM_CALLS - 1 ); } + +fn test_nanosleep() { + let start_test_sleep = Instant::now(); + let duration_zero = libc::timespec { tv_sec: 0, tv_nsec: 0 }; + let remainder = ptr::null_mut::(); + let is_error = unsafe { libc::nanosleep(&duration_zero, remainder) }; + assert_eq!(is_error, 0); + assert!(start_test_sleep.elapsed() < Duration::from_millis(10)); + + let start_test_sleep = Instant::now(); + let duration_100_millis = libc::timespec { tv_sec: 0, tv_nsec: 1_000_000_000 / 10 }; + let remainder = ptr::null_mut::(); + let is_error = unsafe { libc::nanosleep(&duration_100_millis, remainder) }; + assert_eq!(is_error, 0); + assert!(start_test_sleep.elapsed() > Duration::from_millis(100)); +} + +#[cfg(any( + target_os = "freebsd", + target_os = "linux", + target_os = "android", + target_os = "solaris", + target_os = "illumos" +))] +mod test_clock_nanosleep { + use super::*; + + /// Helper function used to create an instant in the future + fn add_100_millis(mut ts: libc::timespec) -> libc::timespec { + // While tv_nsec has type `c_long` tv_sec has type `time_t`. These might + // end up as different types (for example: like i32 and i64). + const SECOND: libc::c_long = 1_000_000_000; + ts.tv_nsec += SECOND / 10; + // If this pushes tv_nsec to SECOND or higher, we need to overflow to tv_sec. + ts.tv_sec += (ts.tv_nsec / SECOND) as libc::time_t; + ts.tv_nsec %= SECOND; + ts + } + + /// Helper function to get the current time for testing relative sleeps + fn timespec_now(clock: libc::clockid_t) -> libc::timespec { + let mut timespec = mem::MaybeUninit::::uninit(); + let is_error = unsafe { libc::clock_gettime(clock, timespec.as_mut_ptr()) }; + assert_eq!(is_error, 0); + unsafe { timespec.assume_init() } + } + + pub fn absolute() { + let start_test_sleep = Instant::now(); + let before_start = libc::timespec { tv_sec: 0, tv_nsec: 0 }; + let remainder = ptr::null_mut::(); + let error = unsafe { + // this will not sleep since unix time zero is in the past + libc::clock_nanosleep( + libc::CLOCK_MONOTONIC, + libc::TIMER_ABSTIME, + &before_start, + remainder, + ) + }; + assert_eq!(error, 0); + assert!(start_test_sleep.elapsed() < Duration::from_millis(10)); + + let start_test_sleep = Instant::now(); + let hunderd_millis_after_start = add_100_millis(timespec_now(libc::CLOCK_MONOTONIC)); + let remainder = ptr::null_mut::(); + let error = unsafe { + libc::clock_nanosleep( + libc::CLOCK_MONOTONIC, + libc::TIMER_ABSTIME, + &hunderd_millis_after_start, + remainder, + ) + }; + assert_eq!(error, 0); + assert!(start_test_sleep.elapsed() > Duration::from_millis(100)); + } + + pub fn relative() { + const NO_FLAGS: i32 = 0; + + let start_test_sleep = Instant::now(); + let duration_zero = libc::timespec { tv_sec: 0, tv_nsec: 0 }; + let remainder = ptr::null_mut::(); + let error = unsafe { + libc::clock_nanosleep(libc::CLOCK_MONOTONIC, NO_FLAGS, &duration_zero, remainder) + }; + assert_eq!(error, 0); + assert!(start_test_sleep.elapsed() < Duration::from_millis(10)); + + let start_test_sleep = Instant::now(); + let duration_100_millis = libc::timespec { tv_sec: 0, tv_nsec: 1_000_000_000 / 10 }; + let remainder = ptr::null_mut::(); + let error = unsafe { + libc::clock_nanosleep(libc::CLOCK_MONOTONIC, NO_FLAGS, &duration_100_millis, remainder) + }; + assert_eq!(error, 0); + assert!(start_test_sleep.elapsed() > Duration::from_millis(100)); + } +} diff --git a/src/tools/miri/tests/pass/shims/time.rs b/src/tools/miri/tests/pass/shims/time.rs index 226f04ade0f..ef0b400f1a7 100644 --- a/src/tools/miri/tests/pass/shims/time.rs +++ b/src/tools/miri/tests/pass/shims/time.rs @@ -1,4 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation +#![feature(thread_sleep_until)] use std::time::{Duration, Instant, SystemTime}; @@ -15,6 +16,14 @@ fn test_sleep() { assert!((after - before).as_millis() >= 100); } +fn test_sleep_until() { + let before = Instant::now(); + let hunderd_millis_after_start = before + Duration::from_millis(100); + std::thread::sleep_until(hunderd_millis_after_start); + let after = Instant::now(); + assert!((after - before).as_millis() >= 100); +} + fn main() { // Check `SystemTime`. let now1 = SystemTime::now(); @@ -49,4 +58,5 @@ fn main() { duration_sanity(diff); test_sleep(); + test_sleep_until(); } -- cgit 1.4.1-3-g733a5