diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 91252ae6727ce..560d39403d4e0 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1432,17 +1432,26 @@ impl CrateMetadata { .attributes .get(self, id) .unwrap_or_else(|| { - // Structure and variant constructors don't have any attributes encoded for them, - // but we assume that someone passing a constructor ID actually wants to look at - // the attributes on the corresponding struct or variant. let def_key = self.def_key(id); - assert_eq!(def_key.disambiguated_data.data, DefPathData::Ctor); - let parent_id = def_key.parent.expect("no parent for a constructor"); - self.root - .tables - .attributes - .get(self, parent_id) - .expect("no encoded attributes for a structure or variant") + match def_key.disambiguated_data.data { + DefPathData::Ctor => { + // Structure and variant constructors don't have any attributes encoded for them, + // but we assume that someone passing a constructor ID actually wants to look at + // the attributes on the corresponding struct or variant. + assert_eq!(def_key.disambiguated_data.data, DefPathData::Ctor); + let parent_id = def_key.parent.expect("no parent for a constructor"); + self.root + .tables + .attributes + .get(self, parent_id) + .expect("no encoded attributes for a structure or variant") + } + DefPathData::SyntheticCoroutineBody => { + // SyntheticCoroutineBodies cannot have attributes + LazyArray::default() + } + _ => panic!("Definition key {def_key:?} of type `{:?}` did not have any attributes stored", def_key.disambiguated_data.data) + } }) .decode((self, tcx)) } diff --git a/src/tools/miri/tests/deps/Cargo.lock b/src/tools/miri/tests/deps/Cargo.lock index 4691588eefb40..c59b729e5eeca 100644 --- a/src/tools/miri/tests/deps/Cargo.lock +++ b/src/tools/miri/tests/deps/Cargo.lock @@ -32,6 +32,13 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cross-crate-items" +version = "0.1.0" +dependencies = [ + "futures", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -290,6 +297,7 @@ dependencies = [ name = "miri-test-deps" version = "0.1.0" dependencies = [ + "cross-crate-items", "futures", "getrandom 0.1.16", "getrandom 0.2.17", diff --git a/src/tools/miri/tests/deps/Cargo.toml b/src/tools/miri/tests/deps/Cargo.toml index bbbcc316f31c2..a377141f98aaf 100644 --- a/src/tools/miri/tests/deps/Cargo.toml +++ b/src/tools/miri/tests/deps/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] # all dependencies (and their transitive ones) listed here can be used in `tests/*-dep`. +cross-crate-items = { path = "cross-crate-items" } # Used to test things that need multiple crates to check libc = "0.2" num_cpus = "1.10.1" @@ -35,3 +36,4 @@ windows-sys = { version = "0.61", features = [ # Make sure we are not part of the rustc workspace. [workspace] +members = ["cross-crate-items"] diff --git a/src/tools/miri/tests/deps/cross-crate-items/Cargo.toml b/src/tools/miri/tests/deps/cross-crate-items/Cargo.toml new file mode 100644 index 0000000000000..1f9fc93cd5237 --- /dev/null +++ b/src/tools/miri/tests/deps/cross-crate-items/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "cross-crate-items" +version = "0.1.0" +edition = "2021" + +[dependencies] +futures = { version = "0.3.0", default-features = false, features = ["alloc", "async-await"] } diff --git a/src/tools/miri/tests/deps/cross-crate-items/src/lib.rs b/src/tools/miri/tests/deps/cross-crate-items/src/lib.rs new file mode 100644 index 0000000000000..8f462d5b515f1 --- /dev/null +++ b/src/tools/miri/tests/deps/cross-crate-items/src/lib.rs @@ -0,0 +1,5 @@ +/// Async closure in an external crate — required because decoder.rs is only called for +/// defs loaded from .rmeta files, not local crate defs. +pub fn returns_async_closure() -> impl futures::Sink<(), Error = std::io::Error> { + futures::sink::unfold((), async |(), ()| Ok::<_, std::io::Error>(())) +} diff --git a/src/tools/miri/tests/pass-dep/cross_crate_async_closure_ice.rs b/src/tools/miri/tests/pass-dep/cross_crate_async_closure_ice.rs new file mode 100644 index 0000000000000..d09ff7c77c9a4 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/cross_crate_async_closure_ice.rs @@ -0,0 +1,26 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes + +// This is a regression test for a Miri ICE when encountering a `SyntheticCoroutineBody` from an external crate (see +// `cross_crate_items` for details). Calling the async closure triggered the ICE: https://github.com/rust-lang/rust/issues/156905 + +use std::future::Future; +use std::task::{Context, Poll, Waker}; + +use futures::SinkExt as _; + +// Taken from tests/pass/async-fn.rs. +fn run_fut(fut: impl Future) -> T { + let mut context = Context::from_waker(Waker::noop()); + let mut pinned = Box::pin(fut); + loop { + match pinned.as_mut().poll(&mut context) { + Poll::Pending => continue, + Poll::Ready(v) => return v, + } + } +} + +fn main() { + let mut sink = Box::pin(cross_crate_items::returns_async_closure()); + run_fut(sink.send(())).unwrap(); +}