diff options
| author | Laurențiu Nicola <lnicola@users.noreply.github.com> | 2025-05-01 07:33:30 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-01 07:33:30 +0000 |
| commit | 00d2f60efd516bc7ea658bd0a6de5e2f1f1df322 (patch) | |
| tree | 9375885343e27ab26b20dfe5a3714e00d5d378d0 /src/tools | |
| parent | e7502210ce5ab2d92cb87c372dab51b637ba6df4 (diff) | |
| parent | 1c5de64814d72effc6890ca823fa4d248041a0bd (diff) | |
| download | rust-00d2f60efd516bc7ea658bd0a6de5e2f1f1df322.tar.gz rust-00d2f60efd516bc7ea658bd0a6de5e2f1f1df322.zip | |
Merge pull request #19726 from lnicola/sync-from-rust
Sync from downstream again
Diffstat (limited to 'src/tools')
77 files changed, 1079 insertions, 671 deletions
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 7da5a530eaa..5edb5c23570 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -853,7 +853,7 @@ impl TyCoercionStability { continue; }, ty::Param(_) if for_return => Self::Deref, - ty::Alias(ty::Weak | ty::Inherent, _) => unreachable!("should have been normalized away above"), + ty::Alias(ty::Free | ty::Inherent, _) => unreachable!("should have been normalized away above"), ty::Alias(ty::Projection, _) if !for_return && ty.has_non_region_param() => Self::Reborrow, ty::Infer(_) | ty::Error(_) diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index 67537a251da..1f142bc3ba6 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -197,7 +197,7 @@ fn fn_inputs_has_impl_trait_ty(cx: &LateContext<'_>, def_id: LocalDefId) -> bool inputs.iter().any(|input| { matches!( input.kind(), - ty::Alias(ty::AliasTyKind::Weak, alias_ty) if cx.tcx.type_of(alias_ty.def_id).skip_binder().is_impl_trait() + ty::Alias(ty::AliasTyKind::Free, alias_ty) if cx.tcx.type_of(alias_ty.def_id).skip_binder().is_impl_trait() ) }) } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index fe1fd70a9fa..17368a7530d 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1117,6 +1117,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_const_arg(s); self.hash_const_arg(e); }, + TyPatKind::Or(variants) => { + for variant in variants.iter() { + self.hash_ty_pat(variant) + } + }, TyPatKind::Err(_) => {}, } } diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr index bdac1e42309..ad3c420270c 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr +++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr @@ -236,7 +236,7 @@ LL | if result.is_ok() { LL | result.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: creating a shared reference to mutable static is discouraged +error: creating a shared reference to mutable static --> tests/ui/checked_unwrap/simple_conditionals.rs:183:12 | LL | if X.is_some() { diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index e0132056d6c..4f93b498741 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -413,14 +413,6 @@ pub struct Config { /// cross-compilation scenarios that do not otherwise want/need to `-Zbuild-std`. Used in e.g. /// ABI tests. pub minicore_path: Utf8PathBuf, - - /// If true, disable the "new" executor, and use the older libtest-based - /// executor to run tests instead. This is a temporary fallback, to make - /// manual comparative testing easier if bugs are found in the new executor. - /// - /// FIXME(Zalathar): Eventually remove this flag and remove the libtest - /// dependency. - pub no_new_executor: bool, } impl Config { diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index 3bb98276bf5..a45f39b036c 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -30,24 +30,20 @@ impl ErrorKind { /// Either the canonical uppercase string, or some additional versions for compatibility. /// FIXME: consider keeping only the canonical versions here. - fn from_user_str(s: &str) -> Option<ErrorKind> { - Some(match s { + pub fn from_user_str(s: &str) -> ErrorKind { + match s { "HELP" | "help" => ErrorKind::Help, "ERROR" | "error" => ErrorKind::Error, - "NOTE" | "note" => ErrorKind::Note, + // `MONO_ITEM` makes annotations in `codegen-units` tests syntactically correct, + // but those tests never use the error kind later on. + "NOTE" | "note" | "MONO_ITEM" => ErrorKind::Note, "SUGGESTION" => ErrorKind::Suggestion, "WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning, - _ => return None, - }) - } - - pub fn expect_from_user_str(s: &str) -> ErrorKind { - ErrorKind::from_user_str(s).unwrap_or_else(|| { - panic!( + _ => panic!( "unexpected diagnostic kind `{s}`, expected \ `ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`" - ) - }) + ), + } } } @@ -67,8 +63,7 @@ impl fmt::Display for ErrorKind { pub struct Error { pub line_num: Option<usize>, /// What kind of message we expect (e.g., warning, error, suggestion). - /// `None` if not specified or unknown message kind. - pub kind: Option<ErrorKind>, + pub kind: ErrorKind, pub msg: String, /// For some `Error`s, like secondary lines of multi-line diagnostics, line annotations /// are not mandatory, even if they would otherwise be mandatory for primary errors. @@ -79,12 +74,7 @@ pub struct Error { impl Error { pub fn render_for_expected(&self) -> String { use colored::Colorize; - format!( - "{: <10}line {: >3}: {}", - self.kind.map(|kind| kind.to_string()).unwrap_or_default(), - self.line_num_str(), - self.msg.cyan(), - ) + format!("{: <10}line {: >3}: {}", self.kind, self.line_num_str(), self.msg.cyan()) } pub fn line_num_str(&self) -> String { @@ -173,9 +163,10 @@ fn parse_expected( // Get the part of the comment after the sigil (e.g. `~^^` or ~|). let tag = captures.get(0).unwrap(); let rest = line[tag.end()..].trim_start(); - let (kind_str, _) = rest.split_once(|c: char| !c.is_ascii_alphabetic()).unwrap_or((rest, "")); + let (kind_str, _) = + rest.split_once(|c: char| c != '_' && !c.is_ascii_alphabetic()).unwrap_or((rest, "")); let kind = ErrorKind::from_user_str(kind_str); - let untrimmed_msg = if kind.is_some() { &rest[kind_str.len()..] } else { rest }; + let untrimmed_msg = &rest[kind_str.len()..]; let msg = untrimmed_msg.strip_prefix(':').unwrap_or(untrimmed_msg).trim().to_owned(); let line_num_adjust = &captures["adjust"]; diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index 990be56ce0c..e774c5e2047 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -12,7 +12,6 @@ use crate::common::{Config, TestPaths}; mod deadline; mod json; -pub(crate) mod libtest; pub(crate) fn run_tests(config: &Config, tests: Vec<CollectedTest>) -> bool { let tests_len = tests.len(); diff --git a/src/tools/compiletest/src/executor/libtest.rs b/src/tools/compiletest/src/executor/libtest.rs deleted file mode 100644 index 032b3f4fa9a..00000000000 --- a/src/tools/compiletest/src/executor/libtest.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! This submodule encapsulates all of the code that actually interacts with -//! libtest, so that it can be easily removed after the new executor becomes -//! the default. - -use std::borrow::Cow; -use std::io; - -use crate::common::Config; -use crate::executor::{CollectedTest, CollectedTestDesc, ColorConfig, OutputFormat, ShouldPanic}; - -/// Delegates to libtest to run the list of collected tests. -/// -/// Returns `Ok(true)` if all tests passed, or `Ok(false)` if one or more tests failed. -pub(crate) fn execute_tests(config: &Config, tests: Vec<CollectedTest>) -> io::Result<bool> { - let opts = test_opts(config); - let tests = tests.into_iter().map(|t| t.into_libtest()).collect::<Vec<_>>(); - - test::run_tests_console(&opts, tests) -} - -impl CollectedTest { - fn into_libtest(self) -> test::TestDescAndFn { - let Self { desc, config, testpaths, revision } = self; - let CollectedTestDesc { name, ignore, ignore_message, should_panic } = desc; - - // Libtest requires the ignore message to be a &'static str, so we might - // have to leak memory to create it. This is fine, as we only do so once - // per test, so the leak won't grow indefinitely. - let ignore_message = ignore_message.map(|msg| match msg { - Cow::Borrowed(s) => s, - Cow::Owned(s) => &*String::leak(s), - }); - - let desc = test::TestDesc { - name: test::DynTestName(name), - ignore, - ignore_message, - source_file: "", - start_line: 0, - start_col: 0, - end_line: 0, - end_col: 0, - should_panic: should_panic.to_libtest(), - compile_fail: false, - no_run: false, - test_type: test::TestType::Unknown, - }; - - // This closure is invoked when libtest returns control to compiletest - // to execute the test. - let testfn = test::DynTestFn(Box::new(move || { - crate::runtest::run(config, &testpaths, revision.as_deref()); - Ok(()) - })); - - test::TestDescAndFn { desc, testfn } - } -} - -impl ColorConfig { - fn to_libtest(self) -> test::ColorConfig { - match self { - Self::AutoColor => test::ColorConfig::AutoColor, - Self::AlwaysColor => test::ColorConfig::AlwaysColor, - Self::NeverColor => test::ColorConfig::NeverColor, - } - } -} - -impl OutputFormat { - fn to_libtest(self) -> test::OutputFormat { - match self { - Self::Pretty => test::OutputFormat::Pretty, - Self::Terse => test::OutputFormat::Terse, - Self::Json => test::OutputFormat::Json, - } - } -} - -impl ShouldPanic { - fn to_libtest(self) -> test::ShouldPanic { - match self { - Self::No => test::ShouldPanic::No, - Self::Yes => test::ShouldPanic::Yes, - } - } -} - -fn test_opts(config: &Config) -> test::TestOpts { - test::TestOpts { - exclude_should_panic: false, - filters: config.filters.clone(), - filter_exact: config.filter_exact, - run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No }, - format: config.format.to_libtest(), - logfile: None, - run_tests: true, - bench_benchmarks: true, - nocapture: config.nocapture, - color: config.color.to_libtest(), - shuffle: false, - shuffle_seed: None, - test_threads: None, - skip: config.skip.clone(), - list: false, - options: test::Options::new(), - time_options: None, - force_run_in_process: false, - fail_fast: config.fail_fast, - } -} diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 2b203bb309c..8bee9caacc9 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -593,7 +593,7 @@ impl TestProps { config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS) { self.dont_require_annotations - .insert(ErrorKind::expect_from_user_str(err_kind.trim())); + .insert(ErrorKind::from_user_str(err_kind.trim())); } }, ); diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 62fe538ee32..960f5ba5888 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -229,7 +229,7 @@ fn push_actual_errors( // Convert multi-line messages into multiple errors. // We expect to replace these with something more structured anyhow. let mut message_lines = diagnostic.message.lines(); - let kind = Some(ErrorKind::from_compiler_str(&diagnostic.level)); + let kind = ErrorKind::from_compiler_str(&diagnostic.level); let first_line = message_lines.next().unwrap_or(&diagnostic.message); if primary_spans.is_empty() { static RE: OnceLock<Regex> = OnceLock::new(); @@ -278,7 +278,7 @@ fn push_actual_errors( for (index, line) in suggested_replacement.lines().enumerate() { errors.push(Error { line_num: Some(span.line_start + index), - kind: Some(ErrorKind::Suggestion), + kind: ErrorKind::Suggestion, msg: line.to_string(), require_annotation: true, }); @@ -297,7 +297,7 @@ fn push_actual_errors( for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) { errors.push(Error { line_num: Some(span.line_start), - kind: Some(ErrorKind::Note), + kind: ErrorKind::Note, msg: span.label.clone().unwrap(), require_annotation: true, }); @@ -317,7 +317,7 @@ fn push_backtrace( if Path::new(&expansion.span.file_name) == Path::new(&file_name) { errors.push(Error { line_num: Some(expansion.span.line_start), - kind: Some(ErrorKind::Note), + kind: ErrorKind::Note, msg: format!("in this expansion of {}", expansion.macro_decl_name), require_annotation: true, }); diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 788bafaa724..0db4d3f6a41 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -1,11 +1,10 @@ #![crate_name = "compiletest"] -// Needed by the libtest-based test executor. -#![feature(test)] // Needed by the "new" test executor that does not depend on libtest. +// FIXME(Zalathar): We should be able to get rid of `internal_output_capture`, +// by having `runtest` manually capture all of its println-like output instead. +// That would result in compiletest being written entirely in stable Rust! #![feature(internal_output_capture)] -extern crate test; - #[cfg(test)] mod tests; @@ -448,8 +447,6 @@ pub fn parse_config(args: Vec<String>) -> Config { diff_command: matches.opt_str("compiletest-diff-tool"), minicore_path: opt_path(matches, "minicore-path"), - - no_new_executor: matches.opt_present("no-new-executor"), } } @@ -576,12 +573,10 @@ pub fn run_tests(config: Arc<Config>) { // Delegate to the executor to filter and run the big list of test structures // created during test discovery. When the executor decides to run a test, // it will return control to the rest of compiletest by calling `runtest::run`. - let res = if !config.no_new_executor { - Ok(executor::run_tests(&config, tests)) - } else { - // FIXME(Zalathar): Eventually remove the libtest executor entirely. - crate::executor::libtest::execute_tests(&config, tests) - }; + // FIXME(Zalathar): Once we're confident that we won't need to revert the + // removal of the libtest-based executor, remove this Result and other + // remnants of the old executor. + let res: io::Result<bool> = Ok(executor::run_tests(&config, tests)); // Check the outcome reported by libtest. match res { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index fe23cce81e9..97cb82c9e36 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -675,9 +675,7 @@ impl<'test> TestCx<'test> { "check_expected_errors: expected_errors={:?} proc_res.status={:?}", expected_errors, proc_res.status ); - if proc_res.status.success() - && expected_errors.iter().any(|x| x.kind == Some(ErrorKind::Error)) - { + if proc_res.status.success() && expected_errors.iter().any(|x| x.kind == ErrorKind::Error) { self.fatal_proc_rec("process did not return an error status", proc_res); } @@ -709,7 +707,7 @@ impl<'test> TestCx<'test> { // if one of them actually occurs in the test. let expected_kinds: HashSet<_> = [ErrorKind::Error, ErrorKind::Warning] .into_iter() - .chain(expected_errors.iter().filter_map(|e| e.kind)) + .chain(expected_errors.iter().map(|e| e.kind)) .collect(); // Parse the JSON output from the compiler and extract out the messages. @@ -723,8 +721,7 @@ impl<'test> TestCx<'test> { expected_errors.iter().enumerate().position(|(index, expected_error)| { !found[index] && actual_error.line_num == expected_error.line_num - && (expected_error.kind.is_none() - || actual_error.kind == expected_error.kind) + && actual_error.kind == expected_error.kind && actual_error.msg.contains(&expected_error.msg) }); @@ -737,19 +734,14 @@ impl<'test> TestCx<'test> { None => { if actual_error.require_annotation - && actual_error.kind.map_or(false, |kind| { - expected_kinds.contains(&kind) - && !self.props.dont_require_annotations.contains(&kind) - }) + && expected_kinds.contains(&actual_error.kind) + && !self.props.dont_require_annotations.contains(&actual_error.kind) { self.error(&format!( "{}:{}: unexpected {}: '{}'", file_name, actual_error.line_num_str(), - actual_error - .kind - .as_ref() - .map_or(String::from("message"), |k| k.to_string()), + actual_error.kind, actual_error.msg )); unexpected.push(actual_error); @@ -766,7 +758,7 @@ impl<'test> TestCx<'test> { "{}:{}: expected {} not found: {}", file_name, expected_error.line_num_str(), - expected_error.kind.as_ref().map_or("message".into(), |k| k.to_string()), + expected_error.kind, expected_error.msg )); not_found.push(expected_error); diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs index e87b037cd28..cf0ae14f81b 100644 --- a/src/tools/compiletest/src/runtest/ui.rs +++ b/src/tools/compiletest/src/runtest/ui.rs @@ -6,8 +6,8 @@ use rustfix::{Filter, apply_suggestions, get_suggestions_from_json}; use tracing::debug; use super::{ - AllowUnused, Emit, ErrorKind, FailMode, LinkToAux, PassMode, TargetLocation, TestCx, - TestOutput, Truncated, UI_FIXED, WillExecute, + AllowUnused, Emit, FailMode, LinkToAux, PassMode, TargetLocation, TestCx, TestOutput, + Truncated, UI_FIXED, WillExecute, }; use crate::{errors, json}; @@ -176,7 +176,7 @@ impl TestCx<'_> { let msg = format!( "line {}: cannot combine `--error-format` with {} annotations; use `error-pattern` instead", expected_errors[0].line_num_str(), - expected_errors[0].kind.unwrap_or(ErrorKind::Error), + expected_errors[0].kind, ); self.fatal(&msg); } diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 59bae513a58..9dbf51e9796 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -89,41 +89,16 @@ jobs: # Check if all jobs that we depend on (in the needs array) were successful. jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' - cron-fail-notify: - name: cronjob failure notification + cron-rustc-pull: + name: automatic pull from rustc runs-on: ubuntu-latest permissions: # The cronjob needs to be able to push to the repo... contents: write # ... and create a PR. pull-requests: write - needs: [build, style, coverage] - if: ${{ github.event_name == 'schedule' && failure() }} + if: ${{ github.event_name == 'schedule' }} steps: - # Send a Zulip notification - - name: Install zulip-send - run: pip3 install zulip - - name: Send Zulip notification - env: - ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }} - ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} - run: | - ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \ - --stream miri --subject "Miri Build Failure ($(date -u +%Y-%m))" \ - --message 'Dear @*T-miri*, - - It would appear that the [Miri cron job build]('"https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"') failed. - - This likely means that rustc changed the miri directory and - we now need to do a [`./miri rustc-pull`](https://github.com/rust-lang/miri/blob/master/CONTRIBUTING.md#importing-changes-from-the-rustc-repo). - - Would you mind investigating this issue? - - Thanks in advance! - Sincerely, - The Miri Cronjobs Bot' - - # Attempt to auto-sync with rustc - uses: actions/checkout@v4 with: fetch-depth: 256 # get a bit more of the history @@ -143,18 +118,45 @@ jobs: run: | ./miri toolchain ./miri fmt --check || (./miri fmt && git commit -am "fmt") - - name: Push changes to a branch + - name: Push changes to a branch and create PR run: | + # `git diff --exit-code` "succeeds" if the diff is empty. + if git diff --exit-code HEAD^; then echo "Nothing changed in rustc, skipping PR"; exit 0; fi + # The diff is non-empty, create a PR. BRANCH="rustup-$(date -u +%Y-%m-%d)" git switch -c $BRANCH git push -u origin $BRANCH - - name: Create Pull Request - run: | - PR=$(gh pr create -B master --title 'Automatic Rustup' --body 'Please close and re-open this PR to trigger CI, then enable auto-merge.') - ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \ - --stream miri --subject "Miri Build Failure ($(date -u +%Y-%m))" \ - --message "A PR doing a rustc-pull [has been automatically created]($PR) for your convenience." + gh pr create -B master --title 'Automatic Rustup' --body 'Please close and re-open this PR to trigger CI, then enable auto-merge.' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }} ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} + + cron-fail-notify: + name: cronjob failure notification + runs-on: ubuntu-latest + needs: [build, style, coverage] + if: ${{ github.event_name == 'schedule' && failure() }} + steps: + # Send a Zulip notification + - name: Install zulip-send + run: pip3 install zulip + - name: Send Zulip notification + env: + ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }} + ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} + run: | + ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \ + --stream miri --subject "Miri Build Failure ($(date -u +%Y-%m))" \ + --message 'Dear @*T-miri*, + + It would appear that the [Miri cron job build]('"https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"') failed. + + This likely means that rustc changed the miri directory and + we now need to do a [`./miri rustc-pull`](https://github.com/rust-lang/miri/blob/master/CONTRIBUTING.md#importing-changes-from-the-rustc-repo). + + Would you mind investigating this issue? + + Thanks in advance! + Sincerely, + The Miri Cronjobs Bot' diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index e8ea988558c..95e1770aa7b 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -489,7 +489,7 @@ Miri knows where it is supposed to start execution: ```rust #[cfg(miri)] -#[no_mangle] +#[unsafe(no_mangle)] fn miri_start(argc: isize, argv: *const *const u8) -> isize { // Call the actual start function that your project implements, based on your target's conventions. } diff --git a/src/tools/miri/bench-cargo-miri/mse/src/main.rs b/src/tools/miri/bench-cargo-miri/mse/src/main.rs index 06d5487d1d4..69c7c39cdd7 100644 --- a/src/tools/miri/bench-cargo-miri/mse/src/main.rs +++ b/src/tools/miri/bench-cargo-miri/mse/src/main.rs @@ -13,7 +13,7 @@ fn read_i16(buffer: &[u8], index: usize) -> i16 { const SIZE: usize = size_of::<i16>(); let mut bytes: [u8; SIZE] = [0u8; SIZE]; bytes.copy_from_slice(&buffer[(index * SIZE)..(index * SIZE + SIZE)]); - unsafe { std::mem::transmute(bytes) } + i16::from_ne_bytes(bytes) } fn mse(samples: usize, frame_buf: &[i16], buf_ref: &[u8]) -> f64 { diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index d1107e51509..59d53891217 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -1bc56185ee257ed829a0aea7abdc3b03c5fed887 +1b8ab72680f36e783af84c1a3c4f8508572bd9f9 diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index c263e86c082..335e8d76999 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -107,47 +107,6 @@ fn align_addr(addr: u64, align: u64) -> u64 { impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { - // Returns the exposed `AllocId` that corresponds to the specified addr, - // or `None` if the addr is out of bounds - fn alloc_id_from_addr(&self, addr: u64, size: i64) -> Option<AllocId> { - let this = self.eval_context_ref(); - let global_state = this.machine.alloc_addresses.borrow(); - assert!(global_state.provenance_mode != ProvenanceMode::Strict); - - // We always search the allocation to the right of this address. So if the size is structly - // negative, we have to search for `addr-1` instead. - let addr = if size >= 0 { addr } else { addr.saturating_sub(1) }; - let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr); - - // Determine the in-bounds provenance for this pointer. - let alloc_id = match pos { - Ok(pos) => Some(global_state.int_to_ptr_map[pos].1), - Err(0) => None, - Err(pos) => { - // This is the largest of the addresses smaller than `int`, - // i.e. the greatest lower bound (glb) - let (glb, alloc_id) = global_state.int_to_ptr_map[pos - 1]; - // This never overflows because `addr >= glb` - let offset = addr - glb; - // We require this to be strict in-bounds of the allocation. This arm is only - // entered for addresses that are not the base address, so even zero-sized - // allocations will get recognized at their base address -- but all other - // allocations will *not* be recognized at their "end" address. - let size = this.get_alloc_info(alloc_id).size; - if offset < size.bytes() { Some(alloc_id) } else { None } - } - }?; - - // We only use this provenance if it has been exposed. - if global_state.exposed.contains(&alloc_id) { - // This must still be live, since we remove allocations from `int_to_ptr_map` when they get freed. - debug_assert!(this.is_alloc_live(alloc_id)); - Some(alloc_id) - } else { - None - } - } - fn addr_from_alloc_id_uncached( &self, global_state: &mut GlobalStateInner, @@ -242,11 +201,65 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(base_addr) } } +} +impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} +pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + // Returns the `AllocId` that corresponds to the specified addr, + // or `None` if the addr is out of bounds. + // Setting `only_exposed_allocations` selects whether only exposed allocations are considered. + fn alloc_id_from_addr( + &self, + addr: u64, + size: i64, + only_exposed_allocations: bool, + ) -> Option<AllocId> { + let this = self.eval_context_ref(); + let global_state = this.machine.alloc_addresses.borrow(); + assert!(global_state.provenance_mode != ProvenanceMode::Strict); + + // We always search the allocation to the right of this address. So if the size is strictly + // negative, we have to search for `addr-1` instead. + let addr = if size >= 0 { addr } else { addr.saturating_sub(1) }; + let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr); + + // Determine the in-bounds provenance for this pointer. + let alloc_id = match pos { + Ok(pos) => Some(global_state.int_to_ptr_map[pos].1), + Err(0) => None, + Err(pos) => { + // This is the largest of the addresses smaller than `int`, + // i.e. the greatest lower bound (glb) + let (glb, alloc_id) = global_state.int_to_ptr_map[pos - 1]; + // This never overflows because `addr >= glb` + let offset = addr - glb; + // We require this to be strict in-bounds of the allocation. This arm is only + // entered for addresses that are not the base address, so even zero-sized + // allocations will get recognized at their base address -- but all other + // allocations will *not* be recognized at their "end" address. + let size = this.get_alloc_info(alloc_id).size; + if offset < size.bytes() { Some(alloc_id) } else { None } + } + }?; + + // We only use this provenance if it has been exposed, or if the caller requested also non-exposed allocations + if !only_exposed_allocations || global_state.exposed.contains(&alloc_id) { + // This must still be live, since we remove allocations from `int_to_ptr_map` when they get freed. + debug_assert!(this.is_alloc_live(alloc_id)); + Some(alloc_id) + } else { + None + } + } + + /// Returns the base address of an allocation, or an error if no base address could be found + /// + /// # Panics + /// If `memory_kind = None` and the `alloc_id` is not cached, meaning that the first call to this function per `alloc_id` must get the `memory_kind`. fn addr_from_alloc_id( &self, alloc_id: AllocId, - memory_kind: MemoryKind, + memory_kind: Option<MemoryKind>, ) -> InterpResult<'tcx, u64> { let this = self.eval_context_ref(); let mut global_state = this.machine.alloc_addresses.borrow_mut(); @@ -256,8 +269,10 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { Some(&addr) => interp_ok(addr), None => { // First time we're looking for the absolute address of this allocation. + let memory_kind = + memory_kind.expect("memory_kind is required since alloc_id is not cached"); let base_addr = - self.addr_from_alloc_id_uncached(global_state, alloc_id, memory_kind)?; + this.addr_from_alloc_id_uncached(global_state, alloc_id, memory_kind)?; trace!("Assigning base address {:#x} to allocation {:?}", base_addr, alloc_id); // Store address in cache. @@ -283,10 +298,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } } -} -impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn expose_provenance(&self, provenance: Provenance) -> InterpResult<'tcx> { let this = self.eval_context_ref(); let mut global_state = this.machine.alloc_addresses.borrow_mut(); @@ -365,7 +377,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let alloc_id = prov.alloc_id(); // Get a pointer to the beginning of this allocation. - let base_addr = this.addr_from_alloc_id(alloc_id, kind)?; + let base_addr = this.addr_from_alloc_id(alloc_id, Some(kind))?; let base_ptr = interpret::Pointer::new( Provenance::Concrete { alloc_id, tag }, Size::from_bytes(base_addr), @@ -388,7 +400,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // In native lib mode, MiriAllocBytes for global allocations are handled via `prepared_alloc_bytes`. // This additional call ensures that some `MiriAllocBytes` are always prepared, just in case // this function gets called before the first time `addr_from_alloc_id` gets called. - this.addr_from_alloc_id(id, MiriMemoryKind::Global.into())?; + this.addr_from_alloc_id(id, Some(MiriMemoryKind::Global.into()))?; // The memory we need here will have already been allocated during an earlier call to // `addr_from_alloc_id` for this allocation. So don't create a new `MiriAllocBytes` here, instead // fetch the previously prepared bytes from `prepared_alloc_bytes`. @@ -423,7 +435,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { alloc_id } else { // A wildcard pointer. - this.alloc_id_from_addr(addr.bytes(), size)? + let only_exposed_allocations = true; + this.alloc_id_from_addr(addr.bytes(), size, only_exposed_allocations)? }; // This cannot fail: since we already have a pointer with that provenance, adjust_alloc_root_pointer diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 4e8fe0ca8ad..8ff1c9d6ff0 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -106,7 +106,7 @@ fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, MiriEntryFnType) { } else { tcx.dcx().fatal( "`miri_start` must have the following signature:\n\ - fn miri_start(argc: isize, argv: *const *const u8) -> isize", + fn miri_start(argc: isize, argv: *const *const u8) -> isize", ); } } else { @@ -115,7 +115,7 @@ fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, MiriEntryFnType) { Alternatively, you can export a `miri_start` function:\n\ \n\ #[cfg(miri)]\n\ - #[no_mangle]\n\ + #[unsafe(no_mangle)]\n\ fn miri_start(argc: isize, argv: *const *const u8) -> isize {\ \n // Call the actual start function that your project implements, based on your target's conventions.\n\ }" diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs index a429940748c..dbfa9807e3b 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs @@ -61,8 +61,7 @@ fn all_read_accesses_commute() { // ... and produce the same final result. assert_eq!( loc12, loc21, - "Read accesses {:?} followed by {:?} do not commute !", - rel1, rel2 + "Read accesses {rel1:?} followed by {rel2:?} do not commute !" ); } } @@ -674,8 +673,8 @@ mod spurious_read { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (x, y) = self.retag_permissions(); write!(f, "{}; ", self.xy_rel)?; - write!(f, "y: ({}); ", y,)?; - write!(f, "retag x ({}); ", x)?; + write!(f, "y: ({y}); ")?; + write!(f, "retag x ({x}); ")?; write!(f, "<arbitrary code>; <spurious read x>;")?; Ok(()) @@ -730,17 +729,17 @@ mod spurious_read { // protector. final_source .distinguishable::</*X*/ AllowRet, /*Y*/ AllowRet>(&final_target) - .then_some(format!("{}", final_target)) + .then_some(format!("{final_target}")) } else { Some(format!("UB")) } }; if let Some(final_target) = distinguishable { eprintln!( - "For pattern '{}', inserting a spurious read through x makes the final state '{}' instead of '{}' which is observable", - pat, final_target, final_source + "For pattern '{pat}', inserting a spurious read through x makes the final state '{final_target}' \ + instead of '{final_source}' which is observable" ); - eprintln!(" (arbitrary code instanciated with '{}')", opaque); + eprintln!(" (arbitrary code instanciated with '{opaque}')"); err += 1; // We found an instanciation of the opaque code that makes this Pattern // fail, we don't really need to check the rest. diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 923031dbbd1..847c6823475 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -381,7 +381,7 @@ impl AccessType { }); if let Some(ty) = ty { - msg.push_str(&format!(" of type `{}`", ty)); + msg.push_str(&format!(" of type `{ty}`")); } msg diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 1af3d1abc64..a3aa8bbbfb3 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1017,7 +1017,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Check that the given `caller_fn_abi` matches the expected ABI described by - /// `callee_abi`, `callee_input_tys`, `callee_output_ty`, and the return the list of + /// `callee_abi`, `callee_input_tys`, `callee_output_ty`, and then returns the list of /// arguments. fn check_shim_abi<'a, const N: usize>( &mut self, diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 7d60a7e5c48..3334c0b5edf 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -7,13 +7,13 @@ use rand::Rng; use rustc_abi::Size; use rustc_apfloat::{Float, Round}; use rustc_middle::mir; -use rustc_middle::ty::{self, FloatTy, ScalarInt}; +use rustc_middle::ty::{self, FloatTy}; use rustc_span::{Symbol, sym}; use self::atomic::EvalContextExt as _; use self::helpers::{ToHost, ToSoft, check_intrinsic_arg_count}; use self::simd::EvalContextExt as _; -use crate::math::apply_random_float_error_ulp; +use crate::math::apply_random_float_error_to_imm; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -473,26 +473,3 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(EmulateItemResult::NeedsReturn) } } - -/// Applies a random 16ULP floating point error to `val` and returns the new value. -/// Will fail if `val` is not a floating point number. -fn apply_random_float_error_to_imm<'tcx>( - ecx: &mut MiriInterpCx<'tcx>, - val: ImmTy<'tcx>, - ulp_exponent: u32, -) -> InterpResult<'tcx, ImmTy<'tcx>> { - let scalar = val.to_scalar_int()?; - let res: ScalarInt = match val.layout.ty.kind() { - ty::Float(FloatTy::F16) => - apply_random_float_error_ulp(ecx, scalar.to_f16(), ulp_exponent).into(), - ty::Float(FloatTy::F32) => - apply_random_float_error_ulp(ecx, scalar.to_f32(), ulp_exponent).into(), - ty::Float(FloatTy::F64) => - apply_random_float_error_ulp(ecx, scalar.to_f64(), ulp_exponent).into(), - ty::Float(FloatTy::F128) => - apply_random_float_error_ulp(ecx, scalar.to_f128(), ulp_exponent).into(), - _ => bug!("intrinsic called with non-float input type"), - }; - - interp_ok(ImmTy::from_scalar_int(res, val.layout)) -} diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index ea59d327be8..55aa3d6fa68 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -721,9 +721,8 @@ impl<'tcx> MiriMachine<'tcx> { // Check if host target == the session target. if host_triple != target_triple { panic!( - "calling external C functions in linked .so file requires host and target to be the same: host={}, target={}", - host_triple, - target_triple, + "calling native C functions in linked .so file requires host and target to be the same: \ + host={host_triple}, target={target_triple}", ); } // Note: it is the user's responsibility to provide a correct SO file. @@ -1200,6 +1199,16 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { } #[inline(always)] + fn apply_float_nondet( + ecx: &mut InterpCx<'tcx, Self>, + val: ImmTy<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx>> { + crate::math::apply_random_float_error_to_imm( + ecx, val, 2 /* log2(4) */ + ) + } + + #[inline(always)] fn equal_float_min_max<F: Float>(ecx: &MiriInterpCx<'tcx>, a: F, b: F) -> F { ecx.equal_float_min_max(a, b) } diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs index fdd021f8539..2ff29c7ac1a 100644 --- a/src/tools/miri/src/math.rs +++ b/src/tools/miri/src/math.rs @@ -1,6 +1,9 @@ use rand::Rng as _; use rustc_apfloat::Float as _; use rustc_apfloat::ieee::IeeeFloat; +use rustc_middle::ty::{self, FloatTy, ScalarInt}; + +use crate::*; /// Disturbes a floating-point result by a relative error in the range (-2^scale, 2^scale). /// @@ -43,6 +46,29 @@ pub(crate) fn apply_random_float_error_ulp<F: rustc_apfloat::Float>( apply_random_float_error(ecx, val, err_scale) } +/// Applies a random 16ULP floating point error to `val` and returns the new value. +/// Will fail if `val` is not a floating point number. +pub(crate) fn apply_random_float_error_to_imm<'tcx>( + ecx: &mut MiriInterpCx<'tcx>, + val: ImmTy<'tcx>, + ulp_exponent: u32, +) -> InterpResult<'tcx, ImmTy<'tcx>> { + let scalar = val.to_scalar_int()?; + let res: ScalarInt = match val.layout.ty.kind() { + ty::Float(FloatTy::F16) => + apply_random_float_error_ulp(ecx, scalar.to_f16(), ulp_exponent).into(), + ty::Float(FloatTy::F32) => + apply_random_float_error_ulp(ecx, scalar.to_f32(), ulp_exponent).into(), + ty::Float(FloatTy::F64) => + apply_random_float_error_ulp(ecx, scalar.to_f64(), ulp_exponent).into(), + ty::Float(FloatTy::F128) => + apply_random_float_error_ulp(ecx, scalar.to_f128(), ulp_exponent).into(), + _ => bug!("intrinsic called with non-float input type"), + }; + + interp_ok(ImmTy::from_scalar_int(res, val.layout)) +} + pub(crate) fn sqrt<S: rustc_apfloat::ieee::Semantics>(x: IeeeFloat<S>) -> IeeeFloat<S> { match x.category() { // preserve zero sign diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index fb80a36af9f..28f4ca5bb1b 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -21,7 +21,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, clk_id_op: &OpTy<'tcx>, tp_op: &OpTy<'tcx>, - ) -> InterpResult<'tcx, Scalar> { + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx> { // This clock support is deliberately minimal because a lot of clock types have fiddly // properties (is it possible for Miri to be suspended independently of the host?). If you // have a use for another clock type, please open an issue. @@ -29,8 +30,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("clock_gettime"); + let clockid_t_size = this.libc_ty_layout("clockid_t").size; - let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; + let clk_id = this.read_scalar(clk_id_op)?.to_int(clockid_t_size)?; let tp = this.deref_pointer_as(tp_op, this.libc_ty_layout("timespec"))?; let absolute_clocks; @@ -43,34 +45,34 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Linux further distinguishes regular and "coarse" clocks, but the "coarse" version // is just specified to be "faster and less precise", so we implement both the same way. absolute_clocks = vec![ - this.eval_libc_i32("CLOCK_REALTIME"), - this.eval_libc_i32("CLOCK_REALTIME_COARSE"), + this.eval_libc("CLOCK_REALTIME").to_int(clockid_t_size)?, + this.eval_libc("CLOCK_REALTIME_COARSE").to_int(clockid_t_size)?, ]; // The second kind is MONOTONIC clocks for which 0 is an arbitrary time point, but they are // never allowed to go backwards. We don't need to do any additional monotonicity // enforcement because std::time::Instant already guarantees that it is monotonic. relative_clocks = vec![ - this.eval_libc_i32("CLOCK_MONOTONIC"), - this.eval_libc_i32("CLOCK_MONOTONIC_COARSE"), + this.eval_libc("CLOCK_MONOTONIC").to_int(clockid_t_size)?, + this.eval_libc("CLOCK_MONOTONIC_COARSE").to_int(clockid_t_size)?, ]; } "macos" => { - absolute_clocks = vec![this.eval_libc_i32("CLOCK_REALTIME")]; - relative_clocks = vec![this.eval_libc_i32("CLOCK_MONOTONIC")]; + absolute_clocks = vec![this.eval_libc("CLOCK_REALTIME").to_int(clockid_t_size)?]; + relative_clocks = vec![this.eval_libc("CLOCK_MONOTONIC").to_int(clockid_t_size)?]; // `CLOCK_UPTIME_RAW` supposed to not increment while the system is asleep... but // that's not really something a program running inside Miri can tell, anyway. // We need to support it because std uses it. - relative_clocks.push(this.eval_libc_i32("CLOCK_UPTIME_RAW")); + relative_clocks.push(this.eval_libc("CLOCK_UPTIME_RAW").to_int(clockid_t_size)?); } "solaris" | "illumos" => { // The REALTIME clock returns the actual time since the Unix epoch. - absolute_clocks = vec![this.eval_libc_i32("CLOCK_REALTIME")]; + absolute_clocks = vec![this.eval_libc("CLOCK_REALTIME").to_int(clockid_t_size)?]; // MONOTONIC, in the other hand, is the high resolution, non-adjustable // clock from an arbitrary time in the past. // Note that the man page mentions HIGHRES but it is just // an alias of MONOTONIC and the libc crate does not expose it anyway. // https://docs.oracle.com/cd/E23824_01/html/821-1465/clock-gettime-3c.html - relative_clocks = vec![this.eval_libc_i32("CLOCK_MONOTONIC")]; + relative_clocks = vec![this.eval_libc("CLOCK_MONOTONIC").to_int(clockid_t_size)?]; } target => throw_unsup_format!("`clock_gettime` is not supported on target OS {target}"), } @@ -81,15 +83,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } else if relative_clocks.contains(&clk_id) { this.machine.monotonic_clock.now().duration_since(this.machine.monotonic_clock.epoch()) } else { - return this.set_last_error_and_return_i32(LibcError("EINVAL")); + return this.set_last_error_and_return(LibcError("EINVAL"), dest); }; let tv_sec = duration.as_secs(); let tv_nsec = duration.subsec_nanos(); this.write_int_fields(&[tv_sec.into(), tv_nsec.into()], &tp)?; + this.write_int(0, dest)?; - interp_ok(Scalar::from_i32(0)) + interp_ok(()) } fn gettimeofday( @@ -188,10 +191,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { tm_zone.push('+'); } let offset_hour = offset_in_seconds.abs() / 3600; - write!(tm_zone, "{:02}", offset_hour).unwrap(); + write!(tm_zone, "{offset_hour:02}").unwrap(); let offset_min = (offset_in_seconds.abs() % 3600) / 60; if offset_min != 0 { - write!(tm_zone, "{:02}", offset_min).unwrap(); + write!(tm_zone, "{offset_min:02}").unwrap(); } // Add null terminator for C string compatibility. diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 5e6259c3574..026aa1f9503 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -112,51 +112,122 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // Environment related shims "getenv" => { - let [name] = this.check_shim(abi, Conv::C, link_name, args)?; + let [name] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.machine.layouts.const_raw_ptr.ty], + this.machine.layouts.mut_raw_ptr.ty, + args, + )?; let result = this.getenv(name)?; this.write_pointer(result, dest)?; } "unsetenv" => { - let [name] = this.check_shim(abi, Conv::C, link_name, args)?; + let [name] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.machine.layouts.const_raw_ptr.ty], + this.tcx.types.i32, + args, + )?; let result = this.unsetenv(name)?; this.write_scalar(result, dest)?; } "setenv" => { - let [name, value, overwrite] = this.check_shim(abi, Conv::C, link_name, args)?; + let [name, value, overwrite] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [ + this.machine.layouts.const_raw_ptr.ty, + this.machine.layouts.const_raw_ptr.ty, + this.tcx.types.i32, + ], + this.tcx.types.i32, + args, + )?; this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(result, dest)?; } "getcwd" => { - let [buf, size] = this.check_shim(abi, Conv::C, link_name, args)?; + let [buf, size] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.machine.layouts.mut_raw_ptr.ty, this.tcx.types.usize], + this.machine.layouts.mut_raw_ptr.ty, + args, + )?; let result = this.getcwd(buf, size)?; this.write_pointer(result, dest)?; } "chdir" => { - let [path] = this.check_shim(abi, Conv::C, link_name, args)?; + let [path] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.machine.layouts.const_raw_ptr.ty], + this.tcx.types.i32, + args, + )?; let result = this.chdir(path)?; this.write_scalar(result, dest)?; } "getpid" => { - let [] = this.check_shim(abi, Conv::C, link_name, args)?; + let [] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [], + this.libc_ty_layout("pid_t").ty, + args, + )?; let result = this.getpid()?; this.write_scalar(result, dest)?; } "sysconf" => { - let [val] = this.check_shim(abi, Conv::C, link_name, args)?; + let [val] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.tcx.types.i32], + this.tcx.types.isize, + args, + )?; let result = this.sysconf(val)?; this.write_scalar(result, dest)?; } // File descriptors "read" => { - let [fd, buf, count] = this.check_shim(abi, Conv::C, link_name, args)?; + let [fd, buf, count] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.tcx.types.i32, this.machine.layouts.mut_raw_ptr.ty, this.tcx.types.usize], + this.tcx.types.isize, + args, + )?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(count)?; this.read(fd, buf, count, None, dest)?; } "write" => { - let [fd, buf, n] = this.check_shim(abi, Conv::C, link_name, args)?; + let [fd, buf, n] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [ + this.tcx.types.i32, + this.machine.layouts.const_raw_ptr.ty, + this.tcx.types.usize, + ], + this.tcx.types.isize, + args, + )?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(n)?; @@ -164,38 +235,88 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write(fd, buf, count, None, dest)?; } "pread" => { - let [fd, buf, count, offset] = this.check_shim(abi, Conv::C, link_name, args)?; + let off_t = this.libc_ty_layout("off_t"); + let [fd, buf, count, offset] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [ + this.tcx.types.i32, + this.machine.layouts.mut_raw_ptr.ty, + this.tcx.types.usize, + off_t.ty, + ], + this.tcx.types.isize, + args, + )?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(count)?; - let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?; + let offset = this.read_scalar(offset)?.to_int(off_t.size)?; this.read(fd, buf, count, Some(offset), dest)?; } "pwrite" => { - let [fd, buf, n, offset] = this.check_shim(abi, Conv::C, link_name, args)?; + let off_t = this.libc_ty_layout("off_t"); + let [fd, buf, n, offset] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [ + this.tcx.types.i32, + this.machine.layouts.const_raw_ptr.ty, + this.tcx.types.usize, + off_t.ty, + ], + this.tcx.types.isize, + args, + )?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(n)?; - let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?; + let offset = this.read_scalar(offset)?.to_int(off_t.size)?; trace!("Called pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset); this.write(fd, buf, count, Some(offset), dest)?; } "pread64" => { - let [fd, buf, count, offset] = this.check_shim(abi, Conv::C, link_name, args)?; + let off64_t = this.libc_ty_layout("off64_t"); + let [fd, buf, count, offset] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [ + this.tcx.types.i32, + this.machine.layouts.mut_raw_ptr.ty, + this.tcx.types.usize, + off64_t.ty, + ], + this.tcx.types.isize, + args, + )?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(count)?; - let offset = - this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?; + let offset = this.read_scalar(offset)?.to_int(off64_t.size)?; this.read(fd, buf, count, Some(offset), dest)?; } "pwrite64" => { - let [fd, buf, n, offset] = this.check_shim(abi, Conv::C, link_name, args)?; + let off64_t = this.libc_ty_layout("off64_t"); + let [fd, buf, n, offset] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [ + this.tcx.types.i32, + this.machine.layouts.const_raw_ptr.ty, + this.tcx.types.usize, + off64_t.ty, + ], + this.tcx.types.isize, + args, + )?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(n)?; - let offset = - this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?; + let offset = this.read_scalar(offset)?.to_int(off64_t.size)?; trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset); this.write(fd, buf, count, Some(offset), dest)?; } @@ -218,13 +339,27 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "dup" => { - let [old_fd] = this.check_shim(abi, Conv::C, link_name, args)?; + let [old_fd] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.tcx.types.i32], + this.tcx.types.i32, + args, + )?; let old_fd = this.read_scalar(old_fd)?.to_i32()?; let new_fd = this.dup(old_fd)?; this.write_scalar(new_fd, dest)?; } "dup2" => { - let [old_fd, new_fd] = this.check_shim(abi, Conv::C, link_name, args)?; + let [old_fd, new_fd] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.tcx.types.i32, this.tcx.types.i32], + this.tcx.types.i32, + args, + )?; let old_fd = this.read_scalar(old_fd)?.to_i32()?; let new_fd = this.read_scalar(new_fd)?.to_i32()?; let result = this.dup2(old_fd, new_fd)?; @@ -233,7 +368,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "flock" => { // Currently this function does not exist on all Unixes, e.g. on Solaris. this.check_target_os(&["linux", "freebsd", "macos", "illumos"], link_name)?; - let [fd, op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [fd, op] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.tcx.types.i32, this.tcx.types.i32], + this.tcx.types.i32, + args, + )?; let fd = this.read_scalar(fd)?.to_i32()?; let op = this.read_scalar(op)?.to_i32()?; let result = this.flock(fd, op)?; @@ -250,140 +392,311 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "unlink" => { - let [path] = this.check_shim(abi, Conv::C, link_name, args)?; + let [path] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.machine.layouts.const_raw_ptr.ty], + this.tcx.types.i32, + args, + )?; let result = this.unlink(path)?; this.write_scalar(result, dest)?; } "symlink" => { - let [target, linkpath] = this.check_shim(abi, Conv::C, link_name, args)?; + let [target, linkpath] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.const_raw_ptr.ty], + this.tcx.types.i32, + args, + )?; let result = this.symlink(target, linkpath)?; this.write_scalar(result, dest)?; } "rename" => { - let [oldpath, newpath] = this.check_shim(abi, Conv::C, link_name, args)?; + let [oldpath, newpath] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.const_raw_ptr.ty], + this.tcx.types.i32, + args, + )?; let result = this.rename(oldpath, newpath)?; this.write_scalar(result, dest)?; } "mkdir" => { - let [path, mode] = this.check_shim(abi, Conv::C, link_name, args)?; + let [path, mode] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.machine.layouts.const_raw_ptr.ty, this.libc_ty_layout("mode_t").ty], + this.tcx.types.i32, + args, + )?; let result = this.mkdir(path, mode)?; this.write_scalar(result, dest)?; } "rmdir" => { - let [path] = this.check_shim(abi, Conv::C, link_name, args)?; + let [path] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.machine.layouts.const_raw_ptr.ty], + this.tcx.types.i32, + args, + )?; let result = this.rmdir(path)?; this.write_scalar(result, dest)?; } "opendir" => { - let [name] = this.check_shim(abi, Conv::C, link_name, args)?; + let [name] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.machine.layouts.const_raw_ptr.ty], + this.machine.layouts.mut_raw_ptr.ty, + args, + )?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "closedir" => { - let [dirp] = this.check_shim(abi, Conv::C, link_name, args)?; + let [dirp] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.machine.layouts.mut_raw_ptr.ty], + this.tcx.types.i32, + args, + )?; let result = this.closedir(dirp)?; this.write_scalar(result, dest)?; } "lseek64" => { - let [fd, offset, whence] = this.check_shim(abi, Conv::C, link_name, args)?; + let off64_t = this.libc_ty_layout("off64_t"); + let [fd, offset, whence] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.tcx.types.i32, off64_t.ty, this.tcx.types.i32], + off64_t.ty, + args, + )?; let fd = this.read_scalar(fd)?.to_i32()?; - let offset = this.read_scalar(offset)?.to_i64()?; + let offset = this.read_scalar(offset)?.to_int(off64_t.size)?; let whence = this.read_scalar(whence)?.to_i32()?; - let result = this.lseek64(fd, offset.into(), whence)?; - this.write_scalar(result, dest)?; + this.lseek64(fd, offset, whence, dest)?; } "lseek" => { - let [fd, offset, whence] = this.check_shim(abi, Conv::C, link_name, args)?; + let off_t = this.libc_ty_layout("off_t"); + let [fd, offset, whence] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.tcx.types.i32, off_t.ty, this.tcx.types.i32], + off_t.ty, + args, + )?; let fd = this.read_scalar(fd)?.to_i32()?; - let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?; + let offset = this.read_scalar(offset)?.to_int(off_t.size)?; let whence = this.read_scalar(whence)?.to_i32()?; - let result = this.lseek64(fd, offset, whence)?; - this.write_scalar(result, dest)?; + this.lseek64(fd, offset, whence, dest)?; } "ftruncate64" => { - let [fd, length] = this.check_shim(abi, Conv::C, link_name, args)?; + let off64_t = this.libc_ty_layout("off64_t"); + let [fd, length] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.tcx.types.i32, off64_t.ty], + this.tcx.types.i32, + args, + )?; let fd = this.read_scalar(fd)?.to_i32()?; - let length = this.read_scalar(length)?.to_i64()?; - let result = this.ftruncate64(fd, length.into())?; + let length = this.read_scalar(length)?.to_int(off64_t.size)?; + let result = this.ftruncate64(fd, length)?; this.write_scalar(result, dest)?; } "ftruncate" => { - let [fd, length] = this.check_shim(abi, Conv::C, link_name, args)?; + let off_t = this.libc_ty_layout("off_t"); + let [fd, length] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.tcx.types.i32, off_t.ty], + this.tcx.types.i32, + args, + )?; let fd = this.read_scalar(fd)?.to_i32()?; - let length = this.read_scalar(length)?.to_int(this.libc_ty_layout("off_t").size)?; + let length = this.read_scalar(length)?.to_int(off_t.size)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(result, dest)?; } "fsync" => { - let [fd] = this.check_shim(abi, Conv::C, link_name, args)?; + let [fd] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.tcx.types.i32], + this.tcx.types.i32, + args, + )?; let result = this.fsync(fd)?; this.write_scalar(result, dest)?; } "fdatasync" => { - let [fd] = this.check_shim(abi, Conv::C, link_name, args)?; + let [fd] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.tcx.types.i32], + this.tcx.types.i32, + args, + )?; let result = this.fdatasync(fd)?; this.write_scalar(result, dest)?; } "readlink" => { - let [pathname, buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?; + let [pathname, buf, bufsize] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [ + this.machine.layouts.const_raw_ptr.ty, + this.machine.layouts.mut_raw_ptr.ty, + this.tcx.types.usize, + ], + this.tcx.types.isize, + args, + )?; let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_target_isize(result, this), dest)?; } "posix_fadvise" => { - let [fd, offset, len, advice] = this.check_shim(abi, Conv::C, link_name, args)?; + let off_t = this.libc_ty_layout("off_t"); + let [fd, offset, len, advice] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.tcx.types.i32, off_t.ty, off_t.ty, this.tcx.types.i32], + this.tcx.types.i32, + args, + )?; this.read_scalar(fd)?.to_i32()?; - this.read_target_isize(offset)?; - this.read_target_isize(len)?; + this.read_scalar(offset)?.to_int(off_t.size)?; + this.read_scalar(len)?.to_int(off_t.size)?; this.read_scalar(advice)?.to_i32()?; // fadvise is only informational, we can ignore it. this.write_null(dest)?; } "realpath" => { - let [path, resolved_path] = this.check_shim(abi, Conv::C, link_name, args)?; + let [path, resolved_path] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.mut_raw_ptr.ty], + this.machine.layouts.mut_raw_ptr.ty, + args, + )?; let result = this.realpath(path, resolved_path)?; this.write_scalar(result, dest)?; } "mkstemp" => { - let [template] = this.check_shim(abi, Conv::C, link_name, args)?; + let [template] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.machine.layouts.mut_raw_ptr.ty], + this.tcx.types.i32, + args, + )?; let result = this.mkstemp(template)?; this.write_scalar(result, dest)?; } // Unnamed sockets and pipes "socketpair" => { - let [domain, type_, protocol, sv] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [domain, type_, protocol, sv] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [ + this.tcx.types.i32, + this.tcx.types.i32, + this.tcx.types.i32, + this.machine.layouts.mut_raw_ptr.ty, + ], + this.tcx.types.i32, + args, + )?; let result = this.socketpair(domain, type_, protocol, sv)?; this.write_scalar(result, dest)?; } "pipe" => { - let [pipefd] = this.check_shim(abi, Conv::C, link_name, args)?; + let [pipefd] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.machine.layouts.mut_raw_ptr.ty], + this.tcx.types.i32, + args, + )?; let result = this.pipe2(pipefd, /*flags*/ None)?; this.write_scalar(result, dest)?; } "pipe2" => { // Currently this function does not exist on all Unixes, e.g. on macOS. this.check_target_os(&["linux", "freebsd", "solaris", "illumos"], link_name)?; - let [pipefd, flags] = this.check_shim(abi, Conv::C, link_name, args)?; + let [pipefd, flags] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.machine.layouts.mut_raw_ptr.ty, this.tcx.types.i32], + this.tcx.types.i32, + args, + )?; let result = this.pipe2(pipefd, Some(flags))?; this.write_scalar(result, dest)?; } // Time "gettimeofday" => { - let [tv, tz] = this.check_shim(abi, Conv::C, link_name, args)?; + let [tv, tz] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.machine.layouts.mut_raw_ptr.ty, this.machine.layouts.mut_raw_ptr.ty], + this.tcx.types.i32, + args, + )?; let result = this.gettimeofday(tv, tz)?; this.write_scalar(result, dest)?; } "localtime_r" => { - let [timep, result_op] = this.check_shim(abi, Conv::C, link_name, args)?; + let [timep, result_op] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.mut_raw_ptr.ty], + this.machine.layouts.mut_raw_ptr.ty, + args, + )?; let result = this.localtime_r(timep, result_op)?; this.write_pointer(result, dest)?; } "clock_gettime" => { - let [clk_id, tp] = this.check_shim(abi, Conv::C, link_name, args)?; - let result = this.clock_gettime(clk_id, tp)?; - this.write_scalar(result, dest)?; + let [clk_id, tp] = this.check_shim_abi( + link_name, + abi, + ExternAbi::C { unwind: false }, + [this.libc_ty_layout("clockid_t").ty, this.machine.layouts.mut_raw_ptr.ty], + this.tcx.types.i32, + args, + )?; + this.clock_gettime(clk_id, tp, dest)?; } // Allocation @@ -834,7 +1147,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame_in_std() => { let [_attr, guard_size] = this.check_shim(abi, Conv::C, link_name, args)?; - let guard_size_layout = this.libc_ty_layout("size_t"); + let guard_size_layout = this.machine.layouts.usize; let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?; this.write_scalar( Scalar::from_uint(this.machine.page_size, guard_size_layout.size), diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index fc0f57694a7..1f6acff0787 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -502,7 +502,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(Scalar::from_i32(this.try_unwrap_io_result(fd)?)) } - fn lseek64(&mut self, fd_num: i32, offset: i128, whence: i32) -> InterpResult<'tcx, Scalar> { + fn lseek64( + &mut self, + fd_num: i32, + offset: i128, + whence: i32, + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescription` trait. @@ -510,7 +516,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let seek_from = if whence == this.eval_libc_i32("SEEK_SET") { if offset < 0 { // Negative offsets return `EINVAL`. - return this.set_last_error_and_return_i64(LibcError("EINVAL")); + return this.set_last_error_and_return(LibcError("EINVAL"), dest); } else { SeekFrom::Start(u64::try_from(offset).unwrap()) } @@ -519,19 +525,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } else if whence == this.eval_libc_i32("SEEK_END") { SeekFrom::End(i64::try_from(offset).unwrap()) } else { - return this.set_last_error_and_return_i64(LibcError("EINVAL")); + return this.set_last_error_and_return(LibcError("EINVAL"), dest); }; let communicate = this.machine.communicate(); let Some(fd) = this.machine.fds.get(fd_num) else { - return this.set_last_error_and_return_i64(LibcError("EBADF")); + return this.set_last_error_and_return(LibcError("EBADF"), dest); }; let result = fd.seek(communicate, seek_from)?.map(|offset| i64::try_from(offset).unwrap()); drop(fd); let result = this.try_unwrap_io_result(result)?; - interp_ok(Scalar::from_i64(result)) + this.write_int(result, dest)?; + interp_ok(()) } fn unlink(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index 8dcadbed130..c80858c6363 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -317,6 +317,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let res = this.GetFileInformationByHandle(handle, info)?; this.write_scalar(res, dest)?; } + "DeleteFileW" => { + let [file_name] = this.check_shim(abi, sys_conv, link_name, args)?; + let res = this.DeleteFileW(file_name)?; + this.write_scalar(res, dest)?; + } // Allocation "HeapAlloc" => { diff --git a/src/tools/miri/src/shims/windows/fs.rs b/src/tools/miri/src/shims/windows/fs.rs index 32bab548969..7561bf45219 100644 --- a/src/tools/miri/src/shims/windows/fs.rs +++ b/src/tools/miri/src/shims/windows/fs.rs @@ -371,6 +371,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(this.eval_windows("c", "TRUE")) } + + fn DeleteFileW( + &mut self, + file_name: &OpTy<'tcx>, // LPCWSTR + ) -> InterpResult<'tcx, Scalar> { + // ^ Returns BOOL (i32 on Windows) + let this = self.eval_context_mut(); + this.assert_target_os("windows", "DeleteFileW"); + this.check_no_isolation("`DeleteFileW`")?; + + let file_name = this.read_path_from_wide_str(this.read_pointer(file_name)?)?; + match std::fs::remove_file(file_name) { + Ok(_) => interp_ok(this.eval_windows("c", "TRUE")), + Err(e) => { + this.set_last_error(e)?; + interp_ok(this.eval_windows("c", "FALSE")) + } + } + } } /// Windows FILETIME is measured in 100-nanosecs since 1601 diff --git a/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs b/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs index f73c1b6acb7..3da54b91882 100644 --- a/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs +++ b/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs @@ -1,13 +1,8 @@ -#![feature(intrinsics)] - -mod rusti { - #[rustc_intrinsic] - pub unsafe fn ctlz_nonzero<T>(x: T) -> u32; -} +#![feature(core_intrinsics)] pub fn main() { unsafe { - use crate::rusti::*; + use std::intrinsics::*; ctlz_nonzero(0u8); //~ ERROR: `ctlz_nonzero` called on 0 } diff --git a/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs b/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs index a41cb8b1553..2b68f6713d8 100644 --- a/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs +++ b/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs @@ -1,13 +1,8 @@ -#![feature(intrinsics)] - -mod rusti { - #[rustc_intrinsic] - pub unsafe fn cttz_nonzero<T>(x: T) -> u32; -} +#![feature(core_intrinsics)] pub fn main() { unsafe { - use crate::rusti::*; + use std::intrinsics::*; cttz_nonzero(0u8); //~ ERROR: `cttz_nonzero` called on 0 } diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.rs index 7ee0117ffb3..831a65966ce 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.rs index 22bf881cef0..a7032e97430 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.rs index 571121f4019..e8c98761956 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.rs index 12600ef6125..c8b29cbcfe9 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.rs index f848a137c27..0996d0244e8 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.rs index 43ef4a95738..f28227134d8 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.rs index 83432c2b77c..9e400b4ad40 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.rs index 609443e6d4e..9aca349b918 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.rs index fb3eb11c0bb..54361f6c32c 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.rs index b46c4777ba7..75f52296367 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.rs index 8a3b9dbdc71..20d8fa1ae80 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.rs index e0c826cb046..611a0ade0a5 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.rs index c7c5bf40226..8ff8c3bee00 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.rs index fb3d7bda4e4..1f662e6c32a 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.rs index 2cf27b33553..fad172801ea 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.rs index 22dca505e64..7eb3559527a 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.rs index b59c8fa8e0c..351fc6c6f1c 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.rs index 4ad0cd343a4..a6f73c79710 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.rs index fd47dfc03d7..b01ff3aafc0 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.rs index 680ebda1c96..a573e4e852c 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.rs index e4cb36c5d2e..4fb38c9bc2e 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.rs index fe4bac92bd3..c4c0d3c17f0 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.rs index 219efd80316..de7d2215fd6 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.rs @@ -1,8 +1,6 @@ -#![feature(intrinsics)] - +#![feature(core_intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; +use std::intrinsics::float_to_int_unchecked; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/no_main.stderr b/src/tools/miri/tests/fail/no_main.stderr index e9b9e5d65b1..e7f63be794f 100644 --- a/src/tools/miri/tests/fail/no_main.stderr +++ b/src/tools/miri/tests/fail/no_main.stderr @@ -2,7 +2,7 @@ error: Miri can only run programs that have a main function. Alternatively, you can export a `miri_start` function: #[cfg(miri)] - #[no_mangle] + #[unsafe(no_mangle)] fn miri_start(argc: isize, argv: *const *const u8) -> isize { // Call the actual start function that your project implements, based on your target's conventions. } diff --git a/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.rs b/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.rs index 515e467fb54..ac6e221fcd8 100644 --- a/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.rs +++ b/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.rs @@ -9,6 +9,6 @@ extern "C" { fn main() { let mut fds = [-1, -1]; let res = unsafe { pipe(fds.as_mut_ptr()) }; - //~^ ERROR: calling a non-variadic function with a variadic caller-side signature + //~^ ERROR: ABI mismatch: calling a non-variadic function with a variadic caller-side signature assert_eq!(res, 0); } diff --git a/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.stderr b/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.stderr index 2782f3b3269..0f642aca322 100644 --- a/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.stderr +++ b/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: calling a non-variadic function with a variadic caller-side signature +error: Undefined Behavior: ABI mismatch: calling a non-variadic function with a variadic caller-side signature --> tests/fail/shims/vararg_caller_signature_mismatch.rs:LL:CC | LL | let res = unsafe { pipe(fds.as_mut_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^ calling a non-variadic function with a variadic caller-side signature + | ^^^^^^^^^^^^^^^^^^^^^^ ABI mismatch: calling a non-variadic function with a variadic caller-side signature | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs index a015464dbde..698ca4e0b4b 100644 --- a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs +++ b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs @@ -2,6 +2,7 @@ //@compile-flags: -Zmiri-disable-isolation #![allow(nonstandard_style)] +use std::io::ErrorKind; use std::os::windows::ffi::OsStrExt; use std::path::Path; use std::ptr; @@ -15,10 +16,10 @@ use windows_sys::Win32::Foundation::{ STATUS_IO_DEVICE_ERROR, }; use windows_sys::Win32::Storage::FileSystem::{ - BY_HANDLE_FILE_INFORMATION, CREATE_ALWAYS, CREATE_NEW, CreateFileW, FILE_ATTRIBUTE_DIRECTORY, - FILE_ATTRIBUTE_NORMAL, FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, - FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, GetFileInformationByHandle, OPEN_ALWAYS, - OPEN_EXISTING, + BY_HANDLE_FILE_INFORMATION, CREATE_ALWAYS, CREATE_NEW, CreateFileW, DeleteFileW, + FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_NORMAL, FILE_FLAG_BACKUP_SEMANTICS, + FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, + GetFileInformationByHandle, OPEN_ALWAYS, OPEN_EXISTING, }; fn main() { @@ -28,6 +29,7 @@ fn main() { test_create_always_twice(); test_open_always_twice(); test_open_dir_reparse(); + test_delete_file(); test_ntstatus_to_dos(); } } @@ -194,6 +196,21 @@ unsafe fn test_open_dir_reparse() { }; } +unsafe fn test_delete_file() { + let temp = utils::tmp().join("test_delete_file.txt"); + let raw_path = to_wide_cstr(&temp); + let _ = std::fs::File::create(&temp).unwrap(); + + if DeleteFileW(raw_path.as_ptr()) == 0 { + panic!("Failed to delete file"); + } + + match std::fs::File::open(temp) { + Ok(_) => panic!("File not deleted"), + Err(e) => assert!(e.kind() == ErrorKind::NotFound, "File not deleted"), + } +} + unsafe fn test_ntstatus_to_dos() { // We won't test all combinations, just a couple common ones assert_eq!(RtlNtStatusToDosError(STATUS_IO_DEVICE_ERROR), ERROR_IO_DEVICE); diff --git a/src/tools/miri/tests/pass/async-drop.rs b/src/tools/miri/tests/pass/async-drop.rs index 6d556b77795..4fa84384d9b 100644 --- a/src/tools/miri/tests/pass/async-drop.rs +++ b/src/tools/miri/tests/pass/async-drop.rs @@ -4,7 +4,7 @@ // WARNING: If you would ever want to modify this test, // please consider modifying rustc's async drop test at -// `tests/ui/async-await/async-drop.rs`. +// `tests/ui/async-await/async-drop/async-drop-initial.rs`. #![feature(async_drop, impl_trait_in_assoc_type)] #![allow(incomplete_features, dead_code)] @@ -68,7 +68,8 @@ fn main() { test_async_drop(SyncThenAsync { i: 15, a: AsyncInt(16), b: SyncInt(17), c: AsyncInt(18) }) .await; - let async_drop_fut = pin!(core::future::async_drop(AsyncInt(19))); + let mut ptr19 = mem::MaybeUninit::new(AsyncInt(19)); + let async_drop_fut = pin!(unsafe { async_drop_in_place(ptr19.as_mut_ptr()) }); test_idempotency(async_drop_fut).await; let foo = AsyncInt(20); @@ -89,13 +90,14 @@ fn main() { struct AsyncInt(i32); +impl Drop for AsyncInt { + fn drop(&mut self) { + println!("AsyncInt::drop: {}", self.0); + } +} impl AsyncDrop for AsyncInt { - type Dropper<'a> = impl Future<Output = ()>; - - fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { - async move { - println!("AsyncInt::Dropper::poll: {}", self.0); - } + async fn drop(self: Pin<&mut Self>) { + println!("AsyncInt::async_drop: {}", self.0); } } @@ -124,16 +126,14 @@ struct AsyncReference<'a> { foo: &'a AsyncInt, } +impl Drop for AsyncReference<'_> { + fn drop(&mut self) { + println!("AsyncReference::drop: {}", self.foo.0); + } +} impl AsyncDrop for AsyncReference<'_> { - type Dropper<'a> - = impl Future<Output = ()> - where - Self: 'a; - - fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { - async move { - println!("AsyncReference::Dropper::poll: {}", self.foo.0); - } + async fn drop(self: Pin<&mut Self>) { + println!("AsyncReference::async_drop: {}", self.foo.0); } } @@ -145,13 +145,14 @@ struct AsyncStruct { b: AsyncInt, } +impl Drop for AsyncStruct { + fn drop(&mut self) { + println!("AsyncStruct::drop: {}", self.i); + } +} impl AsyncDrop for AsyncStruct { - type Dropper<'a> = impl Future<Output = ()>; - - fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { - async move { - println!("AsyncStruct::Dropper::poll: {}", self.i); - } + async fn drop(self: Pin<&mut Self>) { + println!("AsyncStruct::async_drop: {}", self.i); } } @@ -160,23 +161,34 @@ enum AsyncEnum { B(SyncInt), } +impl Drop for AsyncEnum { + fn drop(&mut self) { + let new_self = match self { + AsyncEnum::A(foo) => { + println!("AsyncEnum(A)::drop: {}", foo.0); + AsyncEnum::B(SyncInt(foo.0)) + } + AsyncEnum::B(foo) => { + println!("AsyncEnum(B)::drop: {}", foo.0); + AsyncEnum::A(AsyncInt(foo.0)) + } + }; + mem::forget(mem::replace(&mut *self, new_self)); + } +} impl AsyncDrop for AsyncEnum { - type Dropper<'a> = impl Future<Output = ()>; - - fn async_drop(mut self: Pin<&mut Self>) -> Self::Dropper<'_> { - async move { - let new_self = match &*self { - AsyncEnum::A(foo) => { - println!("AsyncEnum(A)::Dropper::poll: {}", foo.0); - AsyncEnum::B(SyncInt(foo.0)) - } - AsyncEnum::B(foo) => { - println!("AsyncEnum(B)::Dropper::poll: {}", foo.0); - AsyncEnum::A(AsyncInt(foo.0)) - } - }; - mem::forget(mem::replace(&mut *self, new_self)); - } + async fn drop(mut self: Pin<&mut Self>) { + let new_self = match &*self { + AsyncEnum::A(foo) => { + println!("AsyncEnum(A)::async_drop: {}", foo.0); + AsyncEnum::B(SyncInt(foo.0)) + } + AsyncEnum::B(foo) => { + println!("AsyncEnum(B)::async_drop: {}", foo.0); + AsyncEnum::A(AsyncInt(foo.0)) + } + }; + mem::forget(mem::replace(&mut *self, new_self)); } } @@ -186,14 +198,15 @@ union AsyncUnion { unsigned: u32, } +impl Drop for AsyncUnion { + fn drop(&mut self) { + println!("AsyncUnion::drop: {}, {}", unsafe { self.signed }, unsafe { self.unsigned },); + } +} impl AsyncDrop for AsyncUnion { - type Dropper<'a> = impl Future<Output = ()>; - - fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_> { - async move { - println!("AsyncUnion::Dropper::poll: {}, {}", unsafe { self.signed }, unsafe { - self.unsigned - }); - } + async fn drop(self: Pin<&mut Self>) { + println!("AsyncUnion::async_drop: {}, {}", unsafe { self.signed }, unsafe { + self.unsigned + }); } } diff --git a/src/tools/miri/tests/pass/async-drop.stack.stdout b/src/tools/miri/tests/pass/async-drop.stack.stdout index 9cae4331caf..fc53df2f1b4 100644 --- a/src/tools/miri/tests/pass/async-drop.stack.stdout +++ b/src/tools/miri/tests/pass/async-drop.stack.stdout @@ -1,22 +1,23 @@ -AsyncInt::Dropper::poll: 0 -AsyncInt::Dropper::poll: 1 -AsyncInt::Dropper::poll: 2 -AsyncInt::Dropper::poll: 3 -AsyncInt::Dropper::poll: 4 -AsyncStruct::Dropper::poll: 6 -AsyncInt::Dropper::poll: 7 -AsyncInt::Dropper::poll: 8 -AsyncReference::Dropper::poll: 10 -AsyncInt::Dropper::poll: 11 -AsyncEnum(A)::Dropper::poll: 12 +AsyncInt::async_drop: 0 +AsyncInt::async_drop: 1 +AsyncInt::async_drop: 2 +AsyncInt::async_drop: 3 +AsyncInt::async_drop: 4 +AsyncStruct::async_drop: 6 +AsyncInt::async_drop: 7 +AsyncInt::async_drop: 8 +AsyncReference::async_drop: 10 +AsyncInt::async_drop: 11 +AsyncEnum(A)::async_drop: 12 SyncInt::drop: 12 -AsyncEnum(B)::Dropper::poll: 13 -AsyncInt::Dropper::poll: 13 +AsyncEnum(B)::async_drop: 13 +AsyncInt::async_drop: 13 SyncInt::drop: 14 SyncThenAsync::drop: 15 -AsyncInt::Dropper::poll: 16 +AsyncInt::async_drop: 16 SyncInt::drop: 17 -AsyncInt::Dropper::poll: 18 -AsyncInt::Dropper::poll: 19 -AsyncInt::Dropper::poll: 20 -AsyncUnion::Dropper::poll: 21, 21 +AsyncInt::async_drop: 18 +AsyncInt::async_drop: 19 +AsyncInt::async_drop: 20 +AsyncUnion::async_drop: 21, 21 +AsyncInt::async_drop: 10 diff --git a/src/tools/miri/tests/pass/async-drop.tree.stdout b/src/tools/miri/tests/pass/async-drop.tree.stdout index 9cae4331caf..fc53df2f1b4 100644 --- a/src/tools/miri/tests/pass/async-drop.tree.stdout +++ b/src/tools/miri/tests/pass/async-drop.tree.stdout @@ -1,22 +1,23 @@ -AsyncInt::Dropper::poll: 0 -AsyncInt::Dropper::poll: 1 -AsyncInt::Dropper::poll: 2 -AsyncInt::Dropper::poll: 3 -AsyncInt::Dropper::poll: 4 -AsyncStruct::Dropper::poll: 6 -AsyncInt::Dropper::poll: 7 -AsyncInt::Dropper::poll: 8 -AsyncReference::Dropper::poll: 10 -AsyncInt::Dropper::poll: 11 -AsyncEnum(A)::Dropper::poll: 12 +AsyncInt::async_drop: 0 +AsyncInt::async_drop: 1 +AsyncInt::async_drop: 2 +AsyncInt::async_drop: 3 +AsyncInt::async_drop: 4 +AsyncStruct::async_drop: 6 +AsyncInt::async_drop: 7 +AsyncInt::async_drop: 8 +AsyncReference::async_drop: 10 +AsyncInt::async_drop: 11 +AsyncEnum(A)::async_drop: 12 SyncInt::drop: 12 -AsyncEnum(B)::Dropper::poll: 13 -AsyncInt::Dropper::poll: 13 +AsyncEnum(B)::async_drop: 13 +AsyncInt::async_drop: 13 SyncInt::drop: 14 SyncThenAsync::drop: 15 -AsyncInt::Dropper::poll: 16 +AsyncInt::async_drop: 16 SyncInt::drop: 17 -AsyncInt::Dropper::poll: 18 -AsyncInt::Dropper::poll: 19 -AsyncInt::Dropper::poll: 20 -AsyncUnion::Dropper::poll: 21, 21 +AsyncInt::async_drop: 18 +AsyncInt::async_drop: 19 +AsyncInt::async_drop: 20 +AsyncUnion::async_drop: 21, 21 +AsyncInt::async_drop: 10 diff --git a/src/tools/miri/tests/pass/dst-raw.rs b/src/tools/miri/tests/pass/dst-raw.rs index f26191a1d59..3d0b843b3da 100644 --- a/src/tools/miri/tests/pass/dst-raw.rs +++ b/src/tools/miri/tests/pass/dst-raw.rs @@ -1,5 +1,7 @@ // Test DST raw pointers +#![allow(dangerous_implicit_autorefs)] + trait Trait { fn foo(&self) -> isize; } diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 575d70579a4..98a88cfd62d 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -1292,8 +1292,7 @@ fn test_non_determinism() { } } // We saw the same thing N times. - // FIXME: temporarily disabled as it breaks std tests. - //panic!("expected non-determinism, got {rounds} times the same result: {first:?}"); + panic!("expected non-determinism, got {rounds} times the same result: {first:?}"); } macro_rules! test_operations_f { @@ -1319,66 +1318,68 @@ fn test_non_determinism() { } pub fn test_operations_f32(a: f32, b: f32) { test_operations_f!(a, b); - ensure_nondet(|| a.log(b)); - ensure_nondet(|| a.exp()); - ensure_nondet(|| 10f32.exp2()); - ensure_nondet(|| f32::consts::E.ln()); - ensure_nondet(|| 1f32.ln_1p()); - ensure_nondet(|| 10f32.log10()); - ensure_nondet(|| 8f32.log2()); - ensure_nondet(|| 27.0f32.cbrt()); - ensure_nondet(|| 3.0f32.hypot(4.0f32)); - ensure_nondet(|| 1f32.sin()); - ensure_nondet(|| 0f32.cos()); - // On i686-pc-windows-msvc , these functions are implemented by calling the `f64` version, - // which means the little rounding errors Miri introduces are discard by the cast down to `f32`. - // Just skip the test for them. - if !cfg!(all(target_os = "windows", target_env = "msvc", target_arch = "x86")) { - ensure_nondet(|| 1.0f32.tan()); - ensure_nondet(|| 1.0f32.asin()); - ensure_nondet(|| 5.0f32.acos()); - ensure_nondet(|| 1.0f32.atan()); - ensure_nondet(|| 1.0f32.atan2(2.0f32)); - ensure_nondet(|| 1.0f32.sinh()); - ensure_nondet(|| 1.0f32.cosh()); - ensure_nondet(|| 1.0f32.tanh()); - } - ensure_nondet(|| 1.0f32.asinh()); - ensure_nondet(|| 2.0f32.acosh()); - ensure_nondet(|| 0.5f32.atanh()); - ensure_nondet(|| 5.0f32.gamma()); - ensure_nondet(|| 5.0f32.ln_gamma()); - ensure_nondet(|| 5.0f32.erf()); - ensure_nondet(|| 5.0f32.erfc()); + // FIXME: temporarily disabled as it breaks std tests. + // ensure_nondet(|| a.log(b)); + // ensure_nondet(|| a.exp()); + // ensure_nondet(|| 10f32.exp2()); + // ensure_nondet(|| f32::consts::E.ln()); + // ensure_nondet(|| 1f32.ln_1p()); + // ensure_nondet(|| 10f32.log10()); + // ensure_nondet(|| 8f32.log2()); + // ensure_nondet(|| 27.0f32.cbrt()); + // ensure_nondet(|| 3.0f32.hypot(4.0f32)); + // ensure_nondet(|| 1f32.sin()); + // ensure_nondet(|| 0f32.cos()); + // // On i686-pc-windows-msvc , these functions are implemented by calling the `f64` version, + // // which means the little rounding errors Miri introduces are discard by the cast down to `f32`. + // // Just skip the test for them. + // if !cfg!(all(target_os = "windows", target_env = "msvc", target_arch = "x86")) { + // ensure_nondet(|| 1.0f32.tan()); + // ensure_nondet(|| 1.0f32.asin()); + // ensure_nondet(|| 5.0f32.acos()); + // ensure_nondet(|| 1.0f32.atan()); + // ensure_nondet(|| 1.0f32.atan2(2.0f32)); + // ensure_nondet(|| 1.0f32.sinh()); + // ensure_nondet(|| 1.0f32.cosh()); + // ensure_nondet(|| 1.0f32.tanh()); + // } + // ensure_nondet(|| 1.0f32.asinh()); + // ensure_nondet(|| 2.0f32.acosh()); + // ensure_nondet(|| 0.5f32.atanh()); + // ensure_nondet(|| 5.0f32.gamma()); + // ensure_nondet(|| 5.0f32.ln_gamma()); + // ensure_nondet(|| 5.0f32.erf()); + // ensure_nondet(|| 5.0f32.erfc()); } pub fn test_operations_f64(a: f64, b: f64) { test_operations_f!(a, b); - ensure_nondet(|| a.log(b)); - ensure_nondet(|| a.exp()); - ensure_nondet(|| 50f64.exp2()); - ensure_nondet(|| 3f64.ln()); - ensure_nondet(|| 1f64.ln_1p()); - ensure_nondet(|| f64::consts::E.log10()); - ensure_nondet(|| f64::consts::E.log2()); - ensure_nondet(|| 27.0f64.cbrt()); - ensure_nondet(|| 3.0f64.hypot(4.0f64)); - ensure_nondet(|| 1f64.sin()); - ensure_nondet(|| 0f64.cos()); - ensure_nondet(|| 1.0f64.tan()); - ensure_nondet(|| 1.0f64.asin()); - ensure_nondet(|| 5.0f64.acos()); - ensure_nondet(|| 1.0f64.atan()); - ensure_nondet(|| 1.0f64.atan2(2.0f64)); - ensure_nondet(|| 1.0f64.sinh()); - ensure_nondet(|| 1.0f64.cosh()); - ensure_nondet(|| 1.0f64.tanh()); - ensure_nondet(|| 1.0f64.asinh()); - ensure_nondet(|| 3.0f64.acosh()); - ensure_nondet(|| 0.5f64.atanh()); - ensure_nondet(|| 5.0f64.gamma()); - ensure_nondet(|| 5.0f64.ln_gamma()); - ensure_nondet(|| 5.0f64.erf()); - ensure_nondet(|| 5.0f64.erfc()); + // FIXME: temporarily disabled as it breaks std tests. + // ensure_nondet(|| a.log(b)); + // ensure_nondet(|| a.exp()); + // ensure_nondet(|| 50f64.exp2()); + // ensure_nondet(|| 3f64.ln()); + // ensure_nondet(|| 1f64.ln_1p()); + // ensure_nondet(|| f64::consts::E.log10()); + // ensure_nondet(|| f64::consts::E.log2()); + // ensure_nondet(|| 27.0f64.cbrt()); + // ensure_nondet(|| 3.0f64.hypot(4.0f64)); + // ensure_nondet(|| 1f64.sin()); + // ensure_nondet(|| 0f64.cos()); + // ensure_nondet(|| 1.0f64.tan()); + // ensure_nondet(|| 1.0f64.asin()); + // ensure_nondet(|| 5.0f64.acos()); + // ensure_nondet(|| 1.0f64.atan()); + // ensure_nondet(|| 1.0f64.atan2(2.0f64)); + // ensure_nondet(|| 1.0f64.sinh()); + // ensure_nondet(|| 1.0f64.cosh()); + // ensure_nondet(|| 1.0f64.tanh()); + // ensure_nondet(|| 1.0f64.asinh()); + // ensure_nondet(|| 3.0f64.acosh()); + // ensure_nondet(|| 0.5f64.atanh()); + // ensure_nondet(|| 5.0f64.gamma()); + // ensure_nondet(|| 5.0f64.ln_gamma()); + // ensure_nondet(|| 5.0f64.erf()); + // ensure_nondet(|| 5.0f64.erfc()); } pub fn test_operations_f128(a: f128, b: f128) { test_operations_f!(a, b); diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 6ad23055f30..d0a7f245ee0 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -17,10 +17,10 @@ mod utils; fn main() { test_path_conversion(); + test_file_create_new(); // Windows file handling is very incomplete. if cfg!(not(windows)) { test_file(); - test_file_create_new(); test_seek(); test_file_clone(); test_metadata(); diff --git a/src/tools/miri/tests/pass/slices.rs b/src/tools/miri/tests/pass/slices.rs index dd18a061cdd..686683c3a25 100644 --- a/src/tools/miri/tests/pass/slices.rs +++ b/src/tools/miri/tests/pass/slices.rs @@ -1,7 +1,6 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance -#![feature(slice_as_chunks)] #![feature(slice_partition_dedup)] #![feature(layout_for_ptr)] @@ -227,7 +226,7 @@ fn test_for_invalidated_pointers() { buffer.reverse(); - // Calls `fn as_chunks_unchecked_mut` internally (requires unstable `#![feature(slice_as_chunks)]`): + // Calls `fn as_chunks_unchecked_mut` internally: assert_eq!(2, buffer.as_chunks_mut::<32>().0.len()); for chunk in buffer.as_chunks_mut::<32>().0 { for elem in chunk { diff --git a/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs b/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs index 830e9c33847..e86cb3711ac 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs +++ b/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs @@ -1,3 +1,5 @@ +#![allow(dangerous_implicit_autorefs)] + use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell}; use std::mem::{self, MaybeUninit}; diff --git a/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs b/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs new file mode 100644 index 00000000000..6dde593d2cf --- /dev/null +++ b/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs @@ -0,0 +1,178 @@ +//@revisions: default uniq +//@compile-flags: -Zmiri-tree-borrows +//@[uniq]compile-flags: -Zmiri-unique-is-unique +#![allow(dangerous_implicit_autorefs)] +use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell}; +use std::mem::{self, MaybeUninit}; + +fn main() { + aliasing_mut_and_shr(); + aliasing_frz_and_shr(); + into_interior_mutability(); + unsafe_cell_2phase(); + unsafe_cell_deallocate(); + unsafe_cell_invalidate(); + refcell_basic(); + ref_protector(); + ref_mut_protector(); + rust_issue_68303(); +} + +fn aliasing_mut_and_shr() { + fn inner(rc: &RefCell<i32>, aliasing: &mut i32) { + *aliasing += 4; + let _escape_to_raw = rc as *const _; + *aliasing += 4; + let _shr = &*rc; + *aliasing += 4; + // also turning this into a frozen ref now must work + let aliasing = &*aliasing; + let _val = *aliasing; + let _escape_to_raw = rc as *const _; // this must NOT unfreeze + let _val = *aliasing; + let _shr = &*rc; // this must NOT unfreeze + let _val = *aliasing; + } + + let rc = RefCell::new(23); + let mut bmut = rc.borrow_mut(); + inner(&rc, &mut *bmut); + drop(bmut); + assert_eq!(*rc.borrow(), 23 + 12); +} + +fn aliasing_frz_and_shr() { + fn inner(rc: &RefCell<i32>, aliasing: &i32) { + let _val = *aliasing; + let _escape_to_raw = rc as *const _; // this must NOT unfreeze + let _val = *aliasing; + let _shr = &*rc; // this must NOT unfreeze + let _val = *aliasing; + } + + let rc = RefCell::new(23); + let bshr = rc.borrow(); + inner(&rc, &*bshr); + assert_eq!(*rc.borrow(), 23); +} + +// Getting a pointer into a union with interior mutability used to be tricky +// business (https://github.com/rust-lang/miri/issues/615), but it should work +// now. +fn into_interior_mutability() { + let mut x: MaybeUninit<(Cell<u32>, u32)> = MaybeUninit::uninit(); + x.as_ptr(); + x.write((Cell::new(0), 1)); + let ptr = unsafe { x.assume_init_ref() }; + assert_eq!(ptr.1, 1); +} + +// Two-phase borrows of the pointer returned by UnsafeCell::get() should not +// invalidate aliases. +fn unsafe_cell_2phase() { + unsafe { + let x = &UnsafeCell::new(vec![]); + let x2 = &*x; + (*x.get()).push(0); + let _val = (*x2.get()).get(0); + } +} + +/// Make sure we can deallocate an UnsafeCell that was passed to an active fn call. +/// (This is the fix for https://github.com/rust-lang/rust/issues/55005.) +fn unsafe_cell_deallocate() { + fn f(x: &UnsafeCell<i32>) { + let b: Box<i32> = unsafe { Box::from_raw(x as *const _ as *mut i32) }; + drop(b) + } + + let b = Box::new(0i32); + f(unsafe { mem::transmute(Box::into_raw(b)) }); +} + +/// As a side-effect of the above, we also allow this -- at least for now. +fn unsafe_cell_invalidate() { + fn f(_x: &UnsafeCell<i32>, y: *mut i32) { + // Writing to y invalidates x, but that is okay. + unsafe { + *y += 1; + } + } + + let mut x = 0i32; + let raw1 = &mut x as *mut _; + let ref1 = unsafe { &mut *raw1 }; + let raw2 = ref1 as *mut _; + // Now the borrow stack is: raw1, ref2, raw2. + // So using raw1 invalidates raw2. + f(unsafe { mem::transmute(raw2) }, raw1); +} + +fn refcell_basic() { + let c = RefCell::new(42); + { + let s1 = c.borrow(); + let _x: i32 = *s1; + let s2 = c.borrow(); + let _x: i32 = *s1; + let _y: i32 = *s2; + let _x: i32 = *s1; + let _y: i32 = *s2; + } + { + let mut m = c.borrow_mut(); + let _z: i32 = *m; + { + let s: &i32 = &*m; + let _x = *s; + } + *m = 23; + let _z: i32 = *m; + } + { + let s1 = c.borrow(); + let _x: i32 = *s1; + let s2 = c.borrow(); + let _x: i32 = *s1; + let _y: i32 = *s2; + let _x: i32 = *s1; + let _y: i32 = *s2; + } +} + +// Adding a Stacked Borrows protector for `Ref` would break this +fn ref_protector() { + fn break_it(rc: &RefCell<i32>, r: Ref<'_, i32>) { + // `r` has a shared reference, it is passed in as argument and hence + // a protector is added that marks this memory as read-only for the entire + // duration of this function. + drop(r); + // *oops* here we can mutate that memory. + *rc.borrow_mut() = 2; + } + + let rc = RefCell::new(0); + break_it(&rc, rc.borrow()) +} + +fn ref_mut_protector() { + fn break_it(rc: &RefCell<i32>, r: RefMut<'_, i32>) { + // `r` has a shared reference, it is passed in as argument and hence + // a protector is added that marks this memory as inaccessible for the entire + // duration of this function + drop(r); + // *oops* here we can mutate that memory. + *rc.borrow_mut() = 2; + } + + let rc = RefCell::new(0); + break_it(&rc, rc.borrow_mut()) +} + +/// Make sure we do not have bad enum layout optimizations. +fn rust_issue_68303() { + let optional = Some(RefCell::new(false)); + let mut handle = optional.as_ref().unwrap().borrow_mut(); + assert!(optional.is_some()); + *handle = true; +} diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index d257988a57a..8d6c8284e44 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -2039,9 +2039,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "salsa" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4deeb38b4c80ac90a8d4796f83da941b0d76c23783550d15d37eb43ccddcb5bc" +checksum = "6f80d5cf3c3fcab2cef898012f242a670477a1baa609267376af9cb4409026c5" dependencies = [ "boxcar", "crossbeam-queue", @@ -2062,15 +2062,15 @@ dependencies = [ [[package]] name = "salsa-macro-rules" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e6166fa2802d86a77dbcae1bfe75f0ac46fdf952660c233ed64855a53dd603" +checksum = "05303d72606fbf2b9c9523cda2039bb8ecb00304027a3cd7e52b02a65c7d9185" [[package]] name = "salsa-macros" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf358e645a835d9901ee4d812d9812266e046ee92a28d2e37a73b7169a6503b7" +checksum = "eb2f0e2a30c65cb3cd63440c491dde68d9af7e1be2b77832ac7057141107db50" dependencies = [ "heck", "proc-macro2", diff --git a/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs b/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs index 6b81928c91e..357e56ddfaa 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs @@ -159,7 +159,7 @@ impl Parse for Cycle { } impl Parse for Option { - fn parse(input: ParseStream) -> syn::Result<Self> { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { let name = input.parse()?; input.parse::<Token![=]>()?; let value = input.parse()?; diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 09c127f6bcd..90e4d65bf96 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -21079f53a359d9fc82668d4175d49dafdb600563 +6e23095adf9209614a45f7f75fea36dad7b92afb diff --git a/src/tools/rustfmt/src/pairs.rs b/src/tools/rustfmt/src/pairs.rs index 9c51298416b..17ff041d775 100644 --- a/src/tools/rustfmt/src/pairs.rs +++ b/src/tools/rustfmt/src/pairs.rs @@ -1,4 +1,4 @@ -use rustc_ast::ast; +use rustc_ast::{ast, token}; use rustc_span::Span; use crate::config::IndentStyle; @@ -272,13 +272,17 @@ struct PairList<'a, 'b, T: Rewrite> { span: Span, } -fn is_ident(expr: &ast::Expr) -> bool { +fn is_ident_or_bool_lit(expr: &ast::Expr) -> bool { match &expr.kind { ast::ExprKind::Path(None, path) if path.segments.len() == 1 => true, + ast::ExprKind::Lit(token::Lit { + kind: token::LitKind::Bool, + .. + }) => true, ast::ExprKind::Unary(_, expr) | ast::ExprKind::AddrOf(_, _, expr) | ast::ExprKind::Paren(expr) - | ast::ExprKind::Try(expr) => is_ident(expr), + | ast::ExprKind::Try(expr) => is_ident_or_bool_lit(expr), _ => false, } } @@ -296,10 +300,10 @@ impl<'a, 'b> PairList<'a, 'b, ast::Expr> { return false; } - let fist_item_is_ident = is_ident(self.list[0].0); + let fist_item_is_ident_or_bool_lit = is_ident_or_bool_lit(self.list[0].0); let second_item_is_let_chain = matches!(self.list[1].0.kind, ast::ExprKind::Let(..)); - fist_item_is_ident && second_item_is_let_chain + fist_item_is_ident_or_bool_lit && second_item_is_let_chain } } diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 75a5a8532b8..7ec1032dcb4 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -1093,6 +1093,19 @@ impl Rewrite for ast::TyPat { ast::TyPatKind::Range(ref lhs, ref rhs, ref end_kind) => { rewrite_range_pat(context, shape, lhs, rhs, end_kind, self.span) } + ast::TyPatKind::Or(ref variants) => { + let mut first = true; + let mut s = String::new(); + for variant in variants { + if first { + first = false + } else { + s.push_str(" | "); + } + s.push_str(&variant.rewrite_result(context, shape)?); + } + Ok(s) + } ast::TyPatKind::Err(_) => Err(RewriteError::Unknown), } } diff --git a/src/tools/rustfmt/tests/source/let_chains.rs b/src/tools/rustfmt/tests/source/let_chains.rs index b7c1f811096..0c4d8aa85ea 100644 --- a/src/tools/rustfmt/tests/source/let_chains.rs +++ b/src/tools/rustfmt/tests/source/let_chains.rs @@ -20,6 +20,11 @@ fn test_single_line_let_chain() { if a && let Some(b) = foo() { } + // first item in let-chain is a bool literal + if true && let Some(x) = y { + + } + // first item in let-chain is a unary ! with an ident let unary_not = if !from_hir_call && let Some(p) = parent @@ -94,11 +99,6 @@ fn test_multi_line_let_chain() { } - // bool literal - if true && let Some(x) = y { - - } - // cast to a bool if 1 as bool && let Some(x) = y { diff --git a/src/tools/rustfmt/tests/target/let_chains.rs b/src/tools/rustfmt/tests/target/let_chains.rs index 1ceecac8abc..204937b4cac 100644 --- a/src/tools/rustfmt/tests/target/let_chains.rs +++ b/src/tools/rustfmt/tests/target/let_chains.rs @@ -50,6 +50,9 @@ fn test_single_line_let_chain() { // first item in let-chain is an ident if a && let Some(b) = foo() {} + // first item in let-chain is a bool literal + if true && let Some(x) = y {} + // first item in let-chain is a unary ! with an ident let unary_not = if !from_hir_call && let Some(p) = parent {}; @@ -102,11 +105,6 @@ fn test_multi_line_let_chain() { && let Some(x) = y {} - // bool literal - if true - && let Some(x) = y - {} - // cast to a bool if 1 as bool && let Some(x) = y diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index f1ce3ccda04..e6b5aa59622 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -1979,7 +1979,6 @@ ui/issues/issue-27997.rs ui/issues/issue-28105.rs ui/issues/issue-28109.rs ui/issues/issue-28181.rs -ui/issues/issue-2823.rs ui/issues/issue-28279.rs ui/issues/issue-28344.rs ui/issues/issue-28433.rs diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 2e069af23d6..44dd1e50f5b 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -17,7 +17,7 @@ use ignore::Walk; const ENTRY_LIMIT: u32 = 901; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: u32 = 1626; +const ISSUES_ENTRY_LIMIT: u32 = 1624; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files |
