From 316742edb73a81edc231b1c8dc086fae1f3142d9 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Sun, 22 Jan 2023 15:46:53 +0100 Subject: [PATCH 01/37] =?UTF-8?q?io:=20soften=20=E2=80=98at=20most=20one?= =?UTF-8?q?=20write=20attempt=E2=80=99=20requirement=20in=20io::Write::wri?= =?UTF-8?q?te?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the moment, documentation of std::io::Write::write indicates that call to it ‘represents at most one attempt to write to any wrapped object’. It seems that such wording was put there to contrast it with pre-1.0 interface which attempted to write all the data (it has since been changed in [RFC 517]). However, the requirement puts unnecessary constraints and may complicate adaptors which perform non-trivial transformations on the data. For example, they may maintain an internal buffer which needs to be written out before the write method accepts more data. It might be natural to code the method such that it flushes the buffer and then grabs another chunk of user data. With the current wording in the documentation, the adaptor would be forced to return Ok(0). This commit softens the wording such that implementations can choose code structure which makes most sense for their particular use case. While at it, elaborate on the meaning of `Ok(0)` return pointing out that the write_all methods interprets it as an error. [RFC 517]: https://rust-lang.github.io/rfcs/0517-io-os-reform.html --- library/std/src/io/mod.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index de528e85368cb..aa34d4be19242 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1385,17 +1385,18 @@ pub trait Write { /// /// This function will attempt to write the entire contents of `buf`, but /// the entire write might not succeed, or the write may also generate an - /// error. A call to `write` represents *at most one* attempt to write to + /// error. Typically, a call to `write` represents one attempt to write to /// any wrapped object. /// /// Calls to `write` are not guaranteed to block waiting for data to be /// written, and a write which would otherwise block can be indicated through /// an [`Err`] variant. /// - /// If the return value is [`Ok(n)`] then it must be guaranteed that - /// `n <= buf.len()`. A return value of `0` typically means that the - /// underlying object is no longer able to accept bytes and will likely not - /// be able to in the future as well, or that the buffer provided is empty. + /// If the return value is [`Ok(n)`] then it must be guaranteed that `n <= + /// buf.len()`. Unless `input` is empty, this function shouldn’t return `0` + /// since caller may interpret that as an error (the default implementation + /// of [`Write::write_all`] does exactly that). To indicate lack of space + /// function should return [`ErrorKind::StorageFull`] error instead. /// /// # Errors /// From 8654669ed4569216fde2c16edb49d05cd373f038 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Fri, 3 Feb 2023 18:38:51 +0100 Subject: [PATCH 02/37] Update library/std/src/io/mod.rs --- library/std/src/io/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index aa34d4be19242..d4f8c3123b287 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1392,10 +1392,10 @@ pub trait Write { /// written, and a write which would otherwise block can be indicated through /// an [`Err`] variant. /// - /// If the return value is [`Ok(n)`] then it must be guaranteed that `n <= - /// buf.len()`. Unless `input` is empty, this function shouldn’t return `0` - /// since caller may interpret that as an error (the default implementation - /// of [`Write::write_all`] does exactly that). To indicate lack of space + /// If this method consumed `n > 0` bytes of `buf` it must return [`Ok(n)`]. + /// If the return value is `Ok(n)` it must hold than `n <= buf.len()`. + /// Unless `input` is empty, this function shouldn’t return `Ok(0)` since + /// caller may interpret that as an error. To indicate lack of space /// function should return [`ErrorKind::StorageFull`] error instead. /// /// # Errors From 5451dfe6c0c841c0a01d812eebb62e60576dbf89 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Wed, 1 Mar 2023 00:48:22 +0100 Subject: [PATCH 03/37] Update library/std/src/io/mod.rs Co-authored-by: Andrew Gallant --- library/std/src/io/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index d4f8c3123b287..8e8fa147c0d57 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1394,9 +1394,9 @@ pub trait Write { /// /// If this method consumed `n > 0` bytes of `buf` it must return [`Ok(n)`]. /// If the return value is `Ok(n)` it must hold than `n <= buf.len()`. - /// Unless `input` is empty, this function shouldn’t return `Ok(0)` since - /// caller may interpret that as an error. To indicate lack of space - /// function should return [`ErrorKind::StorageFull`] error instead. + /// Unless `buf` is empty, this function shouldn’t return `Ok(0)` since the + /// caller may interpret that as an error. To indicate lack of space, + /// implementors should return [`ErrorKind::StorageFull`] error instead. /// /// # Errors /// From 7d57cd524a33179be58287737b7fd603a9d4a759 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Fri, 3 Mar 2023 03:16:56 +0100 Subject: [PATCH 04/37] Update library/std/src/io/mod.rs Co-authored-by: Jacob Lifshay --- library/std/src/io/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 8e8fa147c0d57..b2fcb966032a1 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1393,7 +1393,7 @@ pub trait Write { /// an [`Err`] variant. /// /// If this method consumed `n > 0` bytes of `buf` it must return [`Ok(n)`]. - /// If the return value is `Ok(n)` it must hold than `n <= buf.len()`. + /// If the return value is `Ok(n)` then `n` must satisfy `n <= buf.len()`. /// Unless `buf` is empty, this function shouldn’t return `Ok(0)` since the /// caller may interpret that as an error. To indicate lack of space, /// implementors should return [`ErrorKind::StorageFull`] error instead. From e99f7ed0713087626c16de542ac24201ac4c356c Mon Sep 17 00:00:00 2001 From: Dan McGregor Date: Tue, 6 Jun 2023 10:15:11 -0600 Subject: [PATCH 05/37] Fix documentation build on FreeBSD After the socket ancillary data implementation was introduced, the build was broken on FreeBSD, add the same workaround as for the existing implementations. --- library/std/src/os/unix/net/ancillary.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs index 7565fbc0d099c..6bd87d61ae188 100644 --- a/library/std/src/os/unix/net/ancillary.rs +++ b/library/std/src/os/unix/net/ancillary.rs @@ -11,7 +11,13 @@ use crate::slice::from_raw_parts; use crate::sys::net::Socket; // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? -#[cfg(all(doc, not(target_os = "linux"), not(target_os = "android"), not(target_os = "netbsd")))] +#[cfg(all( + doc, + not(target_os = "linux"), + not(target_os = "android"), + not(target_os = "netbsd"), + not(target_os = "freebsd") +))] #[allow(non_camel_case_types)] mod libc { pub use libc::c_int; From 8d5e85607d3d52f920990334ae1cfa9798ad9259 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 8 Jun 2023 17:27:34 -0400 Subject: [PATCH 06/37] Allow overwriting the sysroot compile flag via --rustc-args --- src/tools/compiletest/src/runtest.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 6582b534488a8..d16a7d66154b6 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1951,7 +1951,9 @@ impl<'test> TestCx<'test> { rustc.arg("-Ztranslate-remapped-path-to-local-path=no"); // Optionally prevent default --sysroot if specified in test compile-flags. - if !self.props.compile_flags.iter().any(|flag| flag.starts_with("--sysroot")) { + if !self.props.compile_flags.iter().any(|flag| flag.starts_with("--sysroot")) + && !self.config.host_rustcflags.iter().any(|flag| flag == "--sysroot") + { // In stage 0, make sure we use `stage0-sysroot` instead of the bootstrap sysroot. rustc.arg("--sysroot").arg(&self.config.sysroot_base); } From 6d3ff105365318fe41c907c424c6ff2b2ba80dae Mon Sep 17 00:00:00 2001 From: Peter Jaszkowiak Date: Mon, 24 Apr 2023 21:02:36 -0600 Subject: [PATCH 07/37] run `cargo update` weekly - Keep Cargo.lock dependencies current - Presents output from `cargo update` in commit and PR - Edit existing open PR, otherwise open a new one - Skip if existing open PR is S-waiting-on-bors --- .github/workflows/dependencies.yml | 139 +++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 .github/workflows/dependencies.yml diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml new file mode 100644 index 0000000000000..2eccd28e5bb1f --- /dev/null +++ b/.github/workflows/dependencies.yml @@ -0,0 +1,139 @@ +# Automatically run `cargo update` periodically + +--- +name: Bump dependencies in Cargo.lock +on: + schedule: + # Run weekly + - cron: '0 0 * * Sun' + workflow_dispatch: + # Needed so we can run it manually +permissions: + contents: read +defaults: + run: + shell: bash +env: + # So cargo doesn't complain about unstable features + RUSTC_BOOTSTRAP: 1 + PR_TITLE: Weekly `cargo update` + PR_MESSAGE: | + Automation to keep dependencies in `Cargo.lock` current. + + The following is the output from `cargo update`: + COMMIT_MESSAGE: "cargo update \n\n" + +jobs: + not-waiting-on-bors: + name: skip if S-waiting-on-bors + runs-on: ubuntu-latest + steps: + - env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # Fetch state and labels of PR + # Or exit successfully if PR does not exist + JSON=$(gh pr view cargo_update --repo $GITHUB_REPOSITORY --json labels,state || exit 0) + STATE=$(echo "$JSON" | jq -r '.state') + WAITING_ON_BORS=$(echo "$JSON" | jq '.labels[] | any(.name == "S-waiting-on-bors"; .)') + + # Exit with error if open and S-waiting-on-bors + if [[ "$STATE" == "OPEN" && "$WAITING_ON_BORS" == "true" ]]; then + exit 1 + fi + + update: + name: update dependencies + needs: not-waiting-on-bors + runs-on: ubuntu-latest + steps: + - name: checkout the source code + uses: actions/checkout@v3 + with: + submodules: recursive + - name: install the bootstrap toolchain + run: | + # Extract the stage0 version + TOOLCHAIN=$(jq -r '.compiler | {version,date} | join("-")' -- src/stage0.json) + # Install and set as default + rustup toolchain install --no-self-update --profile minimal $TOOLCHAIN + rustup default $TOOLCHAIN + + - name: cargo update + # Remove first line that always just says "Updating crates.io index" + run: cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log + - name: upload Cargo.lock artifact for use in PR + uses: actions/upload-artifact@v3 + with: + name: Cargo-lock + path: Cargo.lock + retention-days: 1 + - name: upload cargo-update log artifact for use in PR + uses: actions/upload-artifact@v3 + with: + name: cargo-updates + path: cargo_update.log + retention-days: 1 + + pr: + name: amend PR + needs: update + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: checkout the source code + uses: actions/checkout@v3 + + - name: download Cargo.lock from update job + uses: actions/download-artifact@v3 + with: + name: Cargo-lock + - name: download cargo-update log from update job + uses: actions/download-artifact@v3 + with: + name: cargo-updates + + - name: craft PR body and commit message + run: | + echo "${COMMIT_MESSAGE}" > commit.txt + cat cargo_update.log >> commit.txt + + echo "${PR_MESSAGE}" > body.md + echo '```txt' >> body.md + cat cargo_update.log >> body.md + echo '```' >> body.md + + - name: commit + run: | + git config user.name github-actions + git config user.email github-actions@github.com + git switch --force-create cargo_update + git add ./Cargo.lock + git commit --no-verify --file=commit.txt + + - name: push + run: git push --no-verify --force --set-upstream origin cargo_update + + - name: edit existing open pull request + id: edit + # Don't fail job if we need to open new PR + continue-on-error: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # Exit with error if PR is closed + STATE=$(gh pr view cargo_update --repo $GITHUB_REPOSITORY --json state --jq '.state') + if [[ "$STATE" != "OPEN" ]]; then + exit 1 + fi + + gh pr edit cargo_update --title "${PR_TITLE}" --body-file body.md --repo $GITHUB_REPOSITORY + + - name: open new pull request + # Only run if there wasn't an existing PR + if: steps.edit.outcome != 'success' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh pr create --title "${PR_TITLE}" --body-file body.md --repo $GITHUB_REPOSITORY From 82466625b48790fe01bba1137d506c3fe2c128cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20B=C3=B6ving?= Date: Tue, 13 Jun 2023 20:20:17 +0000 Subject: [PATCH 08/37] fix: get the l4re target working again --- library/std/src/personality.rs | 2 +- library/std/src/sys/unix/l4re.rs | 6 +++++- .../std/src/sys/unix/process/process_unix.rs | 18 +++++++++++++++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/library/std/src/personality.rs b/library/std/src/personality.rs index 63f0ad4f16e34..386a399f53228 100644 --- a/library/std/src/personality.rs +++ b/library/std/src/personality.rs @@ -29,7 +29,7 @@ cfg_if::cfg_if! { all(target_family = "windows", target_env = "gnu"), target_os = "psp", target_os = "solid_asp3", - all(target_family = "unix", not(target_os = "espidf")), + all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re")), all(target_vendor = "fortanix", target_env = "sgx"), ))] { mod gcc; diff --git a/library/std/src/sys/unix/l4re.rs b/library/std/src/sys/unix/l4re.rs index ee016887e7021..fe9559f2a569f 100644 --- a/library/std/src/sys/unix/l4re.rs +++ b/library/std/src/sys/unix/l4re.rs @@ -10,7 +10,7 @@ macro_rules! unimpl { pub mod net { #![allow(warnings)] use crate::fmt; - use crate::io::{self, IoSlice, IoSliceMut}; + use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::fd::FileDesc; @@ -218,6 +218,10 @@ pub mod net { unimpl!(); } + pub fn read_buf(&self, _: BorrowedCursor<'_>) -> io::Result<()> { + unimpl!(); + } + pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { unimpl!(); } diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 3721988b405b4..22d9d6141f404 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -836,31 +836,47 @@ fn signal_string(signal: i32) -> &'static str { libc::SIGILL => " (SIGILL)", libc::SIGTRAP => " (SIGTRAP)", libc::SIGABRT => " (SIGABRT)", + #[cfg(not(target_os = "l4re"))] libc::SIGBUS => " (SIGBUS)", libc::SIGFPE => " (SIGFPE)", libc::SIGKILL => " (SIGKILL)", + #[cfg(not(target_os = "l4re"))] libc::SIGUSR1 => " (SIGUSR1)", libc::SIGSEGV => " (SIGSEGV)", + #[cfg(not(target_os = "l4re"))] libc::SIGUSR2 => " (SIGUSR2)", libc::SIGPIPE => " (SIGPIPE)", libc::SIGALRM => " (SIGALRM)", libc::SIGTERM => " (SIGTERM)", + #[cfg(not(target_os = "l4re"))] libc::SIGCHLD => " (SIGCHLD)", + #[cfg(not(target_os = "l4re"))] libc::SIGCONT => " (SIGCONT)", + #[cfg(not(target_os = "l4re"))] libc::SIGSTOP => " (SIGSTOP)", + #[cfg(not(target_os = "l4re"))] libc::SIGTSTP => " (SIGTSTP)", + #[cfg(not(target_os = "l4re"))] libc::SIGTTIN => " (SIGTTIN)", + #[cfg(not(target_os = "l4re"))] libc::SIGTTOU => " (SIGTTOU)", + #[cfg(not(target_os = "l4re"))] libc::SIGURG => " (SIGURG)", + #[cfg(not(target_os = "l4re"))] libc::SIGXCPU => " (SIGXCPU)", + #[cfg(not(target_os = "l4re"))] libc::SIGXFSZ => " (SIGXFSZ)", + #[cfg(not(target_os = "l4re"))] libc::SIGVTALRM => " (SIGVTALRM)", + #[cfg(not(target_os = "l4re"))] libc::SIGPROF => " (SIGPROF)", + #[cfg(not(target_os = "l4re"))] libc::SIGWINCH => " (SIGWINCH)", - #[cfg(not(target_os = "haiku"))] + #[cfg(not(any(target_os = "haiku", target_os = "l4re")))] libc::SIGIO => " (SIGIO)", #[cfg(target_os = "haiku")] libc::SIGPOLL => " (SIGPOLL)", + #[cfg(not(target_os = "l4re"))] libc::SIGSYS => " (SIGSYS)", // For information on Linux signals, run `man 7 signal` #[cfg(all( From e94f26a40ae22e6651e8f5d9ad024d44d05fb80a Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 13 Jun 2023 21:45:04 -0700 Subject: [PATCH 09/37] Bump stdarch --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index 7e2cdc675b921..d77878b7299dd 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit 7e2cdc675b92165c5f8c4c794620252be4605e74 +Subproject commit d77878b7299dd7e286799a6e8447048b65d2a861 From be9b1334a0680e64b892e1d2c1ef827628f4a834 Mon Sep 17 00:00:00 2001 From: jyn Date: Wed, 14 Jun 2023 09:01:19 -0500 Subject: [PATCH 10/37] Suggest bumping download-ci-llvm-stamp if the build config for llvm is changed --- triagebot.toml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 0f0b31e9f38a1..9248e8fc28a13 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -477,6 +477,13 @@ message = "This PR changes src/bootstrap/defaults/config.compiler.toml. If appro [mentions."src/bootstrap/defaults/config.codegen.toml"] message = "This PR changes src/bootstrap/defaults/config.codegen.toml. If appropriate, please also update `config.compiler.toml` so the defaults are in sync." +[mentions."src/bootstrap/llvm.rs"] +message = "This PR changes how LLVM is built. Consider updating src/bootstrap/download-ci-llvm-stamp." +[mentions."compiler/rustc_llvm/build.rs"] +message = "This PR changes how LLVM is built. Consider updating src/bootstrap/download-ci-llvm-stamp." +[mentions."compiler/rustc_llvm/llvm-wrapper"] +message = "This PR changes how LLVM is built. Consider updating src/bootstrap/download-ci-llvm-stamp." + [mentions."tests/ui/deriving/deriving-all-codegen.stdout"] message = "Changes to the code generated for builtin derived traits." cc = ["@nnethercote"] From e596579066e611a09557421c348560a89819ad80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 14 Jun 2023 19:52:49 +0000 Subject: [PATCH 11/37] inline explicit rpo access in promote consts --- compiler/rustc_const_eval/src/transform/promote_consts.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 0e2d9ee8fb2fb..44b143c77f36e 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -14,7 +14,6 @@ use rustc_hir as hir; use rustc_middle::mir; -use rustc_middle::mir::traversal::ReversePostorderIter; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::subst::InternalSubsts; @@ -53,9 +52,8 @@ impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> { return; } - let mut rpo = traversal::reverse_postorder(body); let ccx = ConstCx::new(tcx, body); - let (mut temps, all_candidates) = collect_temps_and_candidates(&ccx, &mut rpo); + let (mut temps, all_candidates) = collect_temps_and_candidates(&ccx); let promotable_candidates = validate_candidates(&ccx, &mut temps, &all_candidates); @@ -166,14 +164,13 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { pub fn collect_temps_and_candidates<'tcx>( ccx: &ConstCx<'_, 'tcx>, - rpo: &mut ReversePostorderIter<'_, 'tcx>, ) -> (IndexVec, Vec) { let mut collector = Collector { temps: IndexVec::from_elem(TempState::Undefined, &ccx.body.local_decls), candidates: vec![], ccx, }; - for (bb, data) in rpo { + for (bb, data) in traversal::reverse_postorder(ccx.body) { collector.visit_basic_block_data(bb, data); } (collector.temps, collector.candidates) From 066d38190bb5e086d7ab565bc46d71b49c6d5217 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 14 Jun 2023 19:56:35 +0000 Subject: [PATCH 12/37] add RPO to BB CFG cache --- compiler/rustc_middle/src/mir/basic_blocks.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 9d70dbfa07221..29873a93fe630 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -27,6 +27,7 @@ struct Cache { switch_sources: OnceCell, is_cyclic: OnceCell, postorder: OnceCell>, + reverse_postorder: OnceCell>, dominators: OnceCell>, } @@ -70,6 +71,17 @@ impl<'tcx> BasicBlocks<'tcx> { }) } + /// Returns basic blocks in a reverse postorder. + #[inline] + pub fn reverse_postorder(&self) -> &[BasicBlock] { + self.cache.reverse_postorder.get_or_init(|| { + let mut rpo: Vec<_> = + Postorder::new(&self.basic_blocks, START_BLOCK).map(|(bb, _)| bb).collect(); + rpo.reverse(); + rpo + }) + } + /// `switch_sources()[&(target, switch)]` returns a list of switch /// values that lead to a `target` block from a `switch` block. #[inline] From 4215859617a1037955db1150719c6faed2ce32a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 14 Jun 2023 19:57:23 +0000 Subject: [PATCH 13/37] make const-prop use cached RPO --- compiler/rustc_mir_transform/src/const_prop.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 1d43dbda0aae4..2f2c7357b0069 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -118,8 +118,8 @@ impl<'tcx> MirPass<'tcx> for ConstProp { // Traverse the body in reverse post-order, to ensure that `FullConstProp` locals are // assigned before being read. - let postorder = body.basic_blocks.postorder().to_vec(); - for bb in postorder.into_iter().rev() { + let rpo = body.basic_blocks.reverse_postorder().to_vec(); + for bb in rpo { let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb]; optimization_finder.visit_basic_block_data(bb, data); } From 8f6e65136c94956fc172f73b31be282b65afb0c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 14 Jun 2023 19:57:55 +0000 Subject: [PATCH 14/37] make reorder BB pass use cached RPO --- compiler/rustc_mir_transform/src/prettify.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/prettify.rs b/compiler/rustc_mir_transform/src/prettify.rs index 6f46974ea0053..745fa30841c35 100644 --- a/compiler/rustc_mir_transform/src/prettify.rs +++ b/compiler/rustc_mir_transform/src/prettify.rs @@ -24,7 +24,7 @@ impl<'tcx> MirPass<'tcx> for ReorderBasicBlocks { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let rpo: IndexVec = - body.basic_blocks.postorder().iter().copied().rev().collect(); + body.basic_blocks.reverse_postorder().iter().copied().collect(); if rpo.iter().is_sorted() { return; } From 0eec39b67d12d121095a1da4e24109ce4dc41054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 14 Jun 2023 19:59:41 +0000 Subject: [PATCH 15/37] make `traversal::reverse_postorder` use RPO cache --- compiler/rustc_middle/src/mir/traversal.rs | 35 ++++------------------ 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 99ead14139aec..780003f5fa05d 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -295,34 +295,11 @@ pub fn reachable_as_bitset(body: &Body<'_>) -> BitSet { iter.visited } -#[derive(Clone)] -pub struct ReversePostorderIter<'a, 'tcx> { +/// Creates an iterator over the `Body`'s basic blocks, that: +/// - returns basic blocks in a reverse postorder, +/// - makes use of the `BasicBlocks` CFG cache's reverse postorder. +pub fn reverse_postorder<'a, 'tcx>( body: &'a Body<'tcx>, - blocks: &'a [BasicBlock], - idx: usize, -} - -impl<'a, 'tcx> Iterator for ReversePostorderIter<'a, 'tcx> { - type Item = (BasicBlock, &'a BasicBlockData<'tcx>); - - fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> { - if self.idx == 0 { - return None; - } - self.idx -= 1; - - self.blocks.get(self.idx).map(|&bb| (bb, &self.body[bb])) - } - - fn size_hint(&self) -> (usize, Option) { - (self.idx, Some(self.idx)) - } -} - -impl<'a, 'tcx> ExactSizeIterator for ReversePostorderIter<'a, 'tcx> {} - -pub fn reverse_postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> ReversePostorderIter<'a, 'tcx> { - let blocks = body.basic_blocks.postorder(); - let len = blocks.len(); - ReversePostorderIter { body, blocks, idx: len } +) -> impl Iterator)> + ExactSizeIterator { + body.basic_blocks.reverse_postorder().iter().map(|&bb| (bb, &body.basic_blocks[bb])) } From 0b4b0869a7968a2612c9bd93019a021ce168c557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 14 Jun 2023 20:00:23 +0000 Subject: [PATCH 16/37] make `traversal::postorder` traverse RPO cache backwards --- compiler/rustc_middle/src/mir/traversal.rs | 40 +++++++++++++++++++--- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 780003f5fa05d..6d44234d11f2c 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -188,10 +188,6 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { } } -pub fn postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Postorder<'a, 'tcx> { - Postorder::new(&body.basic_blocks, START_BLOCK) -} - impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> { type Item = (BasicBlock, &'a BasicBlockData<'tcx>); @@ -219,6 +215,42 @@ impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> { } } +/// Creates an iterator over the `Body`'s basic blocks, that: +/// - returns basic blocks in a postorder, +/// - traverses the `BasicBlocks` CFG cache's reverse postorder backwards, and does not cache the +/// postorder itself. +pub fn postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> PostorderIter<'a, 'tcx> { + let blocks = body.basic_blocks.reverse_postorder(); + let len = blocks.len(); + PostorderIter { body, blocks, idx: len } +} + +#[derive(Clone)] +pub struct PostorderIter<'a, 'tcx> { + body: &'a Body<'tcx>, + blocks: &'a [BasicBlock], + idx: usize, +} + +impl<'a, 'tcx> Iterator for PostorderIter<'a, 'tcx> { + type Item = (BasicBlock, &'a BasicBlockData<'tcx>); + + fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> { + if self.idx == 0 { + return None; + } + self.idx -= 1; + + self.blocks.get(self.idx).map(|&bb| (bb, &self.body[bb])) + } + + fn size_hint(&self) -> (usize, Option) { + (self.idx, Some(self.idx)) + } +} + +impl<'a, 'tcx> ExactSizeIterator for PostorderIter<'a, 'tcx> {} + /// Reverse postorder traversal of a graph /// /// Reverse postorder is the reverse order of a postorder traversal. From f134101e69bcf52ffa36b9a713a38df80a3a9676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 14 Jun 2023 20:04:51 +0000 Subject: [PATCH 17/37] remove unused postorder CFG cache --- compiler/rustc_middle/src/mir/basic_blocks.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 29873a93fe630..7722e7b47cffa 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -26,7 +26,6 @@ struct Cache { predecessors: OnceCell, switch_sources: OnceCell, is_cyclic: OnceCell, - postorder: OnceCell>, reverse_postorder: OnceCell>, dominators: OnceCell>, } @@ -63,14 +62,6 @@ impl<'tcx> BasicBlocks<'tcx> { }) } - /// Returns basic blocks in a postorder. - #[inline] - pub fn postorder(&self) -> &[BasicBlock] { - self.cache.postorder.get_or_init(|| { - Postorder::new(&self.basic_blocks, START_BLOCK).map(|(bb, _)| bb).collect() - }) - } - /// Returns basic blocks in a reverse postorder. #[inline] pub fn reverse_postorder(&self) -> &[BasicBlock] { From 88b08582b2781339f30deedffcfc84949d4190a0 Mon Sep 17 00:00:00 2001 From: zica <9918800@gmail.com> Date: Thu, 15 Jun 2023 11:14:24 +0800 Subject: [PATCH 18/37] Correct types in method descriptions of `NonZero*` types --- library/core/src/num/nonzero.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 7f06e170ad0f0..5939dedbd1db0 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -348,7 +348,7 @@ macro_rules! nonzero_unsigned_operations { } /// Adds an unsigned integer to a non-zero value. - #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")] + #[doc = concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.")] /// /// # Examples /// @@ -579,7 +579,7 @@ macro_rules! nonzero_signed_operations { /// Checked absolute value. /// Checks for overflow and returns [`None`] if - #[doc = concat!("`self == ", stringify!($Int), "::MIN`.")] + #[doc = concat!("`self == ", stringify!($Ty), "::MIN`.")] /// The result cannot be zero. /// /// # Example @@ -800,7 +800,8 @@ macro_rules! nonzero_signed_operations { self.get().is_negative() } - /// Checked negation. Computes `-self`, returning `None` if `self == i32::MIN`. + /// Checked negation. Computes `-self`, + #[doc = concat!("returning `None` if `self == ", stringify!($Ty), "::MIN`.")] /// /// # Example /// @@ -859,8 +860,10 @@ macro_rules! nonzero_signed_operations { ((unsafe { $Ty::new_unchecked(result) }), overflow) } - /// Saturating negation. Computes `-self`, returning `MAX` if - /// `self == i32::MIN` instead of overflowing. + /// Saturating negation. Computes `-self`, + #[doc = concat!("returning [`", stringify!($Ty), "::MAX`]")] + #[doc = concat!("if `self == ", stringify!($Ty), "::MIN`")] + /// instead of overflowing. /// /// # Example /// @@ -993,7 +996,7 @@ macro_rules! nonzero_unsigned_signed_operations { } /// Multiplies two non-zero integers together. - #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")] + #[doc = concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.")] /// /// # Examples /// @@ -1102,11 +1105,11 @@ macro_rules! nonzero_unsigned_signed_operations { #[doc = sign_dependent_expr!{ $signedness ? if signed { - concat!("Return [`", stringify!($Int), "::MIN`] ", - "or [`", stringify!($Int), "::MAX`] on overflow.") + concat!("Return [`", stringify!($Ty), "::MIN`] ", + "or [`", stringify!($Ty), "::MAX`] on overflow.") } if unsigned { - concat!("Return [`", stringify!($Int), "::MAX`] on overflow.") + concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.") } }] /// From 886085a4d567bc882038ce5ec8498c45b436412d Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 15 Jun 2023 15:56:00 -0700 Subject: [PATCH 19/37] std: only depend on dlmalloc for wasm*-unknown It was already filtered out for emscripten, but wasi doesn't need dlmalloc either since it reuses `unix/alloc.rs`. --- library/std/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index e6b051838861a..af74efa6bf84d 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -38,7 +38,7 @@ features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } rand_xorshift = "0.3.0" -[target.'cfg(any(all(target_family = "wasm", not(target_os = "emscripten")), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies] +[target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies] dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] } [target.x86_64-fortanix-unknown-sgx.dependencies] From 9f509429cd0fc2290b523bd158953cdfcedcfb12 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 16 Jun 2023 13:43:55 +0200 Subject: [PATCH 20/37] Unify history interactions in search --- src/librustdoc/html/static/js/search.js | 29 ++++++++++++------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 25259971eff2f..180d93b790abd 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2160,6 +2160,18 @@ function initSearch(rawSearchIndex) { printTab(currentTab); } + function updateSearchHistory(url) { + if (!browserSupportsHistoryApi()) { + return; + } + const params = searchState.getQueryStringParams(); + if (!history.state && !params.search) { + history.pushState(null, "", url); + } else { + history.replaceState(null, "", url); + } + } + /** * Perform a search based on the current state of the search input element * and display the results. @@ -2196,15 +2208,7 @@ function initSearch(rawSearchIndex) { // Because searching is incremental by character, only the most // recent search query is added to the browser history. - if (browserSupportsHistoryApi()) { - const newURL = buildUrl(query.original, filterCrates); - - if (!history.state && !params.search) { - history.pushState(null, "", newURL); - } else { - history.replaceState(null, "", newURL); - } - } + updateSearchHistory(buildUrl(query.original, filterCrates)); showResults( execQuery(query, searchWords, filterCrates, window.currentCrate), @@ -2670,13 +2674,8 @@ function initSearch(rawSearchIndex) { function updateCrate(ev) { if (ev.target.value === "all crates") { // If we don't remove it from the URL, it'll be picked up again by the search. - const params = searchState.getQueryStringParams(); const query = searchState.input.value.trim(); - if (!history.state && !params.search) { - history.pushState(null, "", buildUrl(query, null)); - } else { - history.replaceState(null, "", buildUrl(query, null)); - } + updateSearchHistory(buildUrl(query, null)); } // In case you "cut" the entry from the search input, then change the crate filter // before paste back the previous search, you get the old search results without From 7a2490eba3f161c81ad243c7d957b337dd70a2af Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 13 Jun 2023 18:25:15 -0400 Subject: [PATCH 21/37] Launch a non-unwinding panic for misaligned pointer deref --- compiler/rustc_mir_transform/src/check_alignment.rs | 10 ++++------ library/core/src/panicking.rs | 5 +++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index ef64f70fdf349..2787092566f26 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -9,7 +9,6 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::{Ty, TyCtxt, TypeAndMut}; use rustc_session::Session; -use rustc_target::spec::PanicStrategy; pub struct CheckAlignment; @@ -237,11 +236,10 @@ fn insert_alignment_check<'tcx>( required: Operand::Copy(alignment), found: Operand::Copy(addr), }), - unwind: if tcx.sess.panic_strategy() == PanicStrategy::Unwind { - UnwindAction::Terminate - } else { - UnwindAction::Unreachable - }, + // The panic symbol that this calls is #[rustc_nounwind]. We never want to insert an + // unwind into unsafe code, because unwinding could make a failing UB check turn into + // much worse UB when we start unwinding. + unwind: UnwindAction::Unreachable, }, }); } diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 81be3fb22eec4..f0fcdab00ada1 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -166,14 +166,15 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[track_caller] #[lang = "panic_misaligned_pointer_dereference"] // needed by codegen for panic on misaligned pointer deref +#[rustc_nounwind] // `CheckAlignment` MIR pass requires this function to never unwind fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! { if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() } - panic!( + panic_nounwind_fmt(format_args!( "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}" - ) + )) } /// Panic because we cannot unwind out of a function. From f4316392a756eae7f96952bd4ddc37e6449ef926 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 16 Jun 2023 16:56:13 +0200 Subject: [PATCH 22/37] Fix invalid handling of "going back in history" when "Directly go to item in search if there is only one result" setting is set to true --- src/librustdoc/html/static/js/main.js | 10 +++++++--- src/librustdoc/html/static/js/search.js | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index a184b7b705e96..f5296abaee661 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -277,14 +277,18 @@ function preLoadCss(cssUrl) { searchState.mouseMovedAfterSearch = false; document.title = searchState.title; }, - hideResults: () => { - switchDisplayedElement(null); + removeQueryParameters: () => { + // We change the document title. document.title = searchState.titleBeforeSearch; - // We also remove the query parameter from the URL. if (browserSupportsHistoryApi()) { history.replaceState(null, "", getNakedUrl() + window.location.hash); } }, + hideResults: () => { + switchDisplayedElement(null); + // We also remove the query parameter from the URL. + searchState.removeQueryParameters(); + }, getQueryStringParams: () => { const params = {}; window.location.search.substring(1).split("&"). diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 180d93b790abd..af11b31b3958c 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2046,6 +2046,20 @@ function initSearch(rawSearchIndex) { if (go_to_first || (results.others.length === 1 && getSettingValue("go-to-only-result") === "true") ) { + // Needed to force re-execution of JS when coming back to a page. Let's take this + // scenario as example: + // + // 1. You have the "Directly go to item in search if there is only one result" option + // enabled. + // 2. You make a search which results only one result, leading you automatically to + // this result. + // 3. You go back to previous page. + // + // Now, without the call below, the JS will not be re-executed and the previous state + // will be used, starting search again since the search input is not empty, leading you + // back to the previous page again. + window.onunload = () => {}; + searchState.removeQueryParameters(); const elem = document.createElement("a"); elem.href = results.others[0].href; removeClass(elem, "active"); @@ -2182,7 +2196,6 @@ function initSearch(rawSearchIndex) { if (e) { e.preventDefault(); } - const query = parseQuery(searchState.input.value.trim()); let filterCrates = getFilterCrates(); From ea55d25465f8dffc8283c0260f8dfa42076ba847 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 16 Jun 2023 20:41:00 +0200 Subject: [PATCH 23/37] Add regression test for #112676 --- tests/rustdoc-gui/setting-go-to-only-result.goml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/rustdoc-gui/setting-go-to-only-result.goml b/tests/rustdoc-gui/setting-go-to-only-result.goml index c5720b4bf1ac6..45e0b349051ee 100644 --- a/tests/rustdoc-gui/setting-go-to-only-result.goml +++ b/tests/rustdoc-gui/setting-go-to-only-result.goml @@ -34,7 +34,14 @@ go-to: "file://" + |DOC_PATH| + "/lib2/index.html" // We enter it into the search. write: (".search-input", "HasALongTraitWithParams") wait-for-document-property: {"title": "HasALongTraitWithParams in lib2 - Rust"} -assert-document-property: ({"URL": "/lib2/struct.HasALongTraitWithParams.html"}, ENDS_WITH) +assert-window-property: ({"location": "/lib2/struct.HasALongTraitWithParams.html"}, ENDS_WITH) + +// Regression test for . +// If "go-to-only-result" is enabled and you go back to history, it should not lead you back to the +// page result again automatically. +history-go-back: +wait-for-document-property: {"title": "lib2 - Rust"} +assert-window-property: ({"location": "/lib2/index.html"}, ENDS_WITH) // We try again to see if it goes to the only result go-to: "file://" + |DOC_PATH| + "/lib2/index.html?search=HasALongTraitWithParams" From 3078de76368a78ed0b481295393327b7296dcc95 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Fri, 16 Jun 2023 13:39:55 -0700 Subject: [PATCH 24/37] add dry_run check --- src/bootstrap/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 13a10b0d3a506..01d0dbafd1ef6 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1766,7 +1766,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the // // Note that if we encounter `PATH` we make sure to append to our own `PATH` // rather than stomp over it. - if target.contains("msvc") { + if !builder.config.dry_run() && target.contains("msvc") { for &(ref k, ref v) in builder.cc.borrow()[&target].env() { if k != "PATH" { cmd.env(k, v); From a5c6cb888eac7ad8905a3902b985e412aaceb002 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Mon, 1 Aug 2022 13:51:58 -0700 Subject: [PATCH 25/37] remove box_free and replace with drop impl --- .../example/mini_core.rs | 8 +- .../rustc_codegen_gcc/example/mini_core.rs | 8 +- compiler/rustc_hir/src/lang_items.rs | 1 - .../rustc_mir_dataflow/src/elaborate_drops.rs | 100 +++++------------- compiler/rustc_monomorphize/src/collector.rs | 6 -- compiler/rustc_span/src/symbol.rs | 1 - library/alloc/src/alloc.rs | 7 +- library/alloc/src/boxed.rs | 10 +- library/alloc/src/rc.rs | 16 ++- library/alloc/src/sync.rs | 16 ++- .../src/language-features/lang-items.md | 16 +-- .../miri/tests/fail/alloc/stack_free.stderr | 2 +- .../deallocate_against_protector1.stderr | 2 +- .../tree-borrows/strongly-protected.stderr | 2 +- .../stack-protector-heuristics-effect.rs | 2 +- .../unsized_argument.caller.Inline.diff | 29 ++--- tests/ui/mir/ssa-analysis-regression-50041.rs | 11 +- 17 files changed, 91 insertions(+), 146 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 772dd98fade2b..79ca4c039854e 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -546,7 +546,8 @@ impl Box { impl Drop for Box { fn drop(&mut self) { - // drop is currently performed by compiler. + // inner value is dropped by compiler + libc::free(self.0.pointer.0 as *mut u8); } } @@ -563,11 +564,6 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { libc::malloc(size) } -#[lang = "box_free"] -unsafe fn box_free(ptr: Unique, _alloc: ()) { - libc::free(ptr.pointer.0 as *mut u8); -} - #[lang = "drop"] pub trait Drop { fn drop(&mut self); diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index 637b8dc53fefd..c27b610f2aba9 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -490,7 +490,8 @@ impl, U: ?Sized, A: Allocator> CoerceUnsized> fo impl Drop for Box { fn drop(&mut self) { - // drop is currently performed by compiler. + // inner value is dropped by compiler + libc::free(self.pointer.0 as *mut u8); } } @@ -507,11 +508,6 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { libc::malloc(size) } -#[lang = "box_free"] -unsafe fn box_free(ptr: Unique, _alloc: ()) { - libc::free(ptr.pointer.0 as *mut u8); -} - #[lang = "drop"] pub trait Drop { fn drop(&mut self); diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 4b3bc816b9531..c717565d4d5e6 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -250,7 +250,6 @@ language_item_table! { FormatUnsafeArg, sym::format_unsafe_arg, format_unsafe_arg, Target::Struct, GenericRequirement::None; ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None; - BoxFree, sym::box_free, box_free_fn, Target::Fn, GenericRequirement::Minimum(1); DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1); AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None; diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index d615c83d62191..4fc45eaf5220d 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -409,8 +409,15 @@ where self.drop_ladder(fields, succ, unwind).0 } + /// Drops the T contained in a `Box` if it has not been moved out of #[instrument(level = "debug", ret)] - fn open_drop_for_box(&mut self, adt: ty::AdtDef<'tcx>, substs: SubstsRef<'tcx>) -> BasicBlock { + fn open_drop_for_box_contents( + &mut self, + adt: ty::AdtDef<'tcx>, + substs: SubstsRef<'tcx>, + succ: BasicBlock, + unwind: Unwind, + ) -> BasicBlock { // drop glue is sent straight to codegen // box cannot be directly dereferenced let unique_ty = adt.non_enum_variant().fields[FieldIdx::new(0)].ty(self.tcx(), substs); @@ -425,11 +432,7 @@ where let interior_path = self.elaborator.deref_subpath(self.path); - let succ = self.box_free_block(adt, substs, self.succ, self.unwind); - let unwind_succ = - self.unwind.map(|unwind| self.box_free_block(adt, substs, unwind, Unwind::InCleanup)); - - self.drop_subpath(interior, interior_path, succ, unwind_succ) + self.drop_subpath(interior, interior_path, succ, unwind) } #[instrument(level = "debug", ret)] @@ -453,7 +456,15 @@ where self.open_drop_for_adt_contents(adt, substs) }; - if adt.has_dtor(self.tcx()) { + if adt.is_box() { + // we need to drop the inside of the box before running the destructor + let succ = self.destructor_call_block(contents_drop); + let unwind = contents_drop + .1 + .map(|unwind| self.destructor_call_block((unwind, Unwind::InCleanup))); + + self.open_drop_for_box_contents(adt, substs, succ, unwind) + } else if adt.has_dtor(self.tcx()) { self.destructor_call_block(contents_drop) } else { contents_drop.0 @@ -650,7 +661,13 @@ where }), is_cleanup: unwind.is_cleanup(), }; - self.elaborator.patch().new_block(result) + + let destructor_block = self.elaborator.patch().new_block(result); + + let block_start = Location { block: destructor_block, statement_index: 0 }; + self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow); + + self.drop_flag_test_block(destructor_block, succ, unwind) } /// Create a loop that drops an array: @@ -851,13 +868,7 @@ where self.open_drop_for_tuple(&tys) } ty::Tuple(fields) => self.open_drop_for_tuple(fields), - ty::Adt(def, substs) => { - if def.is_box() { - self.open_drop_for_box(*def, substs) - } else { - self.open_drop_for_adt(*def, substs) - } - } + ty::Adt(def, substs) => self.open_drop_for_adt(*def, substs), ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind), ty::Array(ety, size) => { let size = size.try_eval_target_usize(self.tcx(), self.elaborator.param_env()); @@ -905,65 +916,6 @@ where blk } - /// Creates a block that frees the backing memory of a `Box` if its drop is required (either - /// statically or by checking its drop flag). - /// - /// The contained value will not be dropped. - fn box_free_block( - &mut self, - adt: ty::AdtDef<'tcx>, - substs: SubstsRef<'tcx>, - target: BasicBlock, - unwind: Unwind, - ) -> BasicBlock { - let block = self.unelaborated_free_block(adt, substs, target, unwind); - self.drop_flag_test_block(block, target, unwind) - } - - /// Creates a block that frees the backing memory of a `Box` (without dropping the contained - /// value). - fn unelaborated_free_block( - &mut self, - adt: ty::AdtDef<'tcx>, - substs: SubstsRef<'tcx>, - target: BasicBlock, - unwind: Unwind, - ) -> BasicBlock { - let tcx = self.tcx(); - let unit_temp = Place::from(self.new_temp(tcx.mk_unit())); - let free_func = tcx.require_lang_item(LangItem::BoxFree, Some(self.source_info.span)); - let args = adt - .variant(FIRST_VARIANT) - .fields - .iter() - .enumerate() - .map(|(i, f)| { - let field = FieldIdx::new(i); - let field_ty = f.ty(tcx, substs); - Operand::Move(tcx.mk_place_field(self.place, field, field_ty)) - }) - .collect(); - - let call = TerminatorKind::Call { - func: Operand::function_handle(tcx, free_func, substs, self.source_info.span), - args, - destination: unit_temp, - target: Some(target), - unwind: if unwind.is_cleanup() { - UnwindAction::Terminate - } else { - UnwindAction::Continue - }, - from_hir_call: false, - fn_span: self.source_info.span, - }; // FIXME(#43234) - let free_block = self.new_block(unwind, call); - - let block_start = Location { block: free_block, statement_index: 0 }; - self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow); - free_block - } - fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { let block = TerminatorKind::Drop { place: self.place, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index f4ee7b7587587..4a5953c11492c 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -123,12 +123,6 @@ //! pointers to these functions even if they never get called anywhere. This can //! be seen as a special case of taking a function reference. //! -//! #### Boxes -//! Since `Box` expression have special compiler support, no explicit calls to -//! `exchange_malloc()` and `box_free()` may show up in MIR, even if the -//! compiler will generate them. We have to observe `Rvalue::Box` expressions -//! and Box-typed drop-statements for that purpose. -//! //! //! Interaction with Cross-Crate Inlining //! ------------------------------------- diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c5ce2575fff06..7f7262f54e5cc 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -432,7 +432,6 @@ symbols! { bool, borrowck_graphviz_format, borrowck_graphviz_postflow, - box_free, box_new, box_patterns, box_syntax, diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 8c4f6a73d7fea..e24a0fe51bda0 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -4,8 +4,10 @@ #[cfg(not(test))] use core::intrinsics; +#[cfg(all(bootstrap, not(test)))] use core::intrinsics::{min_align_of_val, size_of_val}; +#[cfg(all(bootstrap, not(test)))] use core::ptr::Unique; #[cfg(not(test))] use core::ptr::{self, NonNull}; @@ -335,14 +337,15 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { } } -#[cfg_attr(not(test), lang = "box_free")] +#[cfg(all(bootstrap, not(test)))] +#[lang = "box_free"] #[inline] // This signature has to be the same as `Box`, otherwise an ICE will happen. // When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as // well. // For example if `Box` is changed to `struct Box(Unique, A)`, // this function has to be changed to `fn box_free(Unique, A)` as well. -pub(crate) unsafe fn box_free(ptr: Unique, alloc: A) { +unsafe fn box_free(ptr: Unique, alloc: A) { unsafe { let size = size_of_val(ptr.as_ref()); let align = min_align_of_val(ptr.as_ref()); diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 1768687e8cd02..8ef2bac9282cd 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1211,8 +1211,16 @@ impl Box { #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box { + #[inline] fn drop(&mut self) { - // FIXME: Do nothing, drop is currently performed by compiler. + // the T in the Box is dropped by the compiler before the destructor is run + + let ptr = self.0; + + unsafe { + let layout = Layout::for_value_raw(ptr.as_ptr()); + self.1.deallocate(From::from(ptr.cast()), layout) + } } } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 38a711ac7509f..34d3acae5464c 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -270,7 +270,7 @@ use core::slice::from_raw_parts_mut; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; #[cfg(not(no_global_oom_handling))] -use crate::alloc::{box_free, WriteCloneIntoRaw}; +use crate::alloc::WriteCloneIntoRaw; use crate::alloc::{AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; #[cfg(not(no_global_oom_handling))] @@ -1442,23 +1442,21 @@ impl Rc { } #[cfg(not(no_global_oom_handling))] - fn from_box(v: Box) -> Rc { + fn from_box(src: Box) -> Rc { unsafe { - let (box_unique, alloc) = Box::into_unique(v); - let bptr = box_unique.as_ptr(); - - let value_size = size_of_val(&*bptr); - let ptr = Self::allocate_for_ptr(bptr); + let value_size = size_of_val(&*src); + let ptr = Self::allocate_for_ptr(&*src); // Copy value as bytes ptr::copy_nonoverlapping( - bptr as *const T as *const u8, + &*src as *const T as *const u8, &mut (*ptr).value as *mut _ as *mut u8, value_size, ); // Free the allocation without dropping its contents - box_free(box_unique, alloc); + let src = Box::from_raw(Box::into_raw(src) as *mut mem::ManuallyDrop); + drop(src); Self::from_ptr(ptr) } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index bfdb7a92beff6..d2c87cf705c61 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -33,7 +33,7 @@ use core::sync::atomic::Ordering::{Acquire, Relaxed, Release}; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; #[cfg(not(no_global_oom_handling))] -use crate::alloc::{box_free, WriteCloneIntoRaw}; +use crate::alloc::WriteCloneIntoRaw; use crate::alloc::{AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; @@ -1360,23 +1360,21 @@ impl Arc { } #[cfg(not(no_global_oom_handling))] - fn from_box(v: Box) -> Arc { + fn from_box(src: Box) -> Arc { unsafe { - let (box_unique, alloc) = Box::into_unique(v); - let bptr = box_unique.as_ptr(); - - let value_size = size_of_val(&*bptr); - let ptr = Self::allocate_for_ptr(bptr); + let value_size = size_of_val(&*src); + let ptr = Self::allocate_for_ptr(&*src); // Copy value as bytes ptr::copy_nonoverlapping( - bptr as *const T as *const u8, + &*src as *const T as *const u8, &mut (*ptr).data as *mut _ as *mut u8, value_size, ); // Free the allocation without dropping its contents - box_free(box_unique, alloc); + let src = Box::from_raw(Box::into_raw(src) as *mut mem::ManuallyDrop); + drop(src); Self::from_ptr(ptr) } diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md index 6adb3506e646a..f4bc18bc7dabd 100644 --- a/src/doc/unstable-book/src/language-features/lang-items.md +++ b/src/doc/unstable-book/src/language-features/lang-items.md @@ -11,8 +11,8 @@ it exists. The marker is the attribute `#[lang = "..."]` and there are various different values of `...`, i.e. various different 'lang items'. -For example, `Box` pointers require two lang items, one for allocation -and one for deallocation. A freestanding program that uses the `Box` +For example, `Box` pointers require a lang item for allocation. +A freestanding program that uses the `Box` sugar for dynamic allocations via `malloc` and `free`: ```rust,ignore (libc-is-finicky) @@ -48,9 +48,10 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { p } -#[lang = "box_free"] -unsafe fn box_free(ptr: *mut T) { - libc::free(ptr as *mut libc::c_void) +impl Drop for Box { + fn drop(&mut self) { + libc::free(self.0.0.0 as *mut libc::c_void) + } } #[start] @@ -84,8 +85,8 @@ Other features provided by lang items include: `contravariant_lifetime`, etc. Lang items are loaded lazily by the compiler; e.g. if one never uses -`Box` then there is no need to define functions for `exchange_malloc` -and `box_free`. `rustc` will emit an error when an item is needed +`Box` then there is no need to define a function for `exchange_malloc`. +`rustc` will emit an error when an item is needed but not found in the current crate or any that it depends on. Most lang items are defined by `libcore`, but if you're trying to build @@ -250,7 +251,6 @@ the source code. - Allocations - `owned_box`: `liballoc/boxed.rs` - `exchange_malloc`: `liballoc/heap.rs` - - `box_free`: `liballoc/heap.rs` - Operands - `not`: `libcore/ops/bit.rs` - `bitand`: `libcore/ops/bit.rs` diff --git a/src/tools/miri/tests/fail/alloc/stack_free.stderr b/src/tools/miri/tests/fail/alloc/stack_free.stderr index b1636050a78ca..7c14d372f0c7c 100644 --- a/src/tools/miri/tests/fail/alloc/stack_free.stderr +++ b/src/tools/miri/tests/fail/alloc/stack_free.stderr @@ -9,7 +9,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } = note: BACKTRACE: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside ` as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr b/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr index 516964b9a4e6f..8ebb35450e5fa 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr @@ -9,7 +9,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } = note: BACKTRACE: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside ` as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside closure diff --git a/src/tools/miri/tests/fail/tree-borrows/strongly-protected.stderr b/src/tools/miri/tests/fail/tree-borrows/strongly-protected.stderr index 97088d5854cc9..55665e63e8a7e 100644 --- a/src/tools/miri/tests/fail/tree-borrows/strongly-protected.stderr +++ b/src/tools/miri/tests/fail/tree-borrows/strongly-protected.stderr @@ -20,7 +20,7 @@ LL | fn inner(x: &mut i32, f: fn(&mut i32)) { = note: BACKTRACE (of the first span): = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside ` as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside closure diff --git a/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs b/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs index 7c2b605509053..011a253c6ff61 100644 --- a/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs +++ b/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs @@ -370,7 +370,7 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { // all: __stack_chk_fail - // strong-NOT: __stack_chk_fail + // strong: __stack_chk_fail // basic-NOT: __stack_chk_fail // none-NOT: __stack_chk_fail // missing-NOT: __stack_chk_fail diff --git a/tests/mir-opt/inline/unsized_argument.caller.Inline.diff b/tests/mir-opt/inline/unsized_argument.caller.Inline.diff index 5c64d4305591c..6ee6a0ffe4cde 100644 --- a/tests/mir-opt/inline/unsized_argument.caller.Inline.diff +++ b/tests/mir-opt/inline/unsized_argument.caller.Inline.diff @@ -6,36 +6,41 @@ let mut _0: (); let _2: (); let mut _3: std::boxed::Box<[i32]>; - let mut _4: (); + let mut _4: &mut std::boxed::Box<[i32]>; let mut _5: (); - let mut _6: (); - let mut _7: *const [i32]; + let mut _6: &mut std::boxed::Box<[i32]>; + let mut _7: (); + let mut _8: &mut std::boxed::Box<[i32]>; + let mut _9: (); + let mut _10: *const [i32]; bb0: { StorageLive(_2); StorageLive(_3); _3 = move _1; - _7 = (((_3.0: std::ptr::Unique<[i32]>).0: std::ptr::NonNull<[i32]>).0: *const [i32]); - _2 = callee(move (*_7)) -> [return: bb3, unwind: bb4]; + _10 = (((_3.0: std::ptr::Unique<[i32]>).0: std::ptr::NonNull<[i32]>).0: *const [i32]); + _2 = callee(move (*_10)) -> [return: bb3, unwind: bb4]; } - bb1: { + bb1 (cleanup): { + resume; + } + + bb2: { StorageDead(_3); StorageDead(_2); _0 = const (); return; } - bb2 (cleanup): { - resume; - } - bb3: { - _4 = alloc::alloc::box_free::<[i32], std::alloc::Global>(move (_3.0: std::ptr::Unique<[i32]>), move (_3.1: std::alloc::Global)) -> bb1; + _4 = &mut _3; + _5 = as Drop>::drop(move _4) -> [return: bb2, unwind: bb1]; } bb4 (cleanup): { - _6 = alloc::alloc::box_free::<[i32], std::alloc::Global>(move (_3.0: std::ptr::Unique<[i32]>), move (_3.1: std::alloc::Global)) -> [return: bb2, unwind terminate]; + _8 = &mut _3; + _9 = as Drop>::drop(move _8) -> [return: bb1, unwind terminate]; } } diff --git a/tests/ui/mir/ssa-analysis-regression-50041.rs b/tests/ui/mir/ssa-analysis-regression-50041.rs index ebc3e2f8c0e31..534f1c465bb87 100644 --- a/tests/ui/mir/ssa-analysis-regression-50041.rs +++ b/tests/ui/mir/ssa-analysis-regression-50041.rs @@ -13,13 +13,10 @@ struct Unique(NonNull); pub struct Box(Unique); impl Drop for Box { - fn drop(&mut self) {} -} - -#[lang = "box_free"] -#[inline(always)] -unsafe fn box_free(ptr: Unique) { - dealloc(ptr.0.0) + #[inline(always)] + fn drop(&mut self) { + dealloc(self.0.0.0) + } } #[inline(never)] From 4c6fd7594d6526c7ad58d3bc16e42c0dc538017a Mon Sep 17 00:00:00 2001 From: David Koloski Date: Fri, 16 Jun 2023 16:34:34 -0400 Subject: [PATCH 26/37] Replace fvdl with ffx, allow test without install Along with replacing fvdl uses with the equivalent ffx commands, this also switches from using the install path for libstd-*.so and libtest-*.so to using the build directory (now passed on the command line). The user no longer needs to run x.py install before running tests now, and the correct libstd and libtest are detected on run instead of startup so the test runner can handle recompilations after starting the testing environment. --- src/ci/docker/scripts/fuchsia-test-runner.py | 237 +++++++----------- src/doc/rustc/src/platform-support/fuchsia.md | 19 +- 2 files changed, 100 insertions(+), 156 deletions(-) diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py index 78a8a6662ea64..73cf3de6a4619 100755 --- a/src/ci/docker/scripts/fuchsia-test-runner.py +++ b/src/ci/docker/scripts/fuchsia-test-runner.py @@ -25,13 +25,9 @@ @dataclass class TestEnvironment: - rust_dir: str + rust_build_dir: str sdk_dir: str target: str - package_server_pid: Optional[int] = None - emu_addr: Optional[str] = None - libstd_name: Optional[str] = None - libtest_name: Optional[str] = None verbose: bool = False @staticmethod @@ -57,7 +53,7 @@ def env_file_path(cls): @classmethod def from_args(cls, args): return cls( - os.path.abspath(args.rust), + os.path.abspath(args.rust_build), os.path.abspath(args.sdk), args.target, verbose=args.verbose, @@ -68,13 +64,9 @@ def read_from_file(cls): with open(cls.env_file_path(), encoding="utf-8") as f: test_env = json.loads(f.read()) return cls( - test_env["rust_dir"], + test_env["rust_build_dir"], test_env["sdk_dir"], test_env["target"], - libstd_name=test_env["libstd_name"], - libtest_name=test_env["libtest_name"], - emu_addr=test_env["emu_addr"], - package_server_pid=test_env["package_server_pid"], verbose=test_env["verbose"], ) @@ -82,18 +74,6 @@ def write_to_file(self): with open(self.env_file_path(), "w", encoding="utf-8") as f: f.write(json.dumps(self.__dict__)) - def ssh_dir(self): - return os.path.join(self.tmp_dir(), "ssh") - - def ssh_keyfile_path(self): - return os.path.join(self.ssh_dir(), "fuchsia_ed25519") - - def ssh_authfile_path(self): - return os.path.join(self.ssh_dir(), "fuchsia_authorized_keys") - - def vdl_output_path(self): - return os.path.join(self.tmp_dir(), "vdl_output") - def package_server_log_path(self): return os.path.join(self.tmp_dir(), "package_server_log") @@ -113,7 +93,9 @@ def repo_dir(self): def libs_dir(self): return os.path.join( - self.rust_dir, + self.rust_build_dir, + "host", + "stage2", "lib", ) @@ -212,21 +194,19 @@ def start_ffx_isolation(self): # Set configs configs = { "log.enabled": "true", - "ssh.pub": self.ssh_authfile_path(), - "ssh.priv": self.ssh_keyfile_path(), "test.is_isolated": "true", "test.experimental_structured_output": "true", } for key, value in configs.items(): subprocess.check_call( [ - self.tool_path("ffx"), + ffx_path, "config", "set", key, value, ], - env=self.ffx_cmd_env(), + env=ffx_env, stdout=self.subprocess_output(), stderr=self.subprocess_output(), ) @@ -248,6 +228,7 @@ def stop_ffx_isolation(self): self.tool_path("ffx"), "daemon", "stop", + "-w", ], env=self.ffx_cmd_env(), stdout=self.subprocess_output(), @@ -275,87 +256,62 @@ def start(self): elif len(os.listdir(self.tmp_dir())) != 0: raise Exception(f"Temp directory is not clean (in {self.tmp_dir()})") - os.mkdir(self.ssh_dir()) os.mkdir(self.output_dir()) - # Find libstd and libtest - libstd_paths = glob.glob(os.path.join(self.rustlibs_dir(), "libstd-*.so")) - libtest_paths = glob.glob(os.path.join(self.rustlibs_dir(), "libtest-*.so")) - - if not libstd_paths: - raise Exception(f"Failed to locate libstd (in {self.rustlibs_dir()})") - - if not libtest_paths: - raise Exception(f"Failed to locate libtest (in {self.rustlibs_dir()})") + ffx_path = self.tool_path("ffx") + ffx_env = self.ffx_cmd_env() - self.libstd_name = os.path.basename(libstd_paths[0]) - self.libtest_name = os.path.basename(libtest_paths[0]) + # Start ffx isolation + self.log_info("Starting ffx isolation...") + self.start_ffx_isolation() - # Generate SSH keys for the emulator to use - self.log_info("Generating SSH keys...") + # Stop any running emulators (there shouldn't be any) subprocess.check_call( [ - "ssh-keygen", - "-N", - "", - "-t", - "ed25519", - "-f", - self.ssh_keyfile_path(), - "-C", - "Generated by fuchsia-test-runner.py", + ffx_path, + "emu", + "stop", + "--all", ], + env=ffx_env, stdout=self.subprocess_output(), stderr=self.subprocess_output(), ) - authfile_contents = subprocess.check_output( + + # Start emulator + self.log_info("Starting emulator...") + product_bundle = "terminal.qemu-" + self.triple_to_arch(self.target) + subprocess.check_call( [ - "ssh-keygen", - "-y", - "-f", - self.ssh_keyfile_path(), + ffx_path, + "product-bundle", + "get", + product_bundle, ], + env=ffx_env, + stdout=self.subprocess_output(), stderr=self.subprocess_output(), ) - with open(self.ssh_authfile_path(), "wb") as authfile: - authfile.write(authfile_contents) - - # Start ffx isolation - self.log_info("Starting ffx isolation...") - self.start_ffx_isolation() - - # Start emulator (this will generate the vdl output) - self.log_info("Starting emulator...") + # FIXME: condition --accel hyper on target arch matching host arch subprocess.check_call( [ - self.tool_path("fvdl"), - "--sdk", + ffx_path, + "emu", "start", - "--tuntap", + product_bundle, "--headless", - "--nointeractive", - "--ssh", - self.ssh_dir(), - "--vdl-output", - self.vdl_output_path(), - "--emulator-log", + "--log", self.emulator_log_path(), - "--image-name", - "qemu-" + self.triple_to_arch(self.target), + "--net", + "tap", + "--accel", + "hyper", ], + env=ffx_env, stdout=self.subprocess_output(), stderr=self.subprocess_output(), ) - # Parse vdl output for relevant information - with open(self.vdl_output_path(), encoding="utf-8") as f: - vdl_content = f.read() - matches = re.search( - r'network_address:\s+"\[([0-9a-f]{1,4}:(:[0-9a-f]{1,4}){4}%qemu)\]"', - vdl_content, - ) - self.emu_addr = matches.group(1) - # Create new package repo self.log_info("Creating package repo...") subprocess.check_call( @@ -369,55 +325,40 @@ def start(self): stderr=self.subprocess_output(), ) - # Start package server - self.log_info("Starting package server...") - with open( - self.package_server_log_path(), "w", encoding="utf-8" - ) as package_server_log: - # We want this to be a long-running process that persists after the script finishes - # pylint: disable=consider-using-with - self.package_server_pid = subprocess.Popen( - [ - self.tool_path("pm"), - "serve", - "-vt", - "-repo", - self.repo_dir(), - "-l", - ":8084", - ], - stdout=package_server_log, - stderr=package_server_log, - ).pid - - # Register package server with emulator - self.log_info("Registering package server...") - ssh_client = subprocess.check_output( + # Add repo + subprocess.check_call( [ - "ssh", - "-i", - self.ssh_keyfile_path(), - "-o", - "StrictHostKeyChecking=accept-new", - self.emu_addr, - "-f", - "echo $SSH_CLIENT", + ffx_path, + "repository", + "add-from-pm", + self.repo_dir(), + "--repository", + self.TEST_REPO_NAME, ], - text=True, + env=ffx_env, + stdout=self.subprocess_output(), + stderr=self.subprocess_output(), ) - repo_addr = ssh_client.split()[0].replace("%", "%25") - repo_url = f"http://[{repo_addr}]:8084/config.json" + + # Start repository server + subprocess.check_call( + [ffx_path, "repository", "server", "start", "--address", "[::]:0"], + env=ffx_env, + stdout=self.subprocess_output(), + stderr=self.subprocess_output(), + ) + + # Register with newly-started emulator subprocess.check_call( [ - "ssh", - "-i", - self.ssh_keyfile_path(), - "-o", - "StrictHostKeyChecking=accept-new", - self.emu_addr, - "-f", - f"pkgctl repo add url -f 1 -n {self.TEST_REPO_NAME} {repo_url}", + ffx_path, + "target", + "repository", + "register", + "--repository", + self.TEST_REPO_NAME, ], + env=ffx_env, stdout=self.subprocess_output(), stderr=self.subprocess_output(), ) @@ -471,8 +412,8 @@ def start(self): meta/package={package_dir}/meta/package meta/{package_name}.cm={package_dir}/meta/{package_name}.cm bin/{exe_name}={bin_path} - lib/{libstd_name}={rust_dir}/lib/rustlib/{rustlib_dir}/lib/{libstd_name} - lib/{libtest_name}={rust_dir}/lib/rustlib/{rustlib_dir}/lib/{libtest_name} + lib/{libstd_name}={libstd_path} + lib/{libtest_name}={libtest_path} lib/ld.so.1={sdk_dir}/arch/{target_arch}/sysroot/dist/lib/ld.so.1 lib/libfdio.so={sdk_dir}/arch/{target_arch}/dist/libfdio.so """ @@ -502,6 +443,16 @@ def run(self, args): bin_path = os.path.abspath(args.bin_path) + # Find libstd and libtest + libstd_paths = glob.glob(os.path.join(self.rustlibs_dir(), "libstd-*.so")) + libtest_paths = glob.glob(os.path.join(self.rustlibs_dir(), "libtest-*.so")) + + if not libstd_paths: + raise Exception(f"Failed to locate libstd (in {self.rustlibs_dir()})") + + if not libtest_paths: + raise Exception(f"Failed to locate libtest (in {self.rustlibs_dir()})") + # Build a unique, deterministic name for the test using the name of the # binary and the last 6 hex digits of the hash of the full path def path_checksum(path): @@ -604,11 +555,12 @@ def log(msg): exe_name=exe_name, package_dir=package_dir, package_name=package_name, - rust_dir=self.rust_dir, - rustlib_dir=self.target, + target=self.target, sdk_dir=self.sdk_dir, - libstd_name=self.libstd_name, - libtest_name=self.libtest_name, + libstd_name=os.path.basename(libstd_paths[0]), + libtest_name=os.path.basename(libtest_paths[0]), + libstd_path=libstd_paths[0], + libtest_path=libtest_paths[0], target_arch=self.triple_to_arch(self.target), ) ) @@ -779,20 +731,15 @@ def stop(self): else: self.log_debug("No ffx daemon log found") - # Stop package server - self.log_info("Stopping package server...") - os.kill(self.package_server_pid, signal.SIGTERM) - # Shut down the emulator self.log_info("Stopping emulator...") subprocess.check_call( [ - self.tool_path("fvdl"), - "--sdk", - "kill", - "--launched-proto", - self.vdl_output_path(), + self.tool_path("ffx"), + "emu", + "stop", ], + env=self.ffx_cmd_env(), stdout=self.subprocess_output(), stderr=self.subprocess_output(), ) @@ -969,8 +916,8 @@ def print_help(args): "start", help="initializes the testing environment" ) start_parser.add_argument( - "--rust", - help="the directory of the installed Rust compiler for Fuchsia", + "--rust-build", + help="the current compiler build directory (`$RUST_SRC/build` by default)", required=True, ) start_parser.add_argument( diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index 4d97b8c6cb90b..a328c8cbfbbc3 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -681,12 +681,9 @@ local Rust source checkout: cd ${RUST_SRC_PATH} ``` -To run the Rust test suite on an emulated Fuchsia device, you must install the -Rust compiler locally. See "[Targeting Fuchsia with a compiler built from source](#targeting-fuchsia-with-a-compiler-built-from-source)" -for the steps to build locally. - -You'll also need to download a copy of the Fuchsia SDK. The current minimum -supported SDK version is [10.20221207.2.89][minimum_supported_sdk_version]. +To run the Rust test suite on an emulated Fuchsia device, you'll also need to +download a copy of the Fuchsia SDK. The current minimum supported SDK version is +[10.20221207.2.89][minimum_supported_sdk_version]. [minimum_supported_sdk_version]: https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core/linux-amd64/+/version:10.20221207.2.89 @@ -695,13 +692,13 @@ Fuchsia's test runner interacts with the Fuchsia emulator and is located at test environment with: ```sh -src/ci/docker/scripts/fuchsia-test-runner.py start - --rust ${RUST_SRC_PATH}/install - --sdk ${SDK_PATH} - --target {x86_64-unknown-fuchsia|aarch64-unknown-fuchsia} +src/ci/docker/scripts/fuchsia-test-runner.py start \ + --rust ${RUST_SRC_PATH}/build \ + --sdk ${SDK_PATH} \ + --target {x86_64-unknown-fuchsia|aarch64-unknown-fuchsia} \ ``` -Where `${RUST_SRC_PATH}/install` is the `prefix` set in `config.toml` and +Where `${RUST_SRC_PATH}/build` is the `build-dir` set in `config.toml` and `${SDK_PATH}` is the path to the downloaded and unzipped SDK. Once our environment is started, we can run our tests using `x.py` as usual. The From 08d3065fd51db8715b4d4288bb3eff99371e66b6 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Fri, 16 Jun 2023 18:20:24 -0400 Subject: [PATCH 27/37] Fix --rust-build flag in docs --- src/doc/rustc/src/platform-support/fuchsia.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index a328c8cbfbbc3..1b4888b3775f8 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -693,7 +693,7 @@ test environment with: ```sh src/ci/docker/scripts/fuchsia-test-runner.py start \ - --rust ${RUST_SRC_PATH}/build \ + --rust-build ${RUST_SRC_PATH}/build \ --sdk ${SDK_PATH} \ --target {x86_64-unknown-fuchsia|aarch64-unknown-fuchsia} \ ``` @@ -939,3 +939,4 @@ attach and load any relevant debug symbols. [gdb]: https://www.sourceware.org/gdb/ [the zxdb documentation]: https://fuchsia.dev/fuchsia-src/development/debugger [fdio]: https://cs.opensource.google/fuchsia/fuchsia/+/main:sdk/lib/fdio/ +-- From 12c6f1d9588cd8775e13c6e85fa28794613f7446 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Fri, 16 Jun 2023 18:21:11 -0400 Subject: [PATCH 28/37] Fix edit fail --- src/doc/rustc/src/platform-support/fuchsia.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index 1b4888b3775f8..f7cce35b1232b 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -939,4 +939,3 @@ attach and load any relevant debug symbols. [gdb]: https://www.sourceware.org/gdb/ [the zxdb documentation]: https://fuchsia.dev/fuchsia-src/development/debugger [fdio]: https://cs.opensource.google/fuchsia/fuchsia/+/main:sdk/lib/fdio/ --- From 3dc793e625a1b566ca37ba0b12281f9cfb4eb473 Mon Sep 17 00:00:00 2001 From: asquared31415 <34665709+asquared31415@users.noreply.github.com> Date: Thu, 15 Jun 2023 17:45:53 -0400 Subject: [PATCH 29/37] fix ICE on specific malformed asm clobber_abi --- compiler/rustc_builtin_macros/src/asm.rs | 6 +- tests/ui/asm/{x86_64 => }/parse-error.rs | 34 +++- tests/ui/asm/{x86_64 => }/parse-error.stderr | 175 ++++++++++-------- tests/ui/asm/x86_64/x86_64_parse_error.rs | 21 +++ tests/ui/asm/x86_64/x86_64_parse_error.stderr | 44 +++++ 5 files changed, 184 insertions(+), 96 deletions(-) rename tests/ui/asm/{x86_64 => }/parse-error.rs (84%) rename tests/ui/asm/{x86_64 => }/parse-error.stderr (79%) create mode 100644 tests/ui/asm/x86_64/x86_64_parse_error.rs create mode 100644 tests/ui/asm/x86_64/x86_64_parse_error.stderr diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 5217e317adfee..9734fc2b36d94 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -379,16 +379,12 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, } let mut new_abis = Vec::new(); - loop { + while !p.eat(&token::CloseDelim(Delimiter::Parenthesis)) { match p.parse_str_lit() { Ok(str_lit) => { new_abis.push((str_lit.symbol_unescaped, str_lit.span)); } Err(opt_lit) => { - // If the non-string literal is a closing paren then it's the end of the list and is fine - if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) { - break; - } let span = opt_lit.map_or(p.token.span, |lit| lit.span); let mut err = p.sess.span_diagnostic.struct_span_err(span, "expected string literal"); diff --git a/tests/ui/asm/x86_64/parse-error.rs b/tests/ui/asm/parse-error.rs similarity index 84% rename from tests/ui/asm/x86_64/parse-error.rs rename to tests/ui/asm/parse-error.rs index 2e714d464ae74..9e002b1550f34 100644 --- a/tests/ui/asm/x86_64/parse-error.rs +++ b/tests/ui/asm/parse-error.rs @@ -1,4 +1,4 @@ -// only-x86_64 +// needs-asm-support #![feature(asm_const)] @@ -38,6 +38,9 @@ fn main() { //~^ ERROR expected one of asm!("{}", options(), const foo); //~^ ERROR attempt to use a non-constant value in a constant + + // test that asm!'s clobber_abi doesn't accept non-string literals + // see also https://github.com/rust-lang/rust/issues/112635 asm!("", clobber_abi()); //~^ ERROR at least one abi must be provided asm!("", clobber_abi(foo)); @@ -46,6 +49,25 @@ fn main() { //~^ ERROR expected one of `)` or `,`, found `foo` asm!("", clobber_abi("C", foo)); //~^ ERROR expected string literal + asm!("", clobber_abi(1)); + //~^ ERROR expected string literal + asm!("", clobber_abi(())); + //~^ ERROR expected string literal + asm!("", clobber_abi(uwu)); + //~^ ERROR expected string literal + asm!("", clobber_abi({})); + //~^ ERROR expected string literal + asm!("", clobber_abi(loop {})); + //~^ ERROR expected string literal + asm!("", clobber_abi(if)); + //~^ ERROR expected string literal + asm!("", clobber_abi(do)); + //~^ ERROR expected string literal + asm!("", clobber_abi(<)); + //~^ ERROR expected string literal + asm!("", clobber_abi(.)); + //~^ ERROR expected string literal + asm!("{}", clobber_abi("C"), const foo); //~^ ERROR attempt to use a non-constant value in a constant asm!("", options(), clobber_abi("C")); @@ -56,15 +78,7 @@ fn main() { //~^^ ERROR argument never used //~^^^ ERROR attempt to use a non-constant value in a constant //~^^^^ ERROR attempt to use a non-constant value in a constant - asm!("", a = in("eax") foo); - //~^ ERROR explicit register arguments cannot have names - asm!("{a}", in("eax") foo, a = const bar); - //~^ ERROR attempt to use a non-constant value in a constant - asm!("{a}", in("eax") foo, a = const bar); - //~^ ERROR attempt to use a non-constant value in a constant - asm!("{1}", in("eax") foo, const bar); - //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments - //~^^ ERROR attempt to use a non-constant value in a constant + asm!("", options(), ""); //~^ ERROR expected one of asm!("{}", in(reg) foo, "{}", out(reg) foo); diff --git a/tests/ui/asm/x86_64/parse-error.stderr b/tests/ui/asm/parse-error.stderr similarity index 79% rename from tests/ui/asm/x86_64/parse-error.stderr rename to tests/ui/asm/parse-error.stderr index 0c9d6f71529c1..075d28e176ad8 100644 --- a/tests/ui/asm/x86_64/parse-error.stderr +++ b/tests/ui/asm/parse-error.stderr @@ -83,31 +83,85 @@ LL | asm!("", options(nomem, foo)); | ^^^ expected one of 10 possible tokens error: at least one abi must be provided as an argument to `clobber_abi` - --> $DIR/parse-error.rs:41:30 + --> $DIR/parse-error.rs:44:30 | LL | asm!("", clobber_abi()); | ^ error: expected string literal - --> $DIR/parse-error.rs:43:30 + --> $DIR/parse-error.rs:46:30 | LL | asm!("", clobber_abi(foo)); | ^^^ not a string literal error: expected one of `)` or `,`, found `foo` - --> $DIR/parse-error.rs:45:34 + --> $DIR/parse-error.rs:48:34 | LL | asm!("", clobber_abi("C" foo)); | ^^^ expected one of `)` or `,` error: expected string literal - --> $DIR/parse-error.rs:47:35 + --> $DIR/parse-error.rs:50:35 | LL | asm!("", clobber_abi("C", foo)); | ^^^ not a string literal +error: expected string literal + --> $DIR/parse-error.rs:52:30 + | +LL | asm!("", clobber_abi(1)); + | ^ not a string literal + +error: expected string literal + --> $DIR/parse-error.rs:54:30 + | +LL | asm!("", clobber_abi(())); + | ^ not a string literal + +error: expected string literal + --> $DIR/parse-error.rs:56:30 + | +LL | asm!("", clobber_abi(uwu)); + | ^^^ not a string literal + +error: expected string literal + --> $DIR/parse-error.rs:58:30 + | +LL | asm!("", clobber_abi({})); + | ^ not a string literal + +error: expected string literal + --> $DIR/parse-error.rs:60:30 + | +LL | asm!("", clobber_abi(loop {})); + | ^^^^ not a string literal + +error: expected string literal + --> $DIR/parse-error.rs:62:30 + | +LL | asm!("", clobber_abi(if)); + | ^^ not a string literal + +error: expected string literal + --> $DIR/parse-error.rs:64:30 + | +LL | asm!("", clobber_abi(do)); + | ^^ not a string literal + +error: expected string literal + --> $DIR/parse-error.rs:66:30 + | +LL | asm!("", clobber_abi(<)); + | ^ not a string literal + +error: expected string literal + --> $DIR/parse-error.rs:68:30 + | +LL | asm!("", clobber_abi(.)); + | ^ not a string literal + error: duplicate argument named `a` - --> $DIR/parse-error.rs:54:36 + --> $DIR/parse-error.rs:76:36 | LL | asm!("{a}", a = const foo, a = const bar); | ------------- ^^^^^^^^^^^^^ duplicate argument @@ -115,41 +169,27 @@ LL | asm!("{a}", a = const foo, a = const bar); | previously here error: argument never used - --> $DIR/parse-error.rs:54:36 + --> $DIR/parse-error.rs:76:36 | LL | asm!("{a}", a = const foo, a = const bar); | ^^^^^^^^^^^^^ argument never used | = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` -error: explicit register arguments cannot have names - --> $DIR/parse-error.rs:59:18 - | -LL | asm!("", a = in("eax") foo); - | ^^^^^^^^^^^^^^^^^ - -error: positional arguments cannot follow named arguments or explicit register arguments - --> $DIR/parse-error.rs:65:36 - | -LL | asm!("{1}", in("eax") foo, const bar); - | ------------- ^^^^^^^^^ positional argument - | | - | explicit register argument - error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""` - --> $DIR/parse-error.rs:68:29 + --> $DIR/parse-error.rs:82:29 | LL | asm!("", options(), ""); | ^^ expected one of 9 possible tokens error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"` - --> $DIR/parse-error.rs:70:33 + --> $DIR/parse-error.rs:84:33 | LL | asm!("{}", in(reg) foo, "{}", out(reg) foo); | ^^^^ expected one of 9 possible tokens error: asm template must be a string literal - --> $DIR/parse-error.rs:72:14 + --> $DIR/parse-error.rs:86:14 | LL | asm!(format!("{{{}}}", 0), in(reg) foo); | ^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +197,7 @@ LL | asm!(format!("{{{}}}", 0), in(reg) foo); = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: asm template must be a string literal - --> $DIR/parse-error.rs:74:21 + --> $DIR/parse-error.rs:88:21 | LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); | ^^^^^^^^^^^^^^^^^^^^ @@ -165,121 +205,121 @@ LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: _ cannot be used for input operands - --> $DIR/parse-error.rs:76:28 + --> $DIR/parse-error.rs:90:28 | LL | asm!("{}", in(reg) _); | ^ error: _ cannot be used for input operands - --> $DIR/parse-error.rs:78:31 + --> $DIR/parse-error.rs:92:31 | LL | asm!("{}", inout(reg) _); | ^ error: _ cannot be used for input operands - --> $DIR/parse-error.rs:80:35 + --> $DIR/parse-error.rs:94:35 | LL | asm!("{}", inlateout(reg) _); | ^ error: requires at least a template string argument - --> $DIR/parse-error.rs:87:1 + --> $DIR/parse-error.rs:101:1 | LL | global_asm!(); | ^^^^^^^^^^^^^ error: asm template must be a string literal - --> $DIR/parse-error.rs:89:13 + --> $DIR/parse-error.rs:103:13 | LL | global_asm!(FOO); | ^^^ error: expected token: `,` - --> $DIR/parse-error.rs:91:18 + --> $DIR/parse-error.rs:105:18 | LL | global_asm!("{}" FOO); | ^^^ expected `,` error: expected operand, options, or additional template string - --> $DIR/parse-error.rs:93:19 + --> $DIR/parse-error.rs:107:19 | LL | global_asm!("{}", FOO); | ^^^ expected operand, options, or additional template string error: expected expression, found end of macro arguments - --> $DIR/parse-error.rs:95:24 + --> $DIR/parse-error.rs:109:24 | LL | global_asm!("{}", const); | ^ expected expression error: expected one of `,`, `.`, `?`, or an operator, found `FOO` - --> $DIR/parse-error.rs:97:30 + --> $DIR/parse-error.rs:111:30 | LL | global_asm!("{}", const(reg) FOO); | ^^^ expected one of `,`, `.`, `?`, or an operator error: expected one of `)`, `att_syntax`, or `raw`, found `FOO` - --> $DIR/parse-error.rs:99:25 + --> $DIR/parse-error.rs:113:25 | LL | global_asm!("", options(FOO)); | ^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` - --> $DIR/parse-error.rs:101:25 + --> $DIR/parse-error.rs:115:25 | LL | global_asm!("", options(nomem FOO)); | ^^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` - --> $DIR/parse-error.rs:103:25 + --> $DIR/parse-error.rs:117:25 | LL | global_asm!("", options(nomem, FOO)); | ^^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected string literal - --> $DIR/parse-error.rs:106:29 + --> $DIR/parse-error.rs:120:29 | LL | global_asm!("", clobber_abi(FOO)); | ^^^ not a string literal error: expected one of `)` or `,`, found `FOO` - --> $DIR/parse-error.rs:108:33 + --> $DIR/parse-error.rs:122:33 | LL | global_asm!("", clobber_abi("C" FOO)); | ^^^ expected one of `)` or `,` error: expected string literal - --> $DIR/parse-error.rs:110:34 + --> $DIR/parse-error.rs:124:34 | LL | global_asm!("", clobber_abi("C", FOO)); | ^^^ not a string literal error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:112:19 + --> $DIR/parse-error.rs:126:19 | LL | global_asm!("{}", clobber_abi("C"), const FOO); | ^^^^^^^^^^^^^^^^ error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:114:28 + --> $DIR/parse-error.rs:128:28 | LL | global_asm!("", options(), clobber_abi("C")); | ^^^^^^^^^^^^^^^^ error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:116:30 + --> $DIR/parse-error.rs:130:30 | LL | global_asm!("{}", options(), clobber_abi("C"), const FOO); | ^^^^^^^^^^^^^^^^ error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:118:17 + --> $DIR/parse-error.rs:132:17 | LL | global_asm!("", clobber_abi("C"), clobber_abi("C")); | ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ error: duplicate argument named `a` - --> $DIR/parse-error.rs:120:35 + --> $DIR/parse-error.rs:134:35 | LL | global_asm!("{a}", a = const FOO, a = const BAR); | ------------- ^^^^^^^^^^^^^ duplicate argument @@ -287,7 +327,7 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR); | previously here error: argument never used - --> $DIR/parse-error.rs:120:35 + --> $DIR/parse-error.rs:134:35 | LL | global_asm!("{a}", a = const FOO, a = const BAR); | ^^^^^^^^^^^^^ argument never used @@ -295,19 +335,19 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `""` - --> $DIR/parse-error.rs:123:28 + --> $DIR/parse-error.rs:137:28 | LL | global_asm!("", options(), ""); | ^^ expected one of `clobber_abi`, `const`, `options`, or `sym` error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `"{}"` - --> $DIR/parse-error.rs:125:30 + --> $DIR/parse-error.rs:139:30 | LL | global_asm!("{}", const FOO, "{}", const FOO); | ^^^^ expected one of `clobber_abi`, `const`, `options`, or `sym` error: asm template must be a string literal - --> $DIR/parse-error.rs:127:13 + --> $DIR/parse-error.rs:141:13 | LL | global_asm!(format!("{{{}}}", 0), const FOO); | ^^^^^^^^^^^^^^^^^^^^ @@ -315,7 +355,7 @@ LL | global_asm!(format!("{{{}}}", 0), const FOO); = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: asm template must be a string literal - --> $DIR/parse-error.rs:129:20 + --> $DIR/parse-error.rs:143:20 | LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); | ^^^^^^^^^^^^^^^^^^^^ @@ -332,7 +372,7 @@ LL | asm!("{}", options(), const foo); | ^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:49:44 + --> $DIR/parse-error.rs:71:44 | LL | let mut foo = 0; | ----------- help: consider using `const` instead of `let`: `const foo` @@ -341,7 +381,7 @@ LL | asm!("{}", clobber_abi("C"), const foo); | ^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:52:55 + --> $DIR/parse-error.rs:74:55 | LL | let mut foo = 0; | ----------- help: consider using `const` instead of `let`: `const foo` @@ -350,7 +390,7 @@ LL | asm!("{}", options(), clobber_abi("C"), const foo); | ^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:54:31 + --> $DIR/parse-error.rs:76:31 | LL | let mut foo = 0; | ----------- help: consider using `const` instead of `let`: `const foo` @@ -359,7 +399,7 @@ LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:54:46 + --> $DIR/parse-error.rs:76:46 | LL | let mut bar = 0; | ----------- help: consider using `const` instead of `let`: `const bar` @@ -367,33 +407,6 @@ LL | let mut bar = 0; LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value -error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:61:46 - | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... -LL | asm!("{a}", in("eax") foo, a = const bar); - | ^^^ non-constant value - -error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:63:46 - | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... -LL | asm!("{a}", in("eax") foo, a = const bar); - | ^^^ non-constant value - -error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:65:42 - | -LL | let mut bar = 0; - | ----------- help: consider using `const` instead of `let`: `const bar` -... -LL | asm!("{1}", in("eax") foo, const bar); - | ^^^ non-constant value - -error: aborting due to 59 previous errors +error: aborting due to 63 previous errors For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/asm/x86_64/x86_64_parse_error.rs b/tests/ui/asm/x86_64/x86_64_parse_error.rs new file mode 100644 index 0000000000000..715a67687d124 --- /dev/null +++ b/tests/ui/asm/x86_64/x86_64_parse_error.rs @@ -0,0 +1,21 @@ +// only-x86_64 + +#![feature(asm_const)] + +use std::arch::asm; + +fn main() { + let mut foo = 0; + let mut bar = 0; + unsafe { + asm!("", a = in("eax") foo); + //~^ ERROR explicit register arguments cannot have names + asm!("{a}", in("eax") foo, a = const bar); + //~^ ERROR attempt to use a non-constant value in a constant + asm!("{a}", in("eax") foo, a = const bar); + //~^ ERROR attempt to use a non-constant value in a constant + asm!("{1}", in("eax") foo, const bar); + //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments + //~^^ ERROR attempt to use a non-constant value in a constant + } +} diff --git a/tests/ui/asm/x86_64/x86_64_parse_error.stderr b/tests/ui/asm/x86_64/x86_64_parse_error.stderr new file mode 100644 index 0000000000000..f2854ae512851 --- /dev/null +++ b/tests/ui/asm/x86_64/x86_64_parse_error.stderr @@ -0,0 +1,44 @@ +error: explicit register arguments cannot have names + --> $DIR/x86_64_parse_error.rs:11:18 + | +LL | asm!("", a = in("eax") foo); + | ^^^^^^^^^^^^^^^^^ + +error: positional arguments cannot follow named arguments or explicit register arguments + --> $DIR/x86_64_parse_error.rs:17:36 + | +LL | asm!("{1}", in("eax") foo, const bar); + | ------------- ^^^^^^^^^ positional argument + | | + | explicit register argument + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/x86_64_parse_error.rs:13:46 + | +LL | let mut bar = 0; + | ----------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{a}", in("eax") foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/x86_64_parse_error.rs:15:46 + | +LL | let mut bar = 0; + | ----------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{a}", in("eax") foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/x86_64_parse_error.rs:17:42 + | +LL | let mut bar = 0; + | ----------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{1}", in("eax") foo, const bar); + | ^^^ non-constant value + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0435`. From 3eddb2955578f6216ec8cbfce238f0286ff775bf Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 17 Jun 2023 14:38:51 +1000 Subject: [PATCH 30/37] Add `` to `-Zdump-mir-spanview` output --- compiler/rustc_middle/src/mir/spanview.rs | 5 +++-- tests/mir-opt/spanview_block.main.built.after.html | 3 ++- tests/mir-opt/spanview_statement.main.built.after.html | 3 ++- tests/mir-opt/spanview_terminator.main.built.after.html | 3 ++- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs index 6b03619438189..730c551576acd 100644 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ b/compiler/rustc_middle/src/mir/spanview.rs @@ -15,8 +15,9 @@ const ANNOTATION_LEFT_BRACKET: char = '\u{298a}'; // Unicode `Z NOTATION RIGHT B const ANNOTATION_RIGHT_BRACKET: char = '\u{2989}'; // Unicode `Z NOTATION LEFT BINDING BRACKET` const NEW_LINE_SPAN: &str = "\n"; const HEADER: &str = r#" - -"#; + + +"#; const START_BODY: &str = r#" "#; const FOOTER: &str = r#" diff --git a/tests/mir-opt/spanview_block.main.built.after.html b/tests/mir-opt/spanview_block.main.built.after.html index b962d80c59e52..56f4e4f93706e 100644 --- a/tests/mir-opt/spanview_block.main.built.after.html +++ b/tests/mir-opt/spanview_block.main.built.after.html @@ -1,6 +1,7 @@ - + + spanview_block.main.built.after