diff options
715 files changed, 12472 insertions, 6890 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cf85591ac01..e97cd29bba5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -290,8 +290,8 @@ jobs: os: ubuntu-20.04-xl - name: dist-x86_64-apple env: - SCRIPT: "./x.py dist --exclude rust-docs --exclude extended && ./x.py dist --target=x86_64-apple-darwin rust-docs && ./x.py dist extended" - RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" + SCRIPT: "./x.py dist --host=x86_64-apple-darwin --target=x86_64-apple-darwin" + RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 MACOSX_DEPLOYMENT_TARGET: 10.7 NO_LLVM_ASSERTIONS: 1 @@ -299,6 +299,16 @@ jobs: NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 os: macos-latest + - name: dist-apple-various + env: + SCRIPT: "./x.py dist --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim" + RUST_CONFIGURE_ARGS: "--enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + NO_OVERFLOW_CHECKS: 1 + os: macos-latest - name: dist-x86_64-apple-alt env: SCRIPT: "./x.py dist" diff --git a/Cargo.lock b/Cargo.lock index 1e7c9ee029b..b05351a1e96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -379,7 +379,7 @@ dependencies = [ "tar", "tempfile", "termcolor", - "toml", + "toml_edit", "unicode-width", "unicode-xid", "url 2.2.2", @@ -465,7 +465,7 @@ dependencies = [ "serde_json", "tar", "termcolor", - "toml", + "toml_edit", "url 2.2.2", ] @@ -689,7 +689,7 @@ dependencies = [ "clippy_utils", "if_chain", "itertools 0.10.1", - "pulldown-cmark 0.9.0", + "pulldown-cmark", "quine-mc_cluskey", "regex-syntax", "rustc-semver", @@ -732,6 +732,16 @@ dependencies = [ ] [[package]] +name = "combine" +version = "4.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50b727aacc797f9fc28e355d21f34709ac4fc9adecfe470ad07b8f4464f53062" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] name = "commoncrypto" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1463,7 +1473,7 @@ checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ "cfg-if 0.1.10", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] @@ -1474,7 +1484,7 @@ checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" dependencies = [ "cfg-if 0.1.10", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] @@ -1587,6 +1597,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758" +dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", @@ -1731,12 +1749,13 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.11.2", + "rustc-rayon", "serde", ] @@ -1945,6 +1964,15 @@ dependencies = [ ] [[package]] +name = "kstring" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b310ccceade8121d7d77fee406160e457c2f4e7c7982d589da3499bc7ea4526" +dependencies = [ + "serde", +] + +[[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1958,9 +1986,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.108" +version = "0.2.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119" +checksum = "565dbd88872dbe4cc8a46e527f26483c1d1f7afa6b884a3bd6cd893d4f98da74" dependencies = [ "rustc-std-workspace-core", ] @@ -2186,9 +2214,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e77253c46a90eb7e96b2807201dab941a4db5ea05eca5aaaf7027395f352b3" +checksum = "241f10687eb3b4e0634b3b4e423f97c5f1efbd69dc9522e24a8b94583eeec3c6" dependencies = [ "ammonia", "anyhow", @@ -2201,7 +2229,7 @@ dependencies = [ "log", "memchr", "opener", - "pulldown-cmark 0.8.0", + "pulldown-cmark", "regex", "serde", "serde_derive", @@ -2270,9 +2298,9 @@ dependencies = [ [[package]] name = "minifier" -version = "0.0.41" +version = "0.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5594542d20834f2b974f5e5fb8e0cf1c67a2119dcadc29ef5d93a081fb30cc08" +checksum = "55a1388517eda8a68875243b650c26997e055a33d82571b5a0349129faef7d99" dependencies = [ "macro-utils", ] @@ -2411,7 +2439,7 @@ checksum = "7ce8b38d41f9f3618fc23f908faae61510f8d8ce2d99cbe910641e8f1971f084" dependencies = [ "crc32fast", "flate2", - "hashbrown", + "hashbrown 0.11.2", "indexmap", "memchr", ] @@ -2865,9 +2893,9 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" +checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6" dependencies = [ "bitflags", "getopts", @@ -2876,17 +2904,6 @@ dependencies = [ ] [[package]] -name = "pulldown-cmark" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd16514d1af5f7a71f909a44ef253cdb712a376d7ebc8ae4a471a9be9743548" -dependencies = [ - "bitflags", - "memchr", - "unicase", -] - -[[package]] name = "punycode" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3302,7 +3319,6 @@ dependencies = [ "rustc_codegen_ssa", "rustc_driver", "tikv-jemalloc-sys", - "tikv-jemallocator", ] [[package]] @@ -4440,7 +4456,7 @@ dependencies = [ "expect-test", "itertools 0.9.0", "minifier", - "pulldown-cmark 0.9.0", + "pulldown-cmark", "rayon", "regex", "rustdoc-json-types", @@ -4825,7 +4841,7 @@ dependencies = [ "core", "dlmalloc", "fortanix-sgx-abi", - "hashbrown", + "hashbrown 0.12.0", "hermit-abi", "libc", "miniz_oxide", @@ -4837,7 +4853,7 @@ dependencies = [ "rustc-demangle", "std_detect", "unwind", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] @@ -5107,7 +5123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd95b4559c196987c8451b4e14d08a4c796c2844f9adf4d2a2dbc9b3142843be" dependencies = [ "gimli 0.26.1", - "hashbrown", + "hashbrown 0.11.2", "object 0.28.1", "tracing", ] @@ -5148,16 +5164,6 @@ dependencies = [ ] [[package]] -name = "tikv-jemallocator" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c14a5a604eb8715bc5785018a37d00739b180bcf609916ddf4393d33d49ccdf" -dependencies = [ - "libc", - "tikv-jemalloc-sys", -] - -[[package]] name = "time" version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5226,6 +5232,19 @@ dependencies = [ ] [[package]] +name = "toml_edit" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b80ac5e1b91e3378c63dab121962472b5ca20cf9ab1975e3d588548717807a8" +dependencies = [ + "combine", + "indexmap", + "itertools 0.10.1", + "kstring", + "serde", +] + +[[package]] name = "topological-sort" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5582,6 +5601,12 @@ name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", diff --git a/RELEASES.md b/RELEASES.md index f44291c1fa3..aae2a669650 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -7,7 +7,7 @@ Version 1.58.1 (2022-01-19) * [Fix wrong error message displayed when some imports are missing][91254] * [Fix rustfmt not formatting generated files from stdin][92912] -[CVE-2022-21658]: https://www.cve.org/CVERecord?id=CVE-2022-21658] +[CVE-2022-21658]: https://www.cve.org/CVERecord?id=CVE-2022-21658 [91254]: https://github.com/rust-lang/rust/pull/91254 [92912]: https://github.com/rust-lang/rust/pull/92912 [clippy/8075]: https://github.com/rust-lang/rust-clippy/pull/8075 diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml index 277cf0f51d3..696c003a587 100644 --- a/compiler/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -15,11 +15,7 @@ version = '0.4.0' optional = true features = ['unprefixed_malloc_on_supported_platforms'] -[dependencies.tikv-jemallocator] -version = '0.4.0' -optional = true - [features] -jemalloc = ['tikv-jemalloc-sys', 'tikv-jemallocator'] +jemalloc = ['tikv-jemalloc-sys'] llvm = ['rustc_driver/llvm'] max_level_info = ['rustc_driver/max_level_info'] diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 6f9ecb9cd21..3928d70c0ed 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -45,24 +45,24 @@ pub struct TypedArena<T> { end: Cell<*mut T>, /// A vector of arena chunks. - chunks: RefCell<Vec<TypedArenaChunk<T>>>, + chunks: RefCell<Vec<ArenaChunk<T>>>, /// Marker indicating that dropping the arena causes its owned /// instances of `T` to be dropped. _own: PhantomData<T>, } -struct TypedArenaChunk<T> { +struct ArenaChunk<T = u8> { /// The raw storage for the arena chunk. storage: Box<[MaybeUninit<T>]>, /// The number of valid entries in the chunk. entries: usize, } -impl<T> TypedArenaChunk<T> { +impl<T> ArenaChunk<T> { #[inline] - unsafe fn new(capacity: usize) -> TypedArenaChunk<T> { - TypedArenaChunk { storage: Box::new_uninit_slice(capacity), entries: 0 } + unsafe fn new(capacity: usize) -> ArenaChunk<T> { + ArenaChunk { storage: Box::new_uninit_slice(capacity), entries: 0 } } /// Destroys this arena chunk. @@ -125,6 +125,11 @@ impl<I, T> IterExt<T> for I where I: IntoIterator<Item = T>, { + // This default collects into a `SmallVec` and then allocates by copying + // from it. The specializations below for types like `Vec` are more + // efficient, copying directly without the intermediate collecting step. + // This default could be made more efficient, like + // `DroplessArena::alloc_from_iter`, but it's not hot enough to bother. #[inline] default fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T] { let vec: SmallVec<[_; 8]> = self.into_iter().collect(); @@ -139,7 +144,7 @@ impl<T, const N: usize> IterExt<T> for std::array::IntoIter<T, N> { if len == 0 { return &mut []; } - // Move the content to the arena by copying and then forgetting it + // Move the content to the arena by copying and then forgetting it. unsafe { let start_ptr = arena.alloc_raw_slice(len); self.as_slice().as_ptr().copy_to_nonoverlapping(start_ptr, len); @@ -156,7 +161,7 @@ impl<T> IterExt<T> for Vec<T> { if len == 0 { return &mut []; } - // Move the content to the arena by copying and then forgetting it + // Move the content to the arena by copying and then forgetting it. unsafe { let start_ptr = arena.alloc_raw_slice(len); self.as_ptr().copy_to_nonoverlapping(start_ptr, len); @@ -173,7 +178,7 @@ impl<A: smallvec::Array> IterExt<A::Item> for SmallVec<A> { if len == 0 { return &mut []; } - // Move the content to the arena by copying and then forgetting it + // Move the content to the arena by copying and then forgetting it. unsafe { let start_ptr = arena.alloc_raw_slice(len); self.as_ptr().copy_to_nonoverlapping(start_ptr, len); @@ -272,7 +277,7 @@ impl<T> TypedArena<T> { // Also ensure that this chunk can fit `additional`. new_cap = cmp::max(additional, new_cap); - let mut chunk = TypedArenaChunk::<T>::new(new_cap); + let mut chunk = ArenaChunk::<T>::new(new_cap); self.ptr.set(chunk.start()); self.end.set(chunk.end()); chunks.push(chunk); @@ -281,7 +286,7 @@ impl<T> TypedArena<T> { // Drops the contents of the last chunk. The last chunk is partially empty, unlike all other // chunks. - fn clear_last_chunk(&self, last_chunk: &mut TypedArenaChunk<T>) { + fn clear_last_chunk(&self, last_chunk: &mut ArenaChunk<T>) { // Determine how much was filled. let start = last_chunk.start() as usize; // We obtain the value of the pointer to the first uninitialized element. @@ -340,7 +345,7 @@ pub struct DroplessArena { end: Cell<*mut u8>, /// A vector of arena chunks. - chunks: RefCell<Vec<TypedArenaChunk<u8>>>, + chunks: RefCell<Vec<ArenaChunk>>, } unsafe impl Send for DroplessArena {} @@ -378,7 +383,7 @@ impl DroplessArena { // Also ensure that this chunk can fit `additional`. new_cap = cmp::max(additional, new_cap); - let mut chunk = TypedArenaChunk::<u8>::new(new_cap); + let mut chunk = ArenaChunk::new(new_cap); self.start.set(chunk.start()); self.end.set(chunk.end()); chunks.push(chunk); @@ -520,10 +525,19 @@ impl DroplessArena { } } -// Declare an `Arena` containing one dropless arena and many typed arenas (the -// types of the typed arenas are specified by the arguments). The dropless -// arena will be used for any types that impl `Copy`, and also for any of the -// specified types that satisfy `!mem::needs_drop`. +/// Declare an `Arena` containing one dropless arena and many typed arenas (the +/// types of the typed arenas are specified by the arguments). +/// +/// There are three cases of interest. +/// - Types that are `Copy`: these need not be specified in the arguments. They +/// will use the `DroplessArena`. +/// - Types that are `!Copy` and `!Drop`: these must be specified in the +/// arguments. An empty `TypedArena` will be created for each one, but the +/// `DroplessArena` will always be used and the `TypedArena` will stay empty. +/// This is odd but harmless, because an empty arena allocates no memory. +/// - Types that are `!Copy` and `Drop`: these must be specified in the +/// arguments. The `TypedArena` will be used for them. +/// #[rustc_macro_transparency = "semitransparent"] pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { #[derive(Default)] @@ -532,7 +546,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { $($name: $crate::TypedArena<$ty>,)* } - pub trait ArenaAllocatable<'tcx, T = Self>: Sized { + pub trait ArenaAllocatable<'tcx, C = rustc_arena::IsNotCopy>: Sized { fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self; fn allocate_from_iter<'a>( arena: &'a Arena<'tcx>, @@ -541,7 +555,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { } // Any type that impls `Copy` can be arena-allocated in the `DroplessArena`. - impl<'tcx, T: Copy> ArenaAllocatable<'tcx, ()> for T { + impl<'tcx, T: Copy> ArenaAllocatable<'tcx, rustc_arena::IsCopy> for T { #[inline] fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self { arena.dropless.alloc(self) @@ -555,7 +569,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { } } $( - impl<'tcx> ArenaAllocatable<'tcx, $ty> for $ty { + impl<'tcx> ArenaAllocatable<'tcx, rustc_arena::IsNotCopy> for $ty { #[inline] fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self { if !::std::mem::needs_drop::<Self>() { @@ -581,7 +595,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { impl<'tcx> Arena<'tcx> { #[inline] - pub fn alloc<T: ArenaAllocatable<'tcx, U>, U>(&self, value: T) -> &mut T { + pub fn alloc<T: ArenaAllocatable<'tcx, C>, C>(&self, value: T) -> &mut T { value.allocate_on(self) } @@ -594,7 +608,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { self.dropless.alloc_slice(value) } - pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, U>, U>( + pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, C>, C>( &'a self, iter: impl ::std::iter::IntoIterator<Item = T>, ) -> &'a mut [T] { @@ -603,5 +617,10 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { } } +// Marker types that let us give different behaviour for arenas allocating +// `Copy` types vs `!Copy` types. +pub struct IsCopy; +pub struct IsNotCopy; + #[cfg(test)] mod tests; diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 438168f4fcc..7c19559ed91 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2418,8 +2418,9 @@ impl<S: Encoder> rustc_serialize::Encodable<S> for AttrId { } impl<D: Decoder> rustc_serialize::Decodable<D> for AttrId { - fn decode(d: &mut D) -> Result<AttrId, D::Error> { - d.read_nil().map(|_| crate::attr::mk_attr_id()) + fn decode(d: &mut D) -> AttrId { + d.read_unit(); + crate::attr::mk_attr_id() } } diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs index 9fe87a0a637..70dbda82224 100644 --- a/compiler/rustc_ast/src/ptr.rs +++ b/compiler/rustc_ast/src/ptr.rs @@ -115,8 +115,8 @@ impl<T> fmt::Pointer for P<T> { } impl<D: Decoder, T: 'static + Decodable<D>> Decodable<D> for P<T> { - fn decode(d: &mut D) -> Result<P<T>, D::Error> { - Decodable::decode(d).map(P) + fn decode(d: &mut D) -> P<T> { + P(Decodable::decode(d)) } } @@ -204,8 +204,8 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for P<[T]> { } impl<D: Decoder, T: Decodable<D>> Decodable<D> for P<[T]> { - fn decode(d: &mut D) -> Result<P<[T]>, D::Error> { - Ok(P::from_vec(Decodable::decode(d)?)) + fn decode(d: &mut D) -> P<[T]> { + P::from_vec(Decodable::decode(d)) } } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 51cabb50cd3..2174378a560 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -163,7 +163,7 @@ impl<S: Encoder> Encodable<S> for LazyTokenStream { } impl<D: Decoder> Decodable<D> for LazyTokenStream { - fn decode(_d: &mut D) -> Result<Self, D::Error> { + fn decode(_d: &mut D) -> Self { panic!("Attempted to decode LazyTokenStream"); } } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index f04dc85b28a..17bc8d7591b 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -625,18 +625,18 @@ impl<'hir> LoweringContext<'_, 'hir> { /// } /// } /// ``` - fn lower_expr_await(&mut self, await_span: Span, expr: &Expr) -> hir::ExprKind<'hir> { - let dot_await_span = expr.span.shrink_to_hi().to(await_span); + fn lower_expr_await(&mut self, dot_await_span: Span, expr: &Expr) -> hir::ExprKind<'hir> { + let full_span = expr.span.to(dot_await_span); match self.generator_kind { Some(hir::GeneratorKind::Async(_)) => {} Some(hir::GeneratorKind::Gen) | None => { let mut err = struct_span_err!( self.sess, - await_span, + dot_await_span, E0728, "`await` is only allowed inside `async` functions and blocks" ); - err.span_label(await_span, "only allowed inside `async` functions and blocks"); + err.span_label(dot_await_span, "only allowed inside `async` functions and blocks"); if let Some(item_sp) = self.current_item { err.span_label(item_sp, "this is not `async`"); } @@ -646,7 +646,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let span = self.mark_span_with_reason(DesugaringKind::Await, dot_await_span, None); let gen_future_span = self.mark_span_with_reason( DesugaringKind::Await, - await_span, + full_span, self.allow_gen_future.clone(), ); let expr = self.lower_expr_mut(expr); @@ -699,9 +699,9 @@ impl<'hir> LoweringContext<'_, 'hir> { let loop_hir_id = self.lower_node_id(loop_node_id); let ready_arm = { let x_ident = Ident::with_dummy_span(sym::result); - let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident); - let x_expr = self.expr_ident(span, x_ident, x_pat_hid); - let ready_field = self.single_pat_field(span, x_pat); + let (x_pat, x_pat_hid) = self.pat_ident(gen_future_span, x_ident); + let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid); + let ready_field = self.single_pat_field(gen_future_span, x_pat); let ready_pat = self.pat_lang_item_variant( span, hir::LangItem::PollReady, @@ -711,7 +711,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let break_x = self.with_loop_scope(loop_node_id, move |this| { let expr_break = hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr)); - this.arena.alloc(this.expr(span, expr_break, ThinVec::new())) + this.arena.alloc(this.expr(gen_future_span, expr_break, ThinVec::new())) }); self.arm(ready_pat, break_x) }; @@ -783,7 +783,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // `match ::std::future::IntoFuture::into_future(<expr>) { ... }` let into_future_span = self.mark_span_with_reason( DesugaringKind::Await, - await_span, + dot_await_span, self.allow_into_future.clone(), ); let into_future_expr = self.expr_call_lang_item_fn( diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 47b61067055..32cec3a295a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -479,6 +479,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let attrs = std::mem::take(&mut self.attrs); let mut bodies = std::mem::take(&mut self.bodies); let local_node_ids = std::mem::take(&mut self.local_node_ids); + + let local_id_to_def_id = local_node_ids + .iter() + .filter_map(|&node_id| { + let hir_id = self.node_id_to_hir_id[node_id]?; + if hir_id.local_id == hir::ItemLocalId::new(0) { + None + } else { + let def_id = self.resolver.opt_local_def_id(node_id)?; + Some((hir_id.local_id, def_id)) + } + }) + .collect(); + let trait_map = local_node_ids .into_iter() .filter_map(|node_id| { @@ -501,7 +515,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies); let (nodes, parenting) = index::index_hir(self.sess, self.resolver.definitions(), node, &bodies); - let nodes = hir::OwnerNodes { hash_including_bodies, hash_without_bodies, nodes, bodies }; + let nodes = hir::OwnerNodes { + hash_including_bodies, + hash_without_bodies, + nodes, + bodies, + local_id_to_def_id, + }; let attrs = { let mut hcx = self.resolver.create_stable_hashing_context(); let mut stable_hasher = StableHasher::new(); diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs index 82c40868d18..e1f43cb20dc 100644 --- a/compiler/rustc_ast_pretty/src/pp.rs +++ b/compiler/rustc_ast_pretty/src/pp.rs @@ -147,6 +147,22 @@ pub enum Breaks { } #[derive(Clone, Copy)] +enum IndentStyle { + /// Vertically aligned under whatever column this block begins at. + /// + /// fn demo(arg1: usize, + /// arg2: usize); + Visual, + /// Indented relative to the indentation level of the previous line. + /// + /// fn demo( + /// arg1: usize, + /// arg2: usize, + /// ); + Block { offset: isize }, +} + +#[derive(Clone, Copy)] pub struct BreakToken { offset: isize, blank_space: isize, @@ -154,7 +170,7 @@ pub struct BreakToken { #[derive(Clone, Copy)] pub struct BeginToken { - offset: isize, + indent: IndentStyle, breaks: Breaks, } @@ -178,7 +194,7 @@ impl Token { #[derive(Copy, Clone)] enum PrintFrame { Fits, - Broken { offset: isize, breaks: Breaks }, + Broken { indent: usize, breaks: Breaks }, } const SIZE_INFINITY: isize = 0xffff; @@ -204,6 +220,8 @@ pub struct Printer { scan_stack: VecDeque<usize>, /// Stack of blocks-in-progress being flushed by print print_stack: Vec<PrintFrame>, + /// Level of indentation of current line + indent: usize, /// Buffered indentation to avoid writing trailing whitespace pending_indentation: isize, /// The token most recently popped from the left boundary of the @@ -229,6 +247,7 @@ impl Printer { right_total: 0, scan_stack: VecDeque::new(), print_stack: Vec::new(), + indent: 0, pending_indentation: 0, last_printed: None, } @@ -368,38 +387,41 @@ impl Printer { *self .print_stack .last() - .unwrap_or(&PrintFrame::Broken { offset: 0, breaks: Breaks::Inconsistent }) + .unwrap_or(&PrintFrame::Broken { indent: 0, breaks: Breaks::Inconsistent }) } fn print_begin(&mut self, token: BeginToken, size: isize) { if size > self.space { - let col = self.margin - self.space + token.offset; - self.print_stack.push(PrintFrame::Broken { offset: col, breaks: token.breaks }); + self.print_stack.push(PrintFrame::Broken { indent: self.indent, breaks: token.breaks }); + self.indent = match token.indent { + IndentStyle::Block { offset } => (self.indent as isize + offset) as usize, + IndentStyle::Visual => (self.margin - self.space) as usize, + }; } else { self.print_stack.push(PrintFrame::Fits); } } fn print_end(&mut self) { - self.print_stack.pop().unwrap(); + if let PrintFrame::Broken { indent, .. } = self.print_stack.pop().unwrap() { + self.indent = indent; + } } fn print_break(&mut self, token: BreakToken, size: isize) { - let break_offset = - match self.get_top() { - PrintFrame::Fits => None, - PrintFrame::Broken { offset, breaks: Breaks::Consistent } => Some(offset), - PrintFrame::Broken { offset, breaks: Breaks::Inconsistent } => { - if size > self.space { Some(offset) } else { None } - } - }; - if let Some(offset) = break_offset { - self.out.push('\n'); - self.pending_indentation = offset + token.offset; - self.space = self.margin - (offset + token.offset); - } else { + let fits = match self.get_top() { + PrintFrame::Fits => true, + PrintFrame::Broken { breaks: Breaks::Consistent, .. } => false, + PrintFrame::Broken { breaks: Breaks::Inconsistent, .. } => size <= self.space, + }; + if fits { self.pending_indentation += token.blank_space; self.space -= token.blank_space; + } else { + self.out.push('\n'); + let indent = self.indent as isize + token.offset; + self.pending_indentation = indent; + self.space = self.margin - indent; } } @@ -422,7 +444,10 @@ impl Printer { /// "raw box" pub fn rbox(&mut self, indent: usize, breaks: Breaks) { - self.scan_begin(BeginToken { offset: indent as isize, breaks }) + self.scan_begin(BeginToken { + indent: IndentStyle::Block { offset: indent as isize }, + breaks, + }) } /// Inconsistent breaking box @@ -435,6 +460,10 @@ impl Printer { self.rbox(indent, Breaks::Consistent) } + pub fn visual_align(&mut self) { + self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent }); + } + pub fn break_offset(&mut self, n: usize, off: isize) { self.scan_break(BreakToken { offset: off, blank_space: n as isize }) } @@ -457,7 +486,7 @@ impl Printer { self.break_offset(n, 0) } - crate fn zerobreak(&mut self) { + pub fn zerobreak(&mut self) { self.spaces(0) } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 1cbc3162d43..b575dc21961 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -315,7 +315,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere self.word(cmnt.lines[0].clone()); self.hardbreak() } else { - self.ibox(0); + self.visual_align(); for line in &cmnt.lines { if !line.is_empty() { self.word(line.clone()); @@ -607,7 +607,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere &mut self, macro_def: &ast::MacroDef, ident: &Ident, - sp: &Span, + sp: Span, print_visibility: impl FnOnce(&mut Self), ) { let (kw, has_bang) = if macro_def.macro_rules { @@ -623,7 +623,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere macro_def.body.delim(), ¯o_def.body.inner_tokens(), true, - *sp, + sp, ); if macro_def.body.need_semicolon() { self.word(";"); @@ -655,7 +655,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere // Outer-box is consistent. self.cbox(INDENT_UNIT); // Head-box is inconsistent. - self.ibox(w.len() + 1); + self.ibox(0); // Keyword that starts the head. if !w.is_empty() { self.word_nbsp(w); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 956200d60f5..6a5bba30b8b 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -320,7 +320,9 @@ impl<'a> State<'a> { self.print_ident(label.ident); self.word_space(":"); } - self.head("while"); + self.cbox(0); + self.ibox(0); + self.word_nbsp("while"); self.print_expr_as_cond(test); self.space(); self.print_block_with_attrs(blk, attrs); @@ -330,7 +332,9 @@ impl<'a> State<'a> { self.print_ident(label.ident); self.word_space(":"); } - self.head("for"); + self.cbox(0); + self.ibox(0); + self.word_nbsp("for"); self.print_pat(pat); self.space(); self.word_space("in"); @@ -343,12 +347,14 @@ impl<'a> State<'a> { self.print_ident(label.ident); self.word_space(":"); } - self.head("loop"); + self.cbox(0); + self.ibox(0); + self.word_nbsp("loop"); self.print_block_with_attrs(blk, attrs); } ast::ExprKind::Match(ref expr, ref arms) => { - self.cbox(INDENT_UNIT); - self.ibox(INDENT_UNIT); + self.cbox(0); + self.ibox(0); self.word_nbsp("match"); self.print_expr_as_cond(expr); self.space(); @@ -388,7 +394,7 @@ impl<'a> State<'a> { self.word_space(":"); } // containing cbox, will be closed by print-block at } - self.cbox(INDENT_UNIT); + self.cbox(0); // head-box, will be closed by print-block after { self.ibox(0); self.print_block_with_attrs(blk, attrs); @@ -397,7 +403,7 @@ impl<'a> State<'a> { self.word_nbsp("async"); self.print_capture_clause(capture_clause); // cbox/ibox in analogy to the `ExprKind::Block` arm above - self.cbox(INDENT_UNIT); + self.cbox(0); self.ibox(0); self.print_block_with_attrs(blk, attrs); } @@ -500,7 +506,9 @@ impl<'a> State<'a> { self.word("?") } ast::ExprKind::TryBlock(ref blk) => { - self.head("try"); + self.cbox(0); + self.ibox(0); + self.word_nbsp("try"); self.print_block_with_attrs(blk, attrs) } ast::ExprKind::Err => { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index c756b946b1e..dac84ae9d5f 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -1,5 +1,5 @@ use crate::pp::Breaks::Inconsistent; -use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT}; +use crate::pprust::state::{AnnNode, PrintState, State}; use rustc_ast as ast; use rustc_ast::GenericBound; @@ -347,7 +347,7 @@ impl<'a> State<'a> { } } ast::ItemKind::MacroDef(ref macro_def) => { - self.print_mac_def(macro_def, &item.ident, &item.span, |state| { + self.print_mac_def(macro_def, &item.ident, item.span, |state| { state.print_visibility(&item.vis) }); } @@ -377,7 +377,7 @@ impl<'a> State<'a> { self.space_if_not_bol(); self.maybe_print_comment(v.span.lo()); self.print_outer_attributes(&v.attrs); - self.ibox(INDENT_UNIT); + self.ibox(0); self.print_variant(v); self.word(","); self.end(); diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index 98378a98684..d41143ee763 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -72,7 +72,7 @@ impl<'tcx> Index<OutlivesConstraintIndex> for OutlivesConstraintSet<'tcx> { } } -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, PartialEq, Eq)] pub struct OutlivesConstraint<'tcx> { // NB. The ordering here is not significant for correctness, but // it is for convenience. Before we dump the constraints in the diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 8f4e574fbd6..8ed50075ecb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -798,7 +798,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .map(|assoc_items| { assoc_items .in_definition_order() - .map(|assoc_item_def| assoc_item_def.ident) + .map(|assoc_item_def| assoc_item_def.ident(self.infcx.tcx)) .filter(|&ident| { let original_method_ident = path_segment.ident; original_method_ident != ident diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs index cfd3acb6bde..97233b930c3 100644 --- a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs +++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs @@ -72,7 +72,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } let mut constraints: Vec<_> = self.constraints.outlives().iter().collect(); - constraints.sort(); + constraints.sort_by_key(|c| (c.sup, c.sub)); for constraint in &constraints { let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint; let (name, arg) = match locations { diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index b39a28f79aa..d9120ff2457 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -612,7 +612,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn propagate_constraints(&mut self, _body: &Body<'tcx>) { debug!("constraints={:#?}", { let mut constraints: Vec<_> = self.constraints.outlives().iter().collect(); - constraints.sort(); + constraints.sort_by_key(|c| (c.sup, c.sub)); constraints .into_iter() .map(|c| (c, self.constraint_sccs.scc(c.sup), self.constraint_sccs.scc(c.sub))) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index b6f5f4998a6..73103643e3e 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -758,6 +758,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { }, ProjectionElem::Field(field, fty) => { let fty = self.sanitize_type(place, fty); + let fty = self.cx.normalize(fty, location); match self.field_ty(place, base, field, location) { Ok(ty) => { let ty = self.cx.normalize(ty, location); diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index b986df403f9..16a903d5e59 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -180,8 +180,9 @@ pub enum RegionClassification { /// anywhere. There is only one, `'static`. Global, - /// An **external** region is only relevant for closures. In that - /// case, it refers to regions that are free in the closure type + /// An **external** region is only relevant for + /// closures, generators, and inline consts. In that + /// case, it refers to regions that are free in the type /// -- basically, something bound in the surrounding context. /// /// Consider this example: @@ -198,8 +199,8 @@ pub enum RegionClassification { /// Here, the lifetimes `'a` and `'b` would be **external** to the /// closure. /// - /// If we are not analyzing a closure, there are no external - /// lifetimes. + /// If we are not analyzing a closure/generator/inline-const, + /// there are no external lifetimes. External, /// A **local** lifetime is one about which we know the full set @@ -424,22 +425,30 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id()); - // If this is a closure or generator, then the late-bound regions from the enclosing - // function are actually external regions to us. For example, here, 'a is not local - // to the closure c (although it is local to the fn foo): - // fn foo<'a>() { - // let c = || { let x: &'a u32 = ...; } - // } - if self.mir_def.did.to_def_id() != typeck_root_def_id { + // If this is is a 'root' body (not a closure/generator/inline const), then + // there are no extern regions, so the local regions start at the same + // position as the (empty) sub-list of extern regions + let first_local_index = if self.mir_def.did.to_def_id() == typeck_root_def_id { + first_extern_index + } else { + // If this is a closure, generator, or inline-const, then the late-bound regions from the enclosing + // function are actually external regions to us. For example, here, 'a is not local + // to the closure c (although it is local to the fn foo): + // fn foo<'a>() { + // let c = || { let x: &'a u32 = ...; } + // } self.infcx - .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices) - } - - let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty); + .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices); + // Any regions created during the execution of `defining_ty` or during the above + // late-bound region replacement are all considered 'extern' regions + self.infcx.num_region_vars() + }; // "Liberate" the late-bound regions. These correspond to // "local" free regions. - let first_local_index = self.infcx.num_region_vars(); + + let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty); + let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars( FR, self.mir_def.did, diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index d1393528d1c..41b56cca1dc 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -791,7 +791,7 @@ impl<'a, 'b> Context<'a, 'b> { // Thus in the not nicely ordered case we emit the following instead: // // match (&$arg0, &$arg1, …) { - // _args => [ArgumentV1::new(_args.$i, …), ArgumentV1::new(_args.$j, …), …] + // args => [ArgumentV1::new(args.$i, …), ArgumentV1::new(args.$j, …), …] // } // // for the sequence of indices $i, $j, … governed by fmt_arg_index_and_ty. @@ -804,7 +804,7 @@ impl<'a, 'b> Context<'a, 'b> { self.ecx.expr_addr_of(expansion_span, P(e.take())) } else { let def_site = self.ecx.with_def_site_ctxt(span); - let args_tuple = self.ecx.expr_ident(def_site, Ident::new(sym::_args, def_site)); + let args_tuple = self.ecx.expr_ident(def_site, Ident::new(sym::args, def_site)); let member = Ident::new(sym::integer(arg_index), def_site); self.ecx.expr(def_site, ast::ExprKind::Field(args_tuple, member)) }; @@ -828,7 +828,7 @@ impl<'a, 'b> Context<'a, 'b> { .map(|e| self.ecx.expr_addr_of(e.span.with_ctxt(self.macsp.ctxt()), e)) .collect(); - let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::_args, self.macsp)); + let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::args, self.macsp)); let arm = self.ecx.arm(self.macsp, pat, args_array); let head = self.ecx.expr(self.macsp, ast::ExprKind::Tup(heads)); self.ecx.expr_match(self.macsp, head, vec![arm]) @@ -877,11 +877,21 @@ impl<'a, 'b> Context<'a, 'b> { return ecx.expr_call_global(macsp, path, vec![arg]); } }; + let new_fn_name = match trait_ { + "Display" => "new_display", + "Debug" => "new_debug", + "LowerExp" => "new_lower_exp", + "UpperExp" => "new_upper_exp", + "Octal" => "new_octal", + "Pointer" => "new_pointer", + "Binary" => "new_binary", + "LowerHex" => "new_lower_hex", + "UpperHex" => "new_upper_hex", + _ => unreachable!(), + }; - let path = ecx.std_path(&[sym::fmt, Symbol::intern(trait_), sym::fmt]); - let format_fn = ecx.path_global(sp, path); - let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, sym::new]); - ecx.expr_call_global(macsp, path, vec![arg, ecx.expr_path(format_fn)]) + let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, Symbol::intern(new_fn_name)]); + ecx.expr_call_global(sp, path, vec![arg]) } } diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 65e142a00f8..faed52727c8 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -172,9 +172,9 @@ checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] name = "indexmap" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" dependencies = [ "autocfg", "hashbrown", diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index 3be4250296e..2d19040b509 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -19,7 +19,7 @@ gimli = { version = "0.25.0", default-features = false, features = ["write"]} object = { version = "0.27.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" } -indexmap = "1.0.2" +indexmap = "1.8.0" libloading = { version = "0.6.0", optional = true } smallvec = "1.6.1" diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index b4213da6e05..8a74c4c07e0 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -560,6 +560,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => unimplemented!(), InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => unimplemented!(), InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => unimplemented!(), + InlineAsmRegClass::Msp430(_) => unimplemented!(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => unimplemented!(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => unimplemented!(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => unimplemented!(), @@ -622,6 +623,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(), + InlineAsmRegClass::Msp430(_) => unimplemented!(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(), @@ -729,6 +731,7 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option InlineAsmRegClass::Bpf(_) => unimplemented!(), InlineAsmRegClass::Hexagon(_) => unimplemented!(), InlineAsmRegClass::Mips(_) => unimplemented!(), + InlineAsmRegClass::Msp430(_) => unimplemented!(), InlineAsmRegClass::Nvptx(_) => unimplemented!(), InlineAsmRegClass::PowerPC(_) => unimplemented!(), InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 379c88bbd40..ffb77e16a14 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1256,7 +1256,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { aggregate_value } - fn landing_pad(&mut self, _ty: Type<'gcc>, _pers_fn: RValue<'gcc>, _num_clauses: usize) -> RValue<'gcc> { + fn set_personality_fn(&mut self, _personality: RValue<'gcc>) { + // TODO(antoyo) + } + + fn cleanup_landing_pad(&mut self, _ty: Type<'gcc>, _pers_fn: RValue<'gcc>) -> RValue<'gcc> { let field1 = self.context.new_field(None, self.u8_type, "landing_pad_field_1"); let field2 = self.context.new_field(None, self.i32_type, "landing_pad_field_1"); let struct_type = self.context.new_struct_type(None, "landing_pad", &[field1, field2]); @@ -1267,11 +1271,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // rustc_codegen_ssa now calls the unwinding builder methods even on panic=abort. } - fn set_cleanup(&mut self, _landing_pad: RValue<'gcc>) { - // TODO(antoyo) - } - - fn resume(&mut self, _exn: RValue<'gcc>) -> RValue<'gcc> { + fn resume(&mut self, _exn: RValue<'gcc>) { unimplemented!(); } @@ -1279,7 +1279,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { unimplemented!(); } - fn cleanup_ret(&mut self, _funclet: &Funclet, _unwind: Option<Block<'gcc>>) -> RValue<'gcc> { + fn cleanup_ret(&mut self, _funclet: &Funclet, _unwind: Option<Block<'gcc>>) { unimplemented!(); } @@ -1287,18 +1287,15 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { unimplemented!(); } - fn catch_switch(&mut self, _parent: Option<RValue<'gcc>>, _unwind: Option<Block<'gcc>>, _num_handlers: usize) -> RValue<'gcc> { + fn catch_switch( + &mut self, + _parent: Option<RValue<'gcc>>, + _unwind: Option<Block<'gcc>>, + _handlers: &[Block<'gcc>], + ) -> RValue<'gcc> { unimplemented!(); } - fn add_handler(&mut self, _catch_switch: RValue<'gcc>, _handler: Block<'gcc>) { - unimplemented!(); - } - - fn set_personality_fn(&mut self, _personality: RValue<'gcc>) { - // TODO(antoyo) - } - // Atomic Operations fn atomic_cmpxchg(&mut self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> { let expected = self.current_func().new_local(None, cmp.get_type(), "expected"); diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 8b696dc6fba..e22bec24951 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -232,6 +232,9 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { InlineAsmArch::SpirV => {} InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {} InlineAsmArch::Bpf => {} + InlineAsmArch::Msp430 => { + constraints.push("~{sr}".to_string()); + } } } if !options.contains(InlineAsmOptions::NOMEM) { @@ -580,6 +583,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f", + InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r", InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") } @@ -666,6 +670,7 @@ fn modifier_to_llvm( }, InlineAsmRegClass::Avr(_) => None, InlineAsmRegClass::S390x(_) => None, + InlineAsmRegClass::Msp430(_) => None, InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") } @@ -734,6 +739,7 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(), InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(), + InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(), InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 8a9450c20dd..c9a04e6280f 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -956,29 +956,24 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { llvm::LLVMBuildInsertValue(self.llbuilder, agg_val, elt, idx as c_uint, UNNAMED) } } - fn landing_pad( - &mut self, - ty: &'ll Type, - pers_fn: &'ll Value, - num_clauses: usize, - ) -> &'ll Value { - // Use LLVMSetPersonalityFn to set the personality. It supports arbitrary Consts while, - // LLVMBuildLandingPad requires the argument to be a Function (as of LLVM 12). The - // personality lives on the parent function anyway. - self.set_personality_fn(pers_fn); + fn set_personality_fn(&mut self, personality: &'ll Value) { unsafe { - llvm::LLVMBuildLandingPad(self.llbuilder, ty, None, num_clauses as c_uint, UNNAMED) + llvm::LLVMSetPersonalityFn(self.llfn(), personality); } } - fn set_cleanup(&mut self, landing_pad: &'ll Value) { + fn cleanup_landing_pad(&mut self, ty: &'ll Type, pers_fn: &'ll Value) -> &'ll Value { + let landing_pad = self.landing_pad(ty, pers_fn, 1 /* FIXME should this be 0? */); unsafe { llvm::LLVMSetCleanup(landing_pad, llvm::True); } + landing_pad } - fn resume(&mut self, exn: &'ll Value) -> &'ll Value { - unsafe { llvm::LLVMBuildResume(self.llbuilder, exn) } + fn resume(&mut self, exn: &'ll Value) { + unsafe { + llvm::LLVMBuildResume(self.llbuilder, exn); + } } fn cleanup_pad(&mut self, parent: Option<&'ll Value>, args: &[&'ll Value]) -> Funclet<'ll> { @@ -995,14 +990,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { Funclet::new(ret.expect("LLVM does not have support for cleanuppad")) } - fn cleanup_ret( - &mut self, - funclet: &Funclet<'ll>, - unwind: Option<&'ll BasicBlock>, - ) -> &'ll Value { - let ret = - unsafe { llvm::LLVMRustBuildCleanupRet(self.llbuilder, funclet.cleanuppad(), unwind) }; - ret.expect("LLVM does not have support for cleanupret") + fn cleanup_ret(&mut self, funclet: &Funclet<'ll>, unwind: Option<&'ll BasicBlock>) { + unsafe { + llvm::LLVMRustBuildCleanupRet(self.llbuilder, funclet.cleanuppad(), unwind) + .expect("LLVM does not have support for cleanupret"); + } } fn catch_pad(&mut self, parent: &'ll Value, args: &[&'ll Value]) -> Funclet<'ll> { @@ -1023,7 +1015,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { &mut self, parent: Option<&'ll Value>, unwind: Option<&'ll BasicBlock>, - num_handlers: usize, + handlers: &[&'ll BasicBlock], ) -> &'ll Value { let name = cstr!("catchswitch"); let ret = unsafe { @@ -1031,23 +1023,17 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { self.llbuilder, parent, unwind, - num_handlers as c_uint, + handlers.len() as c_uint, name.as_ptr(), ) }; - ret.expect("LLVM does not have support for catchswitch") - } - - fn add_handler(&mut self, catch_switch: &'ll Value, handler: &'ll BasicBlock) { - unsafe { - llvm::LLVMRustAddHandler(catch_switch, handler); - } - } - - fn set_personality_fn(&mut self, personality: &'ll Value) { - unsafe { - llvm::LLVMSetPersonalityFn(self.llfn(), personality); + let ret = ret.expect("LLVM does not have support for catchswitch"); + for handler in handlers { + unsafe { + llvm::LLVMRustAddHandler(ret, handler); + } } + ret } // Atomic Operations @@ -1478,4 +1464,19 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { None } } + + pub(crate) fn landing_pad( + &mut self, + ty: &'ll Type, + pers_fn: &'ll Value, + num_clauses: usize, + ) -> &'ll Value { + // Use LLVMSetPersonalityFn to set the personality. It supports arbitrary Consts while, + // LLVMBuildLandingPad requires the argument to be a Function (as of LLVM 12). The + // personality lives on the parent function anyway. + self.set_personality_fn(pers_fn); + unsafe { + llvm::LLVMBuildLandingPad(self.llbuilder, ty, None, num_clauses as c_uint, UNNAMED) + } + } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index bb16bc5dccd..8672459b5da 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -215,16 +215,19 @@ pub unsafe fn create_module<'ll>( // to ensure intrinsic calls don't use it. if !sess.needs_plt() { let avoid_plt = "RtLibUseGOT\0".as_ptr().cast(); - llvm::LLVMRustAddModuleFlag(llmod, avoid_plt, 1); + llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1); } if sess.is_sanitizer_cfi_enabled() { // FIXME(rcvalle): Add support for non canonical jump tables. let canonical_jump_tables = "CFI Canonical Jump Tables\0".as_ptr().cast(); - // FIXME(rcvalle): Add it with Override behavior flag--LLVMRustAddModuleFlag adds it with - // Warning behavior flag. Add support for specifying the behavior flag to - // LLVMRustAddModuleFlag. - llvm::LLVMRustAddModuleFlag(llmod, canonical_jump_tables, 1); + // FIXME(rcvalle): Add it with Override behavior flag. + llvm::LLVMRustAddModuleFlag( + llmod, + llvm::LLVMModFlagBehavior::Warning, + canonical_jump_tables, + 1, + ); } // Control Flow Guard is currently only supported by the MSVC linker on Windows. @@ -233,11 +236,21 @@ pub unsafe fn create_module<'ll>( CFGuard::Disabled => {} CFGuard::NoChecks => { // Set `cfguard=1` module flag to emit metadata only. - llvm::LLVMRustAddModuleFlag(llmod, "cfguard\0".as_ptr() as *const _, 1) + llvm::LLVMRustAddModuleFlag( + llmod, + llvm::LLVMModFlagBehavior::Warning, + "cfguard\0".as_ptr() as *const _, + 1, + ) } CFGuard::Checks => { // Set `cfguard=2` module flag to emit metadata and checks. - llvm::LLVMRustAddModuleFlag(llmod, "cfguard\0".as_ptr() as *const _, 2) + llvm::LLVMRustAddModuleFlag( + llmod, + llvm::LLVMModFlagBehavior::Warning, + "cfguard\0".as_ptr() as *const _, + 2, + ) } } } @@ -247,24 +260,28 @@ pub unsafe fn create_module<'ll>( llvm::LLVMRustAddModuleFlag( llmod, + llvm::LLVMModFlagBehavior::Error, "branch-target-enforcement\0".as_ptr().cast(), bti.into(), ); llvm::LLVMRustAddModuleFlag( llmod, + llvm::LLVMModFlagBehavior::Error, "sign-return-address\0".as_ptr().cast(), pac.is_some().into(), ); let pac_opts = pac.unwrap_or(PacRet { leaf: false, key: PAuthKey::A }); llvm::LLVMRustAddModuleFlag( llmod, + llvm::LLVMModFlagBehavior::Error, "sign-return-address-all\0".as_ptr().cast(), pac_opts.leaf.into(), ); let is_bkey = if pac_opts.key == PAuthKey::A { false } else { true }; llvm::LLVMRustAddModuleFlag( llmod, + llvm::LLVMModFlagBehavior::Error, "sign-return-address-with-bkey\0".as_ptr().cast(), is_bkey.into(), ); diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 32f18419753..3014d2f1930 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -9,6 +9,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefIdSet; use rustc_llvm::RustString; +use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::coverage::CodeRegion; use rustc_middle::ty::TyCtxt; @@ -76,10 +77,18 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { let coverage_mapping_buffer = llvm::build_byte_buffer(|coverage_mapping_buffer| { mapgen.write_coverage_mapping(expressions, counter_regions, coverage_mapping_buffer); }); - debug_assert!( - !coverage_mapping_buffer.is_empty(), - "Every `FunctionCoverage` should have at least one counter" - ); + + if coverage_mapping_buffer.is_empty() { + if function_coverage.is_used() { + bug!( + "A used function should have had coverage mapping data but did not: {}", + mangled_function_name + ); + } else { + debug!("unused function had no coverage mapping data: {}", mangled_function_name); + continue; + } + } function_data.push((mangled_function_name, source_hash, is_used, coverage_mapping_buffer)); } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 3d5fd2f354e..1266b540aae 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -10,6 +10,8 @@ use super::CrateDebugContext; use crate::abi; use crate::common::CodegenCx; +use crate::debuginfo::utils::fat_pointer_kind; +use crate::debuginfo::utils::FatPtrKind; use crate::llvm; use crate::llvm::debuginfo::{ DIArray, DICompositeType, DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, @@ -376,22 +378,24 @@ macro_rules! return_if_metadata_created_in_meantime { }; } -fn fixed_vec_metadata<'ll, 'tcx>( +/// Creates debuginfo for a fixed size array (e.g. `[u64; 123]`). +/// For slices (that is, "arrays" of unknown size) use [slice_type_metadata]. +fn fixed_size_array_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, unique_type_id: UniqueTypeId, - array_or_slice_type: Ty<'tcx>, - element_type: Ty<'tcx>, + array_type: Ty<'tcx>, ) -> MetadataCreationResult<'ll> { + let ty::Array(element_type, len) = array_type.kind() else { + bug!("fixed_size_array_metadata() called with non-ty::Array type `{:?}`", array_type) + }; + let element_type_metadata = type_metadata(cx, element_type); return_if_metadata_created_in_meantime!(cx, unique_type_id); - let (size, align) = cx.size_and_align_of(array_or_slice_type); + let (size, align) = cx.size_and_align_of(array_type); - let upper_bound = match array_or_slice_type.kind() { - ty::Array(_, len) => len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong, - _ => -1, - }; + let upper_bound = len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong; let subrange = unsafe { Some(llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)) }; @@ -410,55 +414,111 @@ fn fixed_vec_metadata<'ll, 'tcx>( MetadataCreationResult::new(metadata, false) } -fn vec_slice_metadata<'ll, 'tcx>( +/// Creates debuginfo for built-in pointer-like things: +/// +/// - ty::Ref +/// - ty::RawPtr +/// - ty::Adt in the case it's Box +/// +/// At some point we might want to remove the special handling of Box +/// and treat it the same as other smart pointers (like Rc, Arc, ...). +fn pointer_or_reference_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, - slice_ptr_type: Ty<'tcx>, - element_type: Ty<'tcx>, + ptr_type: Ty<'tcx>, + pointee_type: Ty<'tcx>, unique_type_id: UniqueTypeId, ) -> MetadataCreationResult<'ll> { - let data_ptr_type = cx.tcx.mk_imm_ptr(element_type); - - let data_ptr_metadata = type_metadata(cx, data_ptr_type); + let pointee_type_metadata = type_metadata(cx, pointee_type); return_if_metadata_created_in_meantime!(cx, unique_type_id); - let slice_type_name = compute_debuginfo_type_name(cx.tcx, slice_ptr_type, true); - - let (pointer_size, pointer_align) = cx.size_and_align_of(data_ptr_type); - let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx.types.usize); - - let member_descriptions = vec![ - MemberDescription { - name: "data_ptr".to_owned(), - type_metadata: data_ptr_metadata, - offset: Size::ZERO, - size: pointer_size, - align: pointer_align, - flags: DIFlags::FlagZero, - discriminant: None, - source_info: None, - }, - MemberDescription { - name: "length".to_owned(), - type_metadata: type_metadata(cx, cx.tcx.types.usize), - offset: pointer_size, - size: usize_size, - align: usize_align, - flags: DIFlags::FlagZero, - discriminant: None, - source_info: None, - }, - ]; + let (thin_pointer_size, thin_pointer_align) = + cx.size_and_align_of(cx.tcx.mk_imm_ptr(cx.tcx.types.unit)); + let ptr_type_debuginfo_name = compute_debuginfo_type_name(cx.tcx, ptr_type, true); - let metadata = composite_type_metadata( - cx, - slice_ptr_type, - &slice_type_name, - unique_type_id, - member_descriptions, - NO_SCOPE_METADATA, - ); - MetadataCreationResult::new(metadata, false) + let pointer_type_metadata = match fat_pointer_kind(cx, pointee_type) { + None => { + // This is a thin pointer. Create a regular pointer type and give it the correct name. + debug_assert_eq!( + (thin_pointer_size, thin_pointer_align), + cx.size_and_align_of(ptr_type) + ); + + unsafe { + llvm::LLVMRustDIBuilderCreatePointerType( + DIB(cx), + pointee_type_metadata, + thin_pointer_size.bits(), + thin_pointer_align.bits() as u32, + 0, // Ignore DWARF address space. + ptr_type_debuginfo_name.as_ptr().cast(), + ptr_type_debuginfo_name.len(), + ) + } + } + Some(fat_pointer_kind) => { + let layout = cx.layout_of(ptr_type); + + let addr_field = layout.field(cx, abi::FAT_PTR_ADDR); + let extra_field = layout.field(cx, abi::FAT_PTR_EXTRA); + + let (addr_field_name, extra_field_name) = match fat_pointer_kind { + FatPtrKind::Dyn => ("pointer", "vtable"), + FatPtrKind::Slice => ("data_ptr", "length"), + }; + + debug_assert_eq!(abi::FAT_PTR_ADDR, 0); + debug_assert_eq!(abi::FAT_PTR_EXTRA, 1); + + // The data pointer type is a regular, thin pointer, regardless of whether this is a slice + // or a trait object. + let data_ptr_type_metadata = unsafe { + llvm::LLVMRustDIBuilderCreatePointerType( + DIB(cx), + pointee_type_metadata, + addr_field.size.bits(), + addr_field.align.abi.bits() as u32, + 0, // Ignore DWARF address space. + std::ptr::null(), + 0, + ) + }; + + let member_descriptions = vec![ + MemberDescription { + name: addr_field_name.into(), + type_metadata: data_ptr_type_metadata, + offset: layout.fields.offset(abi::FAT_PTR_ADDR), + size: addr_field.size, + align: addr_field.align.abi, + flags: DIFlags::FlagZero, + discriminant: None, + source_info: None, + }, + MemberDescription { + name: extra_field_name.into(), + type_metadata: type_metadata(cx, extra_field.ty), + offset: layout.fields.offset(abi::FAT_PTR_EXTRA), + size: extra_field.size, + align: extra_field.align.abi, + flags: DIFlags::FlagZero, + discriminant: None, + source_info: None, + }, + ]; + + composite_type_metadata( + cx, + ptr_type, + &ptr_type_debuginfo_name, + unique_type_id, + member_descriptions, + NO_SCOPE_METADATA, + ) + } + }; + + MetadataCreationResult { metadata: pointer_type_metadata, already_stored_in_typemap: false } } fn subroutine_type_metadata<'ll, 'tcx>( @@ -495,83 +555,57 @@ fn subroutine_type_metadata<'ll, 'tcx>( ) } -// FIXME(1563): This is all a bit of a hack because 'trait pointer' is an ill- -// defined concept. For the case of an actual trait pointer (i.e., `Box<Trait>`, -// `&Trait`), `trait_object_type` should be the whole thing (e.g, `Box<Trait>`) and -// `trait_type` should be the actual trait (e.g., `Trait`). Where the trait is part -// of a DST struct, there is no `trait_object_type` and the results of this -// function will be a little bit weird. -fn trait_pointer_metadata<'ll, 'tcx>( +/// Create debuginfo for `dyn SomeTrait` types. Currently these are empty structs +/// we with the correct type name (e.g. "dyn SomeTrait<Foo, Item=u32> + Sync"). +fn dyn_type_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, - trait_type: Ty<'tcx>, - trait_object_type: Option<Ty<'tcx>>, + dyn_type: Ty<'tcx>, unique_type_id: UniqueTypeId, ) -> &'ll DIType { - // The implementation provided here is a stub. It makes sure that the trait - // type is assigned the correct name, size, namespace, and source location. - // However, it does not describe the trait's methods. - - let (containing_scope, trait_type_name) = match trait_object_type { - Some(trait_object_type) => match trait_object_type.kind() { - ty::Adt(def, _) => ( - Some(get_namespace_for_item(cx, def.did)), - compute_debuginfo_type_name(cx.tcx, trait_object_type, false), - ), - ty::RawPtr(_) | ty::Ref(..) => { - (NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_object_type, true)) - } - _ => { - bug!( - "debuginfo: unexpected trait-object type in \ - trait_pointer_metadata(): {:?}", - trait_object_type - ); - } - }, + if let ty::Dynamic(..) = dyn_type.kind() { + let type_name = compute_debuginfo_type_name(cx.tcx, dyn_type, true); + composite_type_metadata(cx, dyn_type, &type_name, unique_type_id, vec![], NO_SCOPE_METADATA) + } else { + bug!("Only ty::Dynamic is valid for dyn_type_metadata(). Found {:?} instead.", dyn_type) + } +} - // No object type, use the trait type directly (no scope here since the type - // will be wrapped in the dyn$ synthetic type). - None => (NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_type, true)), +/// Create debuginfo for `[T]` and `str`. These are unsized. +/// +/// NOTE: We currently emit just emit the debuginfo for the element type here +/// (i.e. `T` for slices and `u8` for `str`), so that we end up with +/// `*const T` for the `data_ptr` field of the corresponding fat-pointer +/// debuginfo of `&[T]`. +/// +/// It would be preferable and more accurate if we emitted a DIArray of T +/// without an upper bound instead. That is, LLVM already supports emitting +/// debuginfo of arrays of unknown size. But GDB currently seems to end up +/// in an infinite loop when confronted with such a type. +/// +/// As a side effect of the current encoding every instance of a type like +/// `struct Foo { unsized_field: [u8] }` will look like +/// `struct Foo { unsized_field: u8 }` in debuginfo. If the length of the +/// slice is zero, then accessing `unsized_field` in the debugger would +/// result in an out-of-bounds access. +fn slice_type_metadata<'ll, 'tcx>( + cx: &CodegenCx<'ll, 'tcx>, + slice_type: Ty<'tcx>, + unique_type_id: UniqueTypeId, +) -> MetadataCreationResult<'ll> { + let element_type = match slice_type.kind() { + ty::Slice(element_type) => element_type, + ty::Str => cx.tcx.types.u8, + _ => { + bug!( + "Only ty::Slice is valid for slice_type_metadata(). Found {:?} instead.", + slice_type + ) + } }; - let layout = cx.layout_of(cx.tcx.mk_mut_ptr(trait_type)); - - assert_eq!(abi::FAT_PTR_ADDR, 0); - assert_eq!(abi::FAT_PTR_EXTRA, 1); - - let data_ptr_field = layout.field(cx, 0); - let vtable_field = layout.field(cx, 1); - let member_descriptions = vec![ - MemberDescription { - name: "pointer".to_owned(), - type_metadata: type_metadata(cx, cx.tcx.mk_mut_ptr(cx.tcx.types.u8)), - offset: layout.fields.offset(0), - size: data_ptr_field.size, - align: data_ptr_field.align.abi, - flags: DIFlags::FlagArtificial, - discriminant: None, - source_info: None, - }, - MemberDescription { - name: "vtable".to_owned(), - type_metadata: type_metadata(cx, vtable_field.ty), - offset: layout.fields.offset(1), - size: vtable_field.size, - align: vtable_field.align.abi, - flags: DIFlags::FlagArtificial, - discriminant: None, - source_info: None, - }, - ]; - - composite_type_metadata( - cx, - trait_object_type.unwrap_or(trait_type), - &trait_type_name, - unique_type_id, - member_descriptions, - containing_scope, - ) + let element_type_metadata = type_metadata(cx, element_type); + return_if_metadata_created_in_meantime!(cx, unique_type_id); + MetadataCreationResult { metadata: element_type_metadata, already_stored_in_typemap: false } } pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { @@ -610,26 +644,6 @@ pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll debug!("type_metadata: {:?}", t); - let ptr_metadata = |ty: Ty<'tcx>| match *ty.kind() { - ty::Slice(typ) => Ok(vec_slice_metadata(cx, t, typ, unique_type_id)), - ty::Str => Ok(vec_slice_metadata(cx, t, cx.tcx.types.u8, unique_type_id)), - ty::Dynamic(..) => Ok(MetadataCreationResult::new( - trait_pointer_metadata(cx, ty, Some(t), unique_type_id), - false, - )), - _ => { - let pointee_metadata = type_metadata(cx, ty); - - if let Some(metadata) = - debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) - { - return Err(metadata); - } - - Ok(MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata), false)) - } - }; - let MetadataCreationResult { metadata, already_stored_in_typemap } = match *t.kind() { ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => { MetadataCreationResult::new(basic_type_metadata(cx, t), false) @@ -637,22 +651,20 @@ pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll ty::Tuple(elements) if elements.is_empty() => { MetadataCreationResult::new(basic_type_metadata(cx, t), false) } - ty::Array(typ, _) | ty::Slice(typ) => fixed_vec_metadata(cx, unique_type_id, t, typ), - ty::Str => fixed_vec_metadata(cx, unique_type_id, t, cx.tcx.types.i8), + ty::Array(..) => fixed_size_array_metadata(cx, unique_type_id, t), + ty::Slice(_) | ty::Str => slice_type_metadata(cx, t, unique_type_id), ty::Dynamic(..) => { - MetadataCreationResult::new(trait_pointer_metadata(cx, t, None, unique_type_id), false) + MetadataCreationResult::new(dyn_type_metadata(cx, t, unique_type_id), false) } ty::Foreign(..) => { MetadataCreationResult::new(foreign_type_metadata(cx, t, unique_type_id), false) } - ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => match ptr_metadata(ty) { - Ok(res) => res, - Err(metadata) => return metadata, - }, - ty::Adt(def, _) if def.is_box() => match ptr_metadata(t.boxed_ty()) { - Ok(res) => res, - Err(metadata) => return metadata, - }, + ty::RawPtr(ty::TypeAndMut { ty: pointee_type, .. }) | ty::Ref(_, pointee_type, _) => { + pointer_or_reference_metadata(cx, t, pointee_type, unique_type_id) + } + ty::Adt(def, _) if def.is_box() => { + pointer_or_reference_metadata(cx, t, t.boxed_ty(), unique_type_id) + } ty::FnDef(..) | ty::FnPtr(_) => { if let Some(metadata) = debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) @@ -694,7 +706,22 @@ pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll type_map.borrow_mut().remove_type(t); // This is actually a function pointer, so wrap it in pointer DI. - MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false) + let (pointer_size, pointer_align) = + cx.size_and_align_of(cx.tcx.mk_imm_ptr(cx.tcx.mk_unit())); + let name = compute_debuginfo_type_name(cx.tcx, t, false); + let md = unsafe { + llvm::LLVMRustDIBuilderCreatePointerType( + DIB(cx), + fn_metadata, + pointer_size.bits(), + pointer_align.bits() as u32, + 0, // Ignore DWARF address space. + name.as_ptr().cast(), + name.len(), + ) + }; + + MetadataCreationResult::new(md, false) } ty::Closure(def_id, substs) => { let upvar_tys: Vec<_> = substs.as_closure().upvar_tys().collect(); @@ -959,26 +986,6 @@ fn foreign_type_metadata<'ll, 'tcx>( create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA, DIFlags::FlagZero) } -fn pointer_type_metadata<'ll, 'tcx>( - cx: &CodegenCx<'ll, 'tcx>, - pointer_type: Ty<'tcx>, - pointee_type_metadata: &'ll DIType, -) -> &'ll DIType { - let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type); - let name = compute_debuginfo_type_name(cx.tcx, pointer_type, false); - unsafe { - llvm::LLVMRustDIBuilderCreatePointerType( - DIB(cx), - pointee_type_metadata, - pointer_size.bits(), - pointer_align.bits() as u32, - 0, // Ignore DWARF address space. - name.as_ptr().cast(), - name.len(), - ) - } -} - fn param_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { debug!("param_type_metadata: {:?}", t); let name = format!("{:?}", t); @@ -1493,7 +1500,7 @@ fn generator_layout_and_saved_local_names<'tcx>( let state_arg = mir::Local::new(1); for var in &body.var_debug_info { - let place = if let mir::VarDebugInfoContents::Place(p) = var.value { p } else { continue }; + let mir::VarDebugInfoContents::Place(place) = &var.value else { continue }; if place.local != state_arg { continue; } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 61e49fab6ff..28eb8e2a0a4 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -108,18 +108,29 @@ impl<'a, 'tcx> CrateDebugContext<'a, 'tcx> { // This can be overridden using --llvm-opts -dwarf-version,N. // Android has the same issue (#22398) if let Some(version) = sess.target.dwarf_version { - llvm::LLVMRustAddModuleFlag(self.llmod, "Dwarf Version\0".as_ptr().cast(), version) + llvm::LLVMRustAddModuleFlag( + self.llmod, + llvm::LLVMModFlagBehavior::Warning, + "Dwarf Version\0".as_ptr().cast(), + version, + ) } // Indicate that we want CodeView debug information on MSVC if sess.target.is_like_msvc { - llvm::LLVMRustAddModuleFlag(self.llmod, "CodeView\0".as_ptr().cast(), 1) + llvm::LLVMRustAddModuleFlag( + self.llmod, + llvm::LLVMModFlagBehavior::Warning, + "CodeView\0".as_ptr().cast(), + 1, + ) } // Prevent bitcode readers from deleting the debug info. let ptr = "Debug Info Version\0".as_ptr(); llvm::LLVMRustAddModuleFlag( self.llmod, + llvm::LLVMModFlagBehavior::Warning, ptr.cast(), llvm::LLVMRustDebugMetadataVersion(), ); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs index 953b6765a48..6dd0d58efe3 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs @@ -4,7 +4,9 @@ use super::namespace::item_namespace; use super::CrateDebugContext; use rustc_hir::def_id::DefId; -use rustc_middle::ty::DefIdTree; +use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::{self, DefIdTree, Ty}; +use rustc_target::abi::VariantIdx; use crate::common::CodegenCx; use crate::llvm; @@ -46,3 +48,58 @@ pub fn DIB<'a, 'll>(cx: &'a CodegenCx<'ll, '_>) -> &'a DIBuilder<'ll> { pub fn get_namespace_for_item<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope { item_namespace(cx, cx.tcx.parent(def_id).expect("get_namespace_for_item: missing parent?")) } + +#[derive(Debug, PartialEq, Eq)] +pub(crate) enum FatPtrKind { + Slice, + Dyn, +} + +/// Determines if `pointee_ty` is slice-like or trait-object-like, i.e. +/// if the second field of the fat pointer is a length or a vtable-pointer. +/// If `pointee_ty` does not require a fat pointer (because it is Sized) then +/// the function returns `None`. +pub(crate) fn fat_pointer_kind<'ll, 'tcx>( + cx: &CodegenCx<'ll, 'tcx>, + pointee_ty: Ty<'tcx>, +) -> Option<FatPtrKind> { + let layout = cx.layout_of(pointee_ty); + + if !layout.is_unsized() { + return None; + } + + match *pointee_ty.kind() { + ty::Str | ty::Slice(_) => Some(FatPtrKind::Slice), + ty::Dynamic(..) => Some(FatPtrKind::Dyn), + ty::Adt(adt_def, _) => { + assert!(adt_def.is_struct()); + assert!(adt_def.variants.len() == 1); + let variant = &adt_def.variants[VariantIdx::from_usize(0)]; + assert!(!variant.fields.is_empty()); + let last_field_index = variant.fields.len() - 1; + + debug_assert!( + (0..last_field_index) + .all(|field_index| { !layout.field(cx, field_index).is_unsized() }) + ); + + let unsized_field = layout.field(cx, last_field_index); + assert!(unsized_field.is_unsized()); + fat_pointer_kind(cx, unsized_field.ty) + } + ty::Foreign(_) => { + // Assert that pointers to foreign types really are thin: + debug_assert_eq!( + cx.size_of(cx.tcx.mk_imm_ptr(pointee_ty)), + cx.size_of(cx.tcx.mk_imm_ptr(cx.tcx.types.u8)) + ); + None + } + _ => { + // For all other pointee types we should already have returned None + // at the beginning of the function. + panic!("fat_pointer_kind() - Encountered unexpected `pointee_ty`: {:?}", pointee_ty) + } + } +} diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 5adfa18035a..f51d014bfb3 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -525,9 +525,8 @@ fn codegen_msvc_try<'ll>( normal.ret(bx.const_i32(0)); - let cs = catchswitch.catch_switch(None, None, 2); - catchswitch.add_handler(cs, catchpad_rust.llbb()); - catchswitch.add_handler(cs, catchpad_foreign.llbb()); + let cs = + catchswitch.catch_switch(None, None, &[catchpad_rust.llbb(), catchpad_foreign.llbb()]); // We can't use the TypeDescriptor defined in libpanic_unwind because it // might be in another DLL and the SEH encoding only supports specifying diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index cea4595fbbf..f0612eaba80 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -7,6 +7,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] +#![feature(let_else)] #![feature(extern_types)] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index a1c7d2b4f61..2b102188790 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -61,6 +61,26 @@ pub enum LLVMMachineType { ARM = 0x01c0, } +/// LLVM's Module::ModFlagBehavior, defined in llvm/include/llvm/IR/Module.h. +/// +/// When merging modules (e.g. during LTO), their metadata flags are combined. Conflicts are +/// resolved according to the merge behaviors specified here. Flags differing only in merge +/// behavior are still considered to be in conflict. +/// +/// In order for Rust-C LTO to work, we must specify behaviors compatible with Clang. Notably, +/// 'Error' and 'Warning' cannot be mixed for a given flag. +#[derive(Copy, Clone, PartialEq)] +#[repr(C)] +pub enum LLVMModFlagBehavior { + Error = 1, + Warning = 2, + Require = 3, + Override = 4, + Append = 5, + AppendUnique = 6, + Max = 7, +} + // Consts for the LLVM CallConv type, pre-cast to usize. /// LLVM CallingConv::ID. Should we wrap this? @@ -1895,7 +1915,16 @@ extern "C" { pub fn LLVMRustIsRustLLVM() -> bool; - pub fn LLVMRustAddModuleFlag(M: &Module, name: *const c_char, value: u32); + /// Add LLVM module flags. + /// + /// In order for Rust-C LTO to work, module flags must be compatible with Clang. What + /// "compatible" means depends on the merge behaviors involved. + pub fn LLVMRustAddModuleFlag( + M: &Module, + merge_behavior: LLVMModFlagBehavior, + name: *const c_char, + value: u32, + ); pub fn LLVMRustMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index acf65259f61..7a13e424f9a 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -932,7 +932,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( but `link.exe` was not found", ); sess.note_without_error( - "please ensure that VS 2013, VS 2015, VS 2017 or VS 2019 \ + "please ensure that VS 2013, VS 2015, VS 2017, VS 2019 or VS 2022 \ was installed with the Visual C++ option", ); } @@ -1159,6 +1159,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { LinkerFlavor::Lld(_) => "lld", LinkerFlavor::PtxLinker => "rust-ptx-linker", LinkerFlavor::BpfLinker => "bpf-linker", + LinkerFlavor::L4Bender => "l4-bender", }), flavor, )), diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 15d16e7d3d6..3fb56f42b8c 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -126,7 +126,6 @@ pub fn get_linker<'a>( // FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction // to the linker args construction. assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp"); - match flavor { LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => { Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker> @@ -149,6 +148,8 @@ pub fn get_linker<'a>( LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>, LinkerFlavor::BpfLinker => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>, + + LinkerFlavor::L4Bender => Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>, } } @@ -1355,6 +1356,157 @@ impl<'a> Linker for WasmLd<'a> { } } +/// Linker shepherd script for L4Re (Fiasco) +pub struct L4Bender<'a> { + cmd: Command, + sess: &'a Session, + hinted_static: bool, +} + +impl<'a> Linker for L4Bender<'a> { + fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) { + bug!("dylibs are not supported on L4Re"); + } + fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) { + self.hint_static(); + self.cmd.arg(format!("-PC{}", lib)); + } + fn link_rlib(&mut self, lib: &Path) { + self.hint_static(); + self.cmd.arg(lib); + } + fn include_path(&mut self, path: &Path) { + self.cmd.arg("-L").arg(path); + } + fn framework_path(&mut self, _: &Path) { + bug!("frameworks are not supported on L4Re"); + } + fn output_filename(&mut self, path: &Path) { + self.cmd.arg("-o").arg(path); + } + + fn add_object(&mut self, path: &Path) { + self.cmd.arg(path); + } + + fn full_relro(&mut self) { + self.cmd.arg("-zrelro"); + self.cmd.arg("-znow"); + } + + fn partial_relro(&mut self) { + self.cmd.arg("-zrelro"); + } + + fn no_relro(&mut self) { + self.cmd.arg("-znorelro"); + } + + fn cmd(&mut self) -> &mut Command { + &mut self.cmd + } + + fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} + + fn link_rust_dylib(&mut self, _: Symbol, _: &Path) { + panic!("Rust dylibs not supported"); + } + + fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) { + bug!("frameworks not supported on L4Re"); + } + + fn link_whole_staticlib(&mut self, lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) { + self.hint_static(); + self.cmd.arg("--whole-archive").arg(format!("-l{}", lib)); + self.cmd.arg("--no-whole-archive"); + } + + fn link_whole_rlib(&mut self, lib: &Path) { + self.hint_static(); + self.cmd.arg("--whole-archive").arg(lib).arg("--no-whole-archive"); + } + + fn gc_sections(&mut self, keep_metadata: bool) { + if !keep_metadata { + self.cmd.arg("--gc-sections"); + } + } + + fn no_gc_sections(&mut self) { + self.cmd.arg("--no-gc-sections"); + } + + fn optimize(&mut self) { + // GNU-style linkers support optimization with -O. GNU ld doesn't + // need a numeric argument, but other linkers do. + if self.sess.opts.optimize == config::OptLevel::Default + || self.sess.opts.optimize == config::OptLevel::Aggressive + { + self.cmd.arg("-O1"); + } + } + + fn pgo_gen(&mut self) {} + + fn debuginfo(&mut self, strip: Strip) { + match strip { + Strip::None => {} + Strip::Debuginfo => { + self.cmd().arg("--strip-debug"); + } + Strip::Symbols => { + self.cmd().arg("--strip-all"); + } + } + } + + fn no_default_libraries(&mut self) { + self.cmd.arg("-nostdlib"); + } + + fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) { + // ToDo, not implemented, copy from GCC + self.sess.warn("exporting symbols not implemented yet for L4Bender"); + return; + } + + fn subsystem(&mut self, subsystem: &str) { + self.cmd.arg(&format!("--subsystem {}", subsystem)); + } + + fn reset_per_library_state(&mut self) { + self.hint_static(); // Reset to default before returning the composed command line. + } + + fn group_start(&mut self) { + self.cmd.arg("--start-group"); + } + + fn group_end(&mut self) { + self.cmd.arg("--end-group"); + } + + fn linker_plugin_lto(&mut self) {} + + fn control_flow_guard(&mut self) {} + + fn no_crt_objects(&mut self) {} +} + +impl<'a> L4Bender<'a> { + pub fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> { + L4Bender { cmd: cmd, sess: sess, hinted_static: false } + } + + fn hint_static(&mut self) { + if !self.hinted_static { + self.cmd.arg("-static"); + self.hinted_static = true; + } + } +} + pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> { if let Some(ref exports) = tcx.sess.target.override_export_symbols { return exports.clone(); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 5ce4e606fd2..4c7a09ca1e9 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -477,6 +477,28 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { helper.do_call(self, &mut bx, fn_abi, llfn, &args, None, cleanup); } + fn codegen_abort_terminator( + &mut self, + helper: TerminatorCodegenHelper<'tcx>, + mut bx: Bx, + terminator: &mir::Terminator<'tcx>, + ) { + let span = terminator.source_info.span; + self.set_debug_loc(&mut bx, terminator.source_info); + + // Get the location information. + let location = self.get_caller_location(&mut bx, terminator.source_info).immediate(); + + // Obtain the panic entry point. + let def_id = common::langcall(bx.tcx(), Some(span), "", LangItem::PanicNoUnwind); + let instance = ty::Instance::mono(bx.tcx(), def_id); + let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty()); + let llfn = bx.get_fn_addr(instance); + + // Codegen the actual panic invoke/call. + helper.do_call(self, &mut bx, fn_abi, llfn, &[location], None, None); + } + /// Returns `true` if this is indeed a panic intrinsic and codegen is done. fn codegen_panic_intrinsic( &mut self, @@ -1014,10 +1036,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::TerminatorKind::Resume => self.codegen_resume_terminator(helper, bx), mir::TerminatorKind::Abort => { - bx.abort(); - // `abort` does not terminate the block, so we still need to generate - // an `unreachable` terminator after it. - bx.unreachable(); + self.codegen_abort_terminator(helper, bx, terminator); } mir::TerminatorKind::Goto { target } => { @@ -1327,8 +1346,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let mut cp_bx = self.new_block(&format!("cp_funclet{:?}", bb)); ret_llbb = cs_bx.llbb(); - let cs = cs_bx.catch_switch(None, None, 1); - cs_bx.add_handler(cs, cp_bx.llbb()); + let cs = cs_bx.catch_switch(None, None, &[cp_bx.llbb()]); // The "null" here is actually a RTTI type descriptor for the // C++ personality function, but `catch (...)` has no type so @@ -1355,8 +1373,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let llpersonality = self.cx.eh_personality(); let llretty = self.landing_pad_type(); - let lp = bx.landing_pad(llretty, llpersonality, 1); - bx.set_cleanup(lp); + let lp = bx.cleanup_landing_pad(llretty, llpersonality); let slot = self.get_personality_slot(&mut bx); slot.storage_live(&mut bx); diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 3657f80c2de..c654232c10a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -369,6 +369,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } + sym::const_allocate => { + // returns a null pointer at runtime. + bx.const_null(bx.type_i8p()) + } + + sym::const_deallocate => { + // nop at runtime. + return; + } + // This requires that atomic intrinsics follow a specific naming pattern: // "atomic_<operation>[_<ordering>]", and no ordering means SeqCst name if name_str.starts_with("atomic_") => { diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 5a06fb46105..53fb21b269a 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -421,29 +421,22 @@ pub trait BuilderMethods<'a, 'tcx>: fn extract_value(&mut self, agg_val: Self::Value, idx: u64) -> Self::Value; fn insert_value(&mut self, agg_val: Self::Value, elt: Self::Value, idx: u64) -> Self::Value; - fn landing_pad( - &mut self, - ty: Self::Type, - pers_fn: Self::Value, - num_clauses: usize, - ) -> Self::Value; - fn set_cleanup(&mut self, landing_pad: Self::Value); - fn resume(&mut self, exn: Self::Value) -> Self::Value; + fn set_personality_fn(&mut self, personality: Self::Value); + + // These are used by everyone except msvc + fn cleanup_landing_pad(&mut self, ty: Self::Type, pers_fn: Self::Value) -> Self::Value; + fn resume(&mut self, exn: Self::Value); + + // These are used only by msvc fn cleanup_pad(&mut self, parent: Option<Self::Value>, args: &[Self::Value]) -> Self::Funclet; - fn cleanup_ret( - &mut self, - funclet: &Self::Funclet, - unwind: Option<Self::BasicBlock>, - ) -> Self::Value; + fn cleanup_ret(&mut self, funclet: &Self::Funclet, unwind: Option<Self::BasicBlock>); fn catch_pad(&mut self, parent: Self::Value, args: &[Self::Value]) -> Self::Funclet; fn catch_switch( &mut self, parent: Option<Self::Value>, unwind: Option<Self::BasicBlock>, - num_handlers: usize, + handlers: &[Self::BasicBlock], ) -> Self::Value; - fn add_handler(&mut self, catch_switch: Self::Value, handler: Self::BasicBlock); - fn set_personality_fn(&mut self, personality: Self::Value); fn atomic_cmpxchg( &mut self, diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 3ec9f3ca3b8..9dc34260de7 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -7,7 +7,6 @@ use crate::interpret::{ }; use rustc_errors::ErrorReported; -use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; @@ -216,7 +215,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { - assert!(key.param_env.constness() == hir::Constness::Const); + assert!(key.param_env.is_const()); // see comment in eval_to_allocation_raw_provider for what we're doing here if key.param_env.reveal() == Reveal::All { let mut key = key; @@ -251,7 +250,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { - assert!(key.param_env.constness() == hir::Constness::Const); + assert!(key.param_env.is_const()); // Because the constant is computed twice (once per value of `Reveal`), we are at risk of // reporting the same error twice here. To resolve this, we check whether we can evaluate the // constant in the more restrictive `Reveal::UserFacing`, which most likely already was diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 30e9cbe4403..89717b75f12 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -347,6 +347,33 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, )?; ecx.write_pointer(ptr, dest)?; } + sym::const_deallocate => { + let ptr = ecx.read_pointer(&args[0])?; + let size = ecx.read_scalar(&args[1])?.to_machine_usize(ecx)?; + let align = ecx.read_scalar(&args[2])?.to_machine_usize(ecx)?; + + let size = Size::from_bytes(size); + let align = match Align::from_bytes(align) { + Ok(a) => a, + Err(err) => throw_ub_format!("align has to be a power of 2, {}", err), + }; + + // If an allocation is created in an another const, + // we don't deallocate it. + let (alloc_id, _, _) = ecx.memory.ptr_get_alloc(ptr)?; + let is_allocated_in_another_const = matches!( + ecx.tcx.get_global_alloc(alloc_id), + Some(interpret::GlobalAlloc::Memory(_)) + ); + + if !is_allocated_in_another_const { + ecx.memory.deallocate( + ptr, + Some((size, align)), + interpret::MemoryKind::Machine(MemoryKind::Heap), + )?; + } + } _ => { return Err(ConstEvalErrKind::NeedsRfc(format!( "calling intrinsic `{}`", diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index cf939aaa73f..91610b15eb9 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -4,11 +4,12 @@ use rustc_errors::ErrorReported; use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::traits::TraitEngine; use rustc_middle::mir::*; use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty}; use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::{ - self, ImplSource, Obligation, ObligationCause, SelectionContext, + self, FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, }; use super::ConstCx; @@ -145,15 +146,10 @@ impl Qualif for NeedsNonConstDrop { qualifs.needs_non_const_drop } - fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, mut ty: Ty<'tcx>) -> bool { - // Avoid selecting for simple cases. - match ty::util::needs_drop_components(ty, &cx.tcx.data_layout).as_deref() { - Ok([]) => return false, - Err(ty::util::AlwaysRequiresDrop) => return true, - // If we've got a single component, select with that - // to increase the chance that we hit the selection cache. - Ok([t]) => ty = t, - Ok([..]) => {} + fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { + // Avoid selecting for simple cases, such as builtin types. + if ty::util::is_trivially_const_drop(ty) { + return false; } let Some(drop_trait) = cx.tcx.lang_items().drop_trait() else { @@ -161,28 +157,50 @@ impl Qualif for NeedsNonConstDrop { // without having the lang item present. return false; }; - let trait_ref = - ty::TraitRef { def_id: drop_trait, substs: cx.tcx.mk_substs_trait(ty, &[]) }; + let obligation = Obligation::new( ObligationCause::dummy(), cx.param_env, ty::Binder::dummy(ty::TraitPredicate { - trait_ref, + trait_ref: ty::TraitRef { + def_id: drop_trait, + substs: cx.tcx.mk_substs_trait(ty, &[]), + }, constness: ty::BoundConstness::ConstIfConst, polarity: ty::ImplPolarity::Positive, }), ); - let implsrc = cx.tcx.infer_ctxt().enter(|infcx| { + cx.tcx.infer_ctxt().enter(|infcx| { let mut selcx = SelectionContext::new(&infcx); - selcx.select(&obligation) - }); - !matches!( - implsrc, - Ok(Some( + let Some(impl_src) = selcx.select(&obligation).ok().flatten() else { + // If we couldn't select a const drop candidate, then it's bad + return true; + }; + + if !matches!( + impl_src, ImplSource::ConstDrop(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst) - )) - ) + ) { + // If our const drop candidate is not ConstDrop or implied by the param env, + // then it's bad + return true; + } + + if impl_src.borrow_nested_obligations().is_empty() { + return false; + } + + // If we successfully found one, then select all of the predicates + // implied by our const drop impl. + let mut fcx = FulfillmentContext::new(); + for nested in impl_src.nested_obligations() { + fcx.register_predicate_obligation(&infcx, nested); + } + + // If we had any errors, then it's bad + !fcx.select_all_or_error(&infcx).is_empty() + }) } fn in_adt_inherently<'tcx>( diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 2bb9d6c1893..ad296c97659 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -9,7 +9,7 @@ doctest = false [dependencies] arrayvec = { version = "0.7", default-features = false } ena = "0.14" -indexmap = "1.5.1" +indexmap = { version = "1.8.0", features = ["rustc-rayon"] } tracing = "0.1" jobserver_crate = { version = "0.1.13", package = "jobserver" } rustc_serialize = { path = "../rustc_serialize" } diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs index c9af35da4bc..525cd650dd2 100644 --- a/compiler/rustc_data_structures/src/fingerprint.rs +++ b/compiler/rustc_data_structures/src/fingerprint.rs @@ -149,10 +149,10 @@ impl<E: rustc_serialize::Encoder> Encodable<E> for Fingerprint { impl<D: rustc_serialize::Decoder> Decodable<D> for Fingerprint { #[inline] - fn decode(d: &mut D) -> Result<Self, D::Error> { + fn decode(d: &mut D) -> Self { let mut bytes = [0u8; 16]; - d.read_raw_bytes_into(&mut bytes)?; - Ok(Fingerprint::from_le_bytes(bytes)) + d.read_raw_bytes_into(&mut bytes); + Fingerprint::from_le_bytes(bytes) } } @@ -195,8 +195,8 @@ impl<E: rustc_serialize::Encoder> Encodable<E> for PackedFingerprint { impl<D: rustc_serialize::Decoder> Decodable<D> for PackedFingerprint { #[inline] - fn decode(d: &mut D) -> Result<Self, D::Error> { - Fingerprint::decode(d).map(PackedFingerprint) + fn decode(d: &mut D) -> Self { + Self(Fingerprint::decode(d)) } } diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs index 872b0eb7854..53062b9c20d 100644 --- a/compiler/rustc_data_structures/src/sip128.rs +++ b/compiler/rustc_data_structures/src/sip128.rs @@ -409,20 +409,6 @@ impl SipHasher128 { } } -macro_rules! dispatch_value { - ($target: expr, $value:expr) => { - let value = $value; - #[allow(unreachable_patterns)] - #[allow(overflowing_literals)] - match value { - 0..=0xFF => $target.short_write(value as u8), - 0x100..=0xFFFF => $target.short_write(value as u16), - 0x10000..=0xFFFFFFFF => $target.short_write(value as u32), - _ => $target.short_write(value as u64), - } - }; -} - impl Hasher for SipHasher128 { #[inline] fn write_u8(&mut self, i: u8) { @@ -436,7 +422,7 @@ impl Hasher for SipHasher128 { #[inline] fn write_u32(&mut self, i: u32) { - dispatch_value!(self, i); + self.short_write(i); } #[inline] @@ -466,7 +452,7 @@ impl Hasher for SipHasher128 { #[inline] fn write_i64(&mut self, i: i64) { - dispatch_value!(self, i as u64); + self.short_write(i as u64); } #[inline] diff --git a/compiler/rustc_data_structures/src/stable_hasher/tests.rs b/compiler/rustc_data_structures/src/stable_hasher/tests.rs index 391db67d29d..31190363eb6 100644 --- a/compiler/rustc_data_structures/src/stable_hasher/tests.rs +++ b/compiler/rustc_data_structures/src/stable_hasher/tests.rs @@ -98,3 +98,45 @@ fn test_hash_bit_matrix() { assert_ne!(a, b); assert_ne!(hash(&a), hash(&b)); } + +// Check that exchanging the value of two adjacent fields changes the hash. +#[test] +fn test_attribute_permutation() { + macro_rules! test_type { + ($ty: ty) => {{ + struct Foo { + a: $ty, + b: $ty, + } + + impl<CTX> HashStable<CTX> for Foo { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + self.a.hash_stable(hcx, hasher); + self.b.hash_stable(hcx, hasher); + } + } + + #[allow(overflowing_literals)] + let mut item = Foo { a: 0xFF, b: 0xFF_FF }; + let hash_a = hash(&item); + std::mem::swap(&mut item.a, &mut item.b); + let hash_b = hash(&item); + assert_ne!( + hash_a, + hash_b, + "The hash stayed the same after values were swapped for type `{}`!", + stringify!($ty) + ); + }}; + } + + test_type!(u16); + test_type!(u32); + test_type!(u64); + test_type!(u128); + + test_type!(i16); + test_type!(i32); + test_type!(i64); + test_type!(i128); +} diff --git a/compiler/rustc_data_structures/src/svh.rs b/compiler/rustc_data_structures/src/svh.rs index ce90fbacaa4..12ef286091c 100644 --- a/compiler/rustc_data_structures/src/svh.rs +++ b/compiler/rustc_data_structures/src/svh.rs @@ -55,8 +55,8 @@ impl<S: Encoder> Encodable<S> for Svh { } impl<D: Decoder> Decodable<D> for Svh { - fn decode(d: &mut D) -> Result<Svh, D::Error> { - d.read_u64().map(u64::from_le).map(Svh::new) + fn decode(d: &mut D) -> Svh { + Svh::new(u64::from_le(d.read_u64())) } } diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 19fa6812b45..2b64312dbef 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -597,10 +597,7 @@ impl RustcDefaultCalls { let rlink_data = fs::read_to_string(file).unwrap_or_else(|err| { sess.fatal(&format!("failed to read rlink file: {}", err)); }); - let codegen_results: CodegenResults = - json::decode(&rlink_data).unwrap_or_else(|err| { - sess.fatal(&format!("failed to decode rlink: {}", err)); - }); + let codegen_results: CodegenResults = json::decode(&rlink_data); let result = compiler.codegen_backend().link(sess, codegen_results, &outputs); abort_on_err(result, sess); } else { diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 79d9c55b547..c401f65edda 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -472,6 +472,7 @@ E0768: include_str!("./error_codes/E0768.md"), E0769: include_str!("./error_codes/E0769.md"), E0770: include_str!("./error_codes/E0770.md"), E0771: include_str!("./error_codes/E0771.md"), +E0772: include_str!("./error_codes/E0772.md"), E0773: include_str!("./error_codes/E0773.md"), E0774: include_str!("./error_codes/E0774.md"), E0775: include_str!("./error_codes/E0775.md"), @@ -486,6 +487,7 @@ E0783: include_str!("./error_codes/E0783.md"), E0784: include_str!("./error_codes/E0784.md"), E0785: include_str!("./error_codes/E0785.md"), E0786: include_str!("./error_codes/E0786.md"), +E0787: include_str!("./error_codes/E0787.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard @@ -641,5 +643,4 @@ E0786: include_str!("./error_codes/E0786.md"), // E0723, // unstable feature in `const` context E0726, // non-explicit (not `'_`) elided lifetime in unsupported position // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. - E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`. } diff --git a/compiler/rustc_error_codes/src/error_codes/E0772.md b/compiler/rustc_error_codes/src/error_codes/E0772.md new file mode 100644 index 00000000000..262e52351ef --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0772.md @@ -0,0 +1,89 @@ +A trait object has some specific lifetime `'1`, but it was used in a way that +requires it to have a `'static` lifetime. + +Example of erroneous code: + +```compile_fail,E0772 +trait BooleanLike {} +trait Person {} + +impl BooleanLike for bool {} + +impl dyn Person { + fn is_cool(&self) -> bool { + // hey you, you're pretty cool + true + } +} + +fn get_is_cool<'p>(person: &'p dyn Person) -> impl BooleanLike { + // error: `person` has an anonymous lifetime `'p` but calling + // `print_cool_fn` introduces an implicit `'static` lifetime + // requirement + person.is_cool() +} +``` + +The trait object `person` in the function `get_is_cool`, while already being +behind a reference with lifetime `'p`, also has it's own implicit lifetime, +`'2`. + +Lifetime `'2` represents the data the trait object might hold inside, for +example: + +``` +trait MyTrait {} + +struct MyStruct<'a>(&'a i32); + +impl<'a> MyTrait for MyStruct<'a> {} +``` + +With this scenario, if a trait object of `dyn MyTrait + '2` was made from +`MyStruct<'a>`, `'a` must live as long, if not longer than `'2`. This allows the +trait object's internal data to be accessed safely from any trait methods. This +rule also goes for any lifetime any struct made into a trait object may have. + +In the implementation for `dyn Person`, the `'2` lifetime representing the +internal data was ommitted, meaning that the compiler inferred the lifetime +`'static`. As a result, the implementation's `is_cool` is inferred by the +compiler to look like this: + +``` +# trait Person {} +# +# impl dyn Person { +fn is_cool<'a>(self: &'a (dyn Person + 'static)) -> bool {unimplemented!()} +# } +``` + +While the `get_is_cool` function is inferred to look like this: + +``` +# trait Person {} +# trait BooleanLike {} +# +fn get_is_cool<'p, R: BooleanLike>(person: &'p (dyn Person + 'p)) -> R { + unimplemented!() +} +``` + +Which brings us to the core of the problem; the assignment of type +`&'_ (dyn Person + '_)` to type `&'_ (dyn Person + 'static)` is impossible. + +Fixing it is as simple as being generic over lifetime `'2`, as to prevent the +compiler from inferring it as `'static`: + +``` +# trait Person {} +# +impl<'d> dyn Person + 'd {/* ... */} + +// This works too, and is more elegant: +//impl dyn Person + '_ {/* ... */} +``` + +See the [Rust Reference on Trait Object Lifetime Bounds][trait-objects] for +more information on trait object lifetimes. + +[trait-object-lifetime-bounds]: https://doc.rust-lang.org/reference/types/trait-object.html#trait-object-lifetime-bounds diff --git a/compiler/rustc_error_codes/src/error_codes/E0787.md b/compiler/rustc_error_codes/src/error_codes/E0787.md new file mode 100644 index 00000000000..cee50829270 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0787.md @@ -0,0 +1,28 @@ +An unsupported naked function definition. + +Erroneous code example: + +```compile_fail,E0787 +#![feature(naked_functions)] + +#[naked] +pub extern "C" fn f() -> u32 { + 42 +} +``` + +The naked functions must be defined using a single inline assembly +block. + +The execution must never fall through past the end of the assembly +code so the block must use `noreturn` option. The asm block can also +use `att_syntax` and `raw` options, but others options are not allowed. + +The asm block must not contain any operands other than `const` and +`sym`. + +### Additional information + +For more information, please see [RFC 2972]. + +[RFC 2972]: https://github.com/rust-lang/rfcs/blob/master/text/2972-constrained-naked.md diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs index d055937ac36..c5b3d204407 100644 --- a/compiler/rustc_errors/src/json/tests.rs +++ b/compiler/rustc_errors/src/json/tests.rs @@ -64,7 +64,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) { let bytes = output.lock().unwrap(); let actual_output = str::from_utf8(&bytes).unwrap(); - let actual_output: TestData = decode(actual_output).unwrap(); + let actual_output: TestData = decode(actual_output); assert_eq!(expected_output, actual_output) }) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index a681298301a..16e9b265d69 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -99,8 +99,8 @@ impl Hash for ToolMetadata { // Doesn't really need to round-trip impl<D: Decoder> Decodable<D> for ToolMetadata { - fn decode(_d: &mut D) -> Result<Self, D::Error> { - Ok(ToolMetadata(None)) + fn decode(_d: &mut D) -> Self { + ToolMetadata(None) } } @@ -445,9 +445,6 @@ struct HandlerInner { deduplicated_warn_count: usize, future_breakage_diagnostics: Vec<Diagnostic>, - - /// If set to `true`, no warning or error will be emitted. - quiet: bool, } /// A key denoting where from a diagnostic was stashed. @@ -563,19 +560,10 @@ impl Handler { emitted_diagnostics: Default::default(), stashed_diagnostics: Default::default(), future_breakage_diagnostics: Vec::new(), - quiet: false, }), } } - pub fn with_disabled_diagnostic<T, F: FnOnce() -> T>(&self, f: F) -> T { - let prev = self.inner.borrow_mut().quiet; - self.inner.borrow_mut().quiet = true; - let ret = f(); - self.inner.borrow_mut().quiet = prev; - ret - } - // This is here to not allow mutation of flags; // as of this writing it's only used in tests in librustc_middle. pub fn can_emit_warnings(&self) -> bool { @@ -946,7 +934,7 @@ impl HandlerInner { } fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) { - if diagnostic.cancelled() || self.quiet { + if diagnostic.cancelled() { return; } @@ -1170,9 +1158,6 @@ impl HandlerInner { } fn delay_as_bug(&mut self, diagnostic: Diagnostic) { - if self.quiet { - return; - } if self.flags.report_delayed_bugs { self.emit_diagnostic(&diagnostic); } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 07b5e20b2dd..258320aeb63 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -8,7 +8,7 @@ use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream}; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{self as ast, AstLike, Attribute, Item, NodeId, PatKind}; use rustc_attr::{self as attr, Deprecation, Stability}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported}; use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; @@ -920,8 +920,25 @@ pub trait ResolverExpand { /// we generated proc macros harnesses, so that we can map /// HIR proc macros items back to their harness items. fn declare_proc_macro(&mut self, id: NodeId); + + /// Tools registered with `#![register_tool]` and used by tool attributes and lints. + fn registered_tools(&self) -> &FxHashSet<Ident>; } +pub trait LintStoreExpand { + fn pre_expansion_lint( + &self, + sess: &Session, + registered_tools: &FxHashSet<Ident>, + node_id: NodeId, + attrs: &[Attribute], + items: &[P<Item>], + name: &str, + ); +} + +type LintStoreExpandDyn<'a> = Option<&'a (dyn LintStoreExpand + 'a)>; + #[derive(Clone, Default)] pub struct ModuleData { /// Path to the module starting from the crate name, like `my_crate::foo::bar`. @@ -956,9 +973,6 @@ pub struct ExpansionData { pub is_trailing_mac: bool, } -type OnExternModLoaded<'a> = - Option<&'a dyn Fn(Ident, Vec<Attribute>, Vec<P<Item>>, Span) -> (Vec<Attribute>, Vec<P<Item>>)>; - /// One of these is made during expansion and incrementally updated as we go; /// when a macro expansion occurs, the resulting nodes have the `backtrace() /// -> expn_data` of their expansion context stored into their span. @@ -973,10 +987,8 @@ pub struct ExtCtxt<'a> { /// (or during eager expansion, but that's a hack). pub force_mode: bool, pub expansions: FxHashMap<Span, Vec<String>>, - /// Called directly after having parsed an external `mod foo;` in expansion. - /// - /// `Ident` is the module name. - pub(super) extern_mod_loaded: OnExternModLoaded<'a>, + /// Used for running pre-expansion lints on freshly loaded modules. + pub(super) lint_store: LintStoreExpandDyn<'a>, /// When we 'expand' an inert attribute, we leave it /// in the AST, but insert it here so that we know /// not to expand it again. @@ -988,14 +1000,14 @@ impl<'a> ExtCtxt<'a> { sess: &'a Session, ecfg: expand::ExpansionConfig<'a>, resolver: &'a mut dyn ResolverExpand, - extern_mod_loaded: OnExternModLoaded<'a>, + lint_store: LintStoreExpandDyn<'a>, ) -> ExtCtxt<'a> { ExtCtxt { sess, ecfg, reduced_recursion_limit: None, resolver, - extern_mod_loaded, + lint_store, root_path: PathBuf::new(), current_expansion: ExpansionData { id: LocalExpnId::ROOT, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 7604a464be2..9a4daa6d750 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1097,7 +1097,7 @@ impl InvocationCollectorNode for P<ast::Item> { ModKind::Unloaded => { // We have an outline `mod foo;` so we need to parse the file. let old_attrs_len = attrs.len(); - let ParsedExternalMod { mut items, inner_span, file_path, dir_path, dir_ownership } = + let ParsedExternalMod { items, inner_span, file_path, dir_path, dir_ownership } = parse_external_mod( &ecx.sess, ident, @@ -1107,8 +1107,15 @@ impl InvocationCollectorNode for P<ast::Item> { &mut attrs, ); - if let Some(extern_mod_loaded) = ecx.extern_mod_loaded { - (attrs, items) = extern_mod_loaded(ident, attrs, items, inner_span); + if let Some(lint_store) = ecx.lint_store { + lint_store.pre_expansion_lint( + ecx.sess, + ecx.resolver.registered_tools(), + ecx.current_expansion.lint_node_id, + &attrs, + &items, + ident.name.as_str(), + ); } *mod_kind = ModKind::Loaded(items, Inline::No, inner_span); diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 5599c1df6d9..dfc07da9169 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -2,7 +2,6 @@ #![feature(associated_type_defaults)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] -#![cfg_attr(bootstrap, feature(destructuring_assignment))] #![feature(if_let_guard)] #![feature(let_else)] #![feature(proc_macro_diagnostic)] diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 723cc06864a..fc7f01f041d 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -625,7 +625,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), rustc_attr!( rustc_pass_by_value, Normal, - template!(Word), WarnFollowing, + template!(Word), ErrorFollowing, "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference." ), BuiltinAttribute { @@ -697,6 +697,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_with_negative_coherence, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing), rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing), diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index e839f7fc777..74d6b05ca5f 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -107,8 +107,6 @@ pub struct Definitions { /// Their `HirId`s are defined by their position while lowering the enclosing owner. // FIXME(cjgillot) Some `LocalDefId`s from `use` items are dropped during lowering and lack a `HirId`. pub(super) def_id_to_hir_id: IndexVec<LocalDefId, Option<hir::HirId>>, - /// The reverse mapping of `def_id_to_hir_id`. - pub(super) hir_id_to_def_id: FxHashMap<hir::HirId, LocalDefId>, /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`. expansions_that_defined: FxHashMap<LocalDefId, ExpnId>, @@ -330,11 +328,6 @@ impl Definitions { self.def_id_to_hir_id[id].unwrap() } - #[inline] - pub fn opt_hir_id_to_local_def_id(&self, hir_id: hir::HirId) -> Option<LocalDefId> { - self.hir_id_to_def_id.get(&hir_id).copied() - } - /// Adds a root definition (no parent) and a few other reserved definitions. pub fn new(stable_crate_id: StableCrateId, crate_span: Span) -> Definitions { let key = DefKey { @@ -362,7 +355,6 @@ impl Definitions { Definitions { table, def_id_to_hir_id: Default::default(), - hir_id_to_def_id: Default::default(), expansions_that_defined: Default::default(), def_id_to_span, stable_crate_id, @@ -425,12 +417,6 @@ impl Definitions { "trying to initialize `LocalDefId` <-> `HirId` mappings twice" ); - // Build the reverse mapping of `def_id_to_hir_id`. - self.hir_id_to_def_id = mapping - .iter_enumerated() - .filter_map(|(def_id, hir_id)| hir_id.map(|hir_id| (hir_id, def_id))) - .collect(); - self.def_id_to_hir_id = mapping; } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 4e6fac5eb28..a0ed72c9e9e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -707,6 +707,8 @@ pub struct OwnerNodes<'tcx> { pub nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>, /// Content of local bodies. pub bodies: SortedMap<ItemLocalId, &'tcx Body<'tcx>>, + /// Non-owning definitions contained in this owner. + pub local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>, } /// Full information resulting from lowering an AST node. diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index def0c1d0687..be4849d0b84 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -283,6 +283,7 @@ language_item_table! { PanicInfo, sym::panic_info, panic_info, Target::Struct, GenericRequirement::None; PanicLocation, sym::panic_location, panic_location, Target::Struct, GenericRequirement::None; PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None; + PanicNoUnwind, sym::panic_no_unwind, panic_no_unwind, Target::Fn, GenericRequirement::Exact(0); /// libstd panic entry point. Necessary for const eval to be able to catch it BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None; diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index a43c1f9d9ae..b15054ae6d6 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -208,8 +208,13 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<' fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { // We ignore the `nodes` and `bodies` fields since these refer to information included in // `hash` which is hashed in the collector and used for the crate hash. - let OwnerNodes { hash_including_bodies, hash_without_bodies: _, nodes: _, bodies: _ } = - *self; + let OwnerNodes { + hash_including_bodies, + hash_without_bodies: _, + nodes: _, + bodies: _, + local_id_to_def_id: _, + } = *self; hash_including_bodies.hash_stable(hcx, hasher); } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 9e54122f8dd..a47ebaf1237 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -571,7 +571,7 @@ impl<'a> State<'a> { self.ann.nested(self, Nested::Body(body)); } hir::ItemKind::Macro(ref macro_def) => { - self.print_mac_def(macro_def, &item.ident, &item.span, |state| { + self.print_mac_def(macro_def, &item.ident, item.span, |state| { state.print_visibility(&item.vis) }); } diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index d563a6ca478..870c3f80682 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -158,14 +158,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { // Decode the list of work_products let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos); let work_products: Vec<SerializedWorkProduct> = - Decodable::decode(&mut work_product_decoder).unwrap_or_else(|e| { - let msg = format!( - "Error decoding `work-products` from incremental \ - compilation session directory: {}", - e - ); - sess.fatal(&msg) - }); + Decodable::decode(&mut work_product_decoder); for swp in work_products { let mut all_files_exist = true; @@ -203,8 +196,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { LoadResult::Error { message } => LoadResult::Error { message }, LoadResult::Ok { data: (bytes, start_pos) } => { let mut decoder = Decoder::new(&bytes, start_pos); - let prev_commandline_args_hash = u64::decode(&mut decoder) - .expect("Error reading commandline arg hash from cached dep-graph"); + let prev_commandline_args_hash = u64::decode(&mut decoder); if prev_commandline_args_hash != expected_hash { if report_incremental_info { @@ -220,8 +212,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { return LoadResult::DataOutOfDate; } - let dep_graph = SerializedDepGraph::decode(&mut decoder) - .expect("Error reading cached dep-graph"); + let dep_graph = SerializedDepGraph::decode(&mut decoder); LoadResult::Ok { data: (dep_graph, prev_work_products) } } diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index e3c6528b218..8b61530577d 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -395,8 +395,8 @@ macro_rules! newtype_index { (@serializable $type:ident) => ( impl<D: ::rustc_serialize::Decoder> ::rustc_serialize::Decodable<D> for $type { - fn decode(d: &mut D) -> Result<Self, D::Error> { - d.read_u32().map(Self::from_u32) + fn decode(d: &mut D) -> Self { + Self::from_u32(d.read_u32()) } } impl<E: ::rustc_serialize::Encoder> ::rustc_serialize::Encodable<E> for $type { @@ -527,8 +527,8 @@ impl<S: Encoder, I: Idx, T: Encodable<S>> Encodable<S> for &IndexVec<I, T> { } impl<D: Decoder, I: Idx, T: Decodable<D>> Decodable<D> for IndexVec<I, T> { - fn decode(d: &mut D) -> Result<Self, D::Error> { - Decodable::decode(d).map(|v| IndexVec { raw: v, _marker: PhantomData }) + fn decode(d: &mut D) -> Self { + IndexVec { raw: Decodable::decode(d), _marker: PhantomData } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 14ab635a2ae..1eb8190bd7d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2650,7 +2650,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { infer::LateBoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!( " for lifetime parameter {}in trait containing associated type `{}`", br_string(br), - self.tcx.associated_item(def_id).ident + self.tcx.associated_item(def_id).name ), infer::EarlyBoundRegion(_, name) => format!(" for lifetime parameter `{}`", name), infer::UpvarRegion(ref upvar_id, _) => { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 412a077959d..0a9f59fbc97 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -70,7 +70,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { .map(|s| format!("`{}`", s)) .unwrap_or_else(|| "`fn` parameter".to_string()), lifetime, - ctxt.assoc_item.ident, + ctxt.assoc_item.name, ); err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime)); err.span_label( @@ -231,7 +231,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // Handle case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a // `'static` lifetime when called as a method on a binding: `bar.qux()`. if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) { - override_error_code = Some(ctxt.assoc_item.ident); + override_error_code = Some(ctxt.assoc_item.name); } } } @@ -252,7 +252,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { self.get_impl_ident_and_self_ty_from_trait(*item_def_id, &v.0) { if self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0, ident, self_ty) { - override_error_code = Some(ident); + override_error_code = Some(ident.name); } } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 266eec08ceb..d1b24b332bd 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -195,7 +195,7 @@ pub struct InferCtxtInner<'tcx> { // Opaque types found in explicit return types and their // associated fresh inference variable. Writeback resolves these // variables to get the concrete type, which can be used to - // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions. + // 'de-opaque' OpaqueTypeDecl outside of type inference. pub opaque_types: OpaqueTypeMap<'tcx>, /// A map from inference variables created from opaque diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 4851e637d3a..e7dca94806c 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -569,13 +569,15 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { let predicate = predicate.fold_with(&mut BottomUpFolder { tcx, ty_op: |ty| match ty.kind() { - ty::Projection(projection_ty) => infcx.infer_projection( - self.param_env, - *projection_ty, - traits::ObligationCause::misc(self.value_span, self.body_id), - 0, - &mut self.obligations, - ), + ty::Projection(projection_ty) if !projection_ty.has_escaping_bound_vars() => { + infcx.infer_projection( + self.param_env, + *projection_ty, + traits::ObligationCause::misc(self.value_span, self.body_id), + 0, + &mut self.obligations, + ) + } _ => ty, }, lt_op: |lt| lt, diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 3804e100307..26343561959 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -124,7 +124,16 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String Err(errs) => errs.into_iter().for_each(|mut err| err.cancel()), } - error!(r#"expected `key` or `key="value"`"#); + // If the user tried to use a key="value" flag, but is missing the quotes, provide + // a hint about how to resolve this. + if s.contains("=") && !s.contains("=\"") && !s.ends_with("\"") { + error!(concat!( + r#"expected `key` or `key="value"`, ensure escaping is appropriate"#, + r#" for your shell, try 'key="value"' or key=\"value\""# + )); + } else { + error!(r#"expected `key` or `key="value"`"#); + } }) .collect::<CrateConfig>(); cfg.into_iter().map(|(a, b)| (a.to_string(), b.map(|b| b.to_string()))).collect() diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 2fc3759968f..b911b108a73 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,5 +1,6 @@ #![feature(bool_to_option)] #![feature(box_patterns)] +#![feature(let_else)] #![feature(internal_output_capture)] #![feature(thread_spawn_unchecked)] #![feature(nll)] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 33bf670f570..be31eb89f1b 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -3,7 +3,7 @@ use crate::proc_macro_decls; use crate::util; use rustc_ast::mut_visit::MutVisitor; -use rustc_ast::{self as ast, visit, DUMMY_NODE_ID}; +use rustc_ast::{self as ast, visit}; use rustc_borrowck as mir_borrowck; use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_ssa::traits::CodegenBackend; @@ -11,16 +11,16 @@ use rustc_data_structures::parallel; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::{Applicability, ErrorReported, PResult}; -use rustc_expand::base::ExtCtxt; +use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand}; use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE}; use rustc_hir::Crate; -use rustc_lint::LintStore; +use rustc_lint::{EarlyCheckNode, LintStore}; use rustc_metadata::creader::CStore; use rustc_metadata::{encode_metadata, EncodedMetadata}; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; use rustc_middle::ty::query::{ExternProviders, Providers}; -use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt}; +use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, ResolverOutputs, TyCtxt}; use rustc_mir_build as mir_build; use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr}; use rustc_passes::{self, hir_stats, layout_test}; @@ -34,7 +34,7 @@ use rustc_session::lint; use rustc_session::output::{filename_for_input, filename_for_metadata}; use rustc_session::search_paths::PathKind; use rustc_session::{Limit, Session}; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{sym, Symbol}; use rustc_span::{FileName, MultiSpan}; use rustc_trait_selection::traits; use rustc_typeck as typeck; @@ -233,26 +233,43 @@ pub fn register_plugins<'a>( Ok((krate, lint_store)) } -fn pre_expansion_lint( +fn pre_expansion_lint<'a>( sess: &Session, lint_store: &LintStore, - krate: &ast::Crate, - crate_attrs: &[ast::Attribute], - crate_name: &str, + registered_tools: &RegisteredTools, + check_node: impl EarlyCheckNode<'a>, + node_name: &str, ) { - sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", crate_name).run(|| { - rustc_lint::check_ast_crate( + sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", node_name).run(|| { + rustc_lint::check_ast_node( sess, - lint_store, - krate, - crate_attrs, true, + lint_store, + registered_tools, None, rustc_lint::BuiltinCombinedPreExpansionLintPass::new(), + check_node, ); }); } +// Cannot implement directly for `LintStore` due to trait coherence. +struct LintStoreExpandImpl<'a>(&'a LintStore); + +impl LintStoreExpand for LintStoreExpandImpl<'_> { + fn pre_expansion_lint( + &self, + sess: &Session, + registered_tools: &RegisteredTools, + node_id: ast::NodeId, + attrs: &[ast::Attribute], + items: &[rustc_ast::ptr::P<ast::Item>], + name: &str, + ) { + pre_expansion_lint(sess, self.0, registered_tools, (node_id, attrs, items), name); + } +} + /// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins, /// syntax expansion, secondary `cfg` expansion, synthesis of a test /// harness if one is to be provided, injection of a dependency on the @@ -265,7 +282,7 @@ pub fn configure_and_expand( resolver: &mut Resolver<'_>, ) -> Result<ast::Crate> { tracing::trace!("configure_and_expand"); - pre_expansion_lint(sess, lint_store, &krate, &krate.attrs, crate_name); + pre_expansion_lint(sess, lint_store, resolver.registered_tools(), &krate, crate_name); rustc_builtin_macros::register_builtin_macros(resolver); krate = sess.time("crate_injection", || { @@ -321,13 +338,8 @@ pub fn configure_and_expand( ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string()) }; - let crate_attrs = krate.attrs.clone(); - let extern_mod_loaded = |ident: Ident, attrs, items, span| { - let krate = ast::Crate { attrs, items, span, id: DUMMY_NODE_ID, is_placeholder: false }; - pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, ident.name.as_str()); - (krate.attrs, krate.items) - }; - let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&extern_mod_loaded)); + let lint_store = LintStoreExpandImpl(lint_store); + let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&lint_store)); // Expand macros now! let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate)); @@ -499,14 +511,15 @@ pub fn lower_to_hir<'res, 'tcx>( ); sess.time("early_lint_checks", || { - rustc_lint::check_ast_crate( + let lint_buffer = Some(std::mem::take(resolver.lint_buffer())); + rustc_lint::check_ast_node( sess, - lint_store, - &krate, - &krate.attrs, false, - Some(std::mem::take(resolver.lint_buffer())), + lint_store, + resolver.registered_tools(), + lint_buffer, rustc_lint::BuiltinCombinedEarlyLintPass::new(), + &*krate, ) }); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 3921187baa5..6d9183eda9d 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -717,57 +717,57 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> { } fn should_ignore_fn(ret_ty: &ast::FnRetTy) -> bool { - if let ast::FnRetTy::Ty(ref ty) = ret_ty { - fn involves_impl_trait(ty: &ast::Ty) -> bool { - match ty.kind { - ast::TyKind::ImplTrait(..) => true, - ast::TyKind::Slice(ref subty) - | ast::TyKind::Array(ref subty, _) - | ast::TyKind::Ptr(ast::MutTy { ty: ref subty, .. }) - | ast::TyKind::Rptr(_, ast::MutTy { ty: ref subty, .. }) - | ast::TyKind::Paren(ref subty) => involves_impl_trait(subty), - ast::TyKind::Tup(ref tys) => any_involves_impl_trait(tys.iter()), - ast::TyKind::Path(_, ref path) => { - path.segments.iter().any(|seg| match seg.args.as_deref() { - None => false, - Some(&ast::GenericArgs::AngleBracketed(ref data)) => { - data.args.iter().any(|arg| match arg { - ast::AngleBracketedArg::Arg(arg) => match arg { - ast::GenericArg::Type(ty) => involves_impl_trait(ty), - ast::GenericArg::Lifetime(_) - | ast::GenericArg::Const(_) => false, - }, - ast::AngleBracketedArg::Constraint(c) => match c.kind { - ast::AssocConstraintKind::Bound { .. } => true, - ast::AssocConstraintKind::Equality { ref term } => { - match term { - Term::Ty(ty) => involves_impl_trait(ty), - // FIXME(...): This should check if the constant - // involves a trait impl, but for now ignore. - Term::Const(_) => false, - } + let ast::FnRetTy::Ty(ref ty) = ret_ty else { + return false; + }; + fn involves_impl_trait(ty: &ast::Ty) -> bool { + match ty.kind { + ast::TyKind::ImplTrait(..) => true, + ast::TyKind::Slice(ref subty) + | ast::TyKind::Array(ref subty, _) + | ast::TyKind::Ptr(ast::MutTy { ty: ref subty, .. }) + | ast::TyKind::Rptr(_, ast::MutTy { ty: ref subty, .. }) + | ast::TyKind::Paren(ref subty) => involves_impl_trait(subty), + ast::TyKind::Tup(ref tys) => any_involves_impl_trait(tys.iter()), + ast::TyKind::Path(_, ref path) => { + path.segments.iter().any(|seg| match seg.args.as_deref() { + None => false, + Some(&ast::GenericArgs::AngleBracketed(ref data)) => { + data.args.iter().any(|arg| match arg { + ast::AngleBracketedArg::Arg(arg) => match arg { + ast::GenericArg::Type(ty) => involves_impl_trait(ty), + ast::GenericArg::Lifetime(_) | ast::GenericArg::Const(_) => { + false + } + }, + ast::AngleBracketedArg::Constraint(c) => match c.kind { + ast::AssocConstraintKind::Bound { .. } => true, + ast::AssocConstraintKind::Equality { ref term } => { + match term { + Term::Ty(ty) => involves_impl_trait(ty), + // FIXME(...): This should check if the constant + // involves a trait impl, but for now ignore. + Term::Const(_) => false, } - }, - }) - } - Some(&ast::GenericArgs::Parenthesized(ref data)) => { - any_involves_impl_trait(data.inputs.iter()) - || ReplaceBodyWithLoop::should_ignore_fn(&data.output) - } - }) - } - _ => false, + } + }, + }) + } + Some(&ast::GenericArgs::Parenthesized(ref data)) => { + any_involves_impl_trait(data.inputs.iter()) + || ReplaceBodyWithLoop::should_ignore_fn(&data.output) + } + }) } + _ => false, } + } - fn any_involves_impl_trait<'a, I: Iterator<Item = &'a P<ast::Ty>>>(mut it: I) -> bool { - it.any(|subty| involves_impl_trait(subty)) - } - - involves_impl_trait(ty) - } else { - false + fn any_involves_impl_trait<'a, I: Iterator<Item = &'a P<ast::Ty>>>(mut it: I) -> bool { + it.any(|subty| involves_impl_trait(subty)) } + + involves_impl_trait(ty) } fn is_sig_const(sig: &ast::FnSig) -> bool { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 65385d4c7a1..9b24f43f7fd 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -912,7 +912,7 @@ declare_lint_pass!( impl EarlyLintPass for AnonymousParameters { fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) { - if cx.sess.edition() != Edition::Edition2015 { + if cx.sess().edition() != Edition::Edition2015 { // This is a hard error in future editions; avoid linting and erroring return; } @@ -921,7 +921,7 @@ impl EarlyLintPass for AnonymousParameters { if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind { if ident.name == kw::Empty { cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| { - let ty_snip = cx.sess.source_map().span_to_snippet(arg.ty.span); + let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span); let (ty_snip, appl) = if let Ok(ref snip) = ty_snip { (snip.as_str(), Applicability::MachineApplicable) @@ -1775,7 +1775,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { }; if join.edition() >= Edition::Edition2021 { let mut err = - rustc_errors::struct_span_err!(cx.sess, pat.span, E0783, "{}", msg,); + rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,); err.span_suggestion( pat.span, suggestion, @@ -1799,7 +1799,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { let replace = "..=".to_owned(); if join.edition() >= Edition::Edition2021 { let mut err = - rustc_errors::struct_span_err!(cx.sess, pat.span, E0783, "{}", msg,); + rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,); err.span_suggestion_short( join, suggestion, @@ -1983,7 +1983,7 @@ impl KeywordIdents { UnderMacro(under_macro): UnderMacro, ident: Ident, ) { - let next_edition = match cx.sess.edition() { + let next_edition = match cx.sess().edition() { Edition::Edition2015 => { match ident.name { kw::Async | kw::Await | kw::Try => Edition::Edition2018, @@ -2011,7 +2011,7 @@ impl KeywordIdents { }; // Don't lint `r#foo`. - if cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) { + if cx.sess().parse_sess.raw_identifier_spans.borrow().contains(&ident.span) { return; } @@ -2379,7 +2379,7 @@ declare_lint_pass!( impl EarlyLintPass for IncompleteFeatures { fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { - let features = cx.sess.features_untracked(); + let features = cx.sess().features_untracked(); features .declared_lang_features .iter() @@ -3158,7 +3158,10 @@ declare_lint! { /// of this, GNU assembler [local labels] *must* be used instead of labels /// with a name. Using named labels might cause assembler or linker errors. /// + /// See the explanation in [Rust By Example] for more details. + /// /// [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels + /// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels pub NAMED_ASM_LABELS, Deny, "named labels in inline assembly", diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 69c376c6169..cb08e952586 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -16,10 +16,9 @@ use self::TargetLint::*; -use crate::levels::{is_known_lint_tool, LintLevelsBuilder}; +use crate::levels::LintLevelsBuilder; use crate::passes::{EarlyLintPassObject, LateLintPassObject}; -use ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; -use rustc_ast as ast; +use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync; use rustc_errors::{struct_span_err, Applicability, SuggestionStyle}; @@ -32,13 +31,14 @@ use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::stability; use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt}; +use rustc_middle::ty::{self, print::Printer, subst::GenericArg, RegisteredTools, Ty, TyCtxt}; use rustc_serialize::json::Json; use rustc_session::lint::{BuiltinLintDiagnostics, ExternDepSpec}; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; use rustc_session::Session; use rustc_span::lev_distance::find_best_match_for_name; -use rustc_span::{symbol::Symbol, BytePos, MultiSpan, Span, DUMMY_SP}; +use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; use rustc_target::abi; use tracing::debug; @@ -313,7 +313,7 @@ impl LintStore { sess: &Session, lint_name: &str, level: Level, - crate_attrs: &[ast::Attribute], + registered_tools: &RegisteredTools, ) { let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name); if lint_name_only == crate::WARNINGS.name_lower() && level == Level::ForceWarn { @@ -326,7 +326,7 @@ impl LintStore { ) .emit(); } - let db = match self.check_lint_name(sess, lint_name_only, tool_name, crate_attrs) { + let db = match self.check_lint_name(lint_name_only, tool_name, registered_tools) { CheckLintNameResult::Ok(_) => None, CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)), CheckLintNameResult::NoLint(suggestion) => { @@ -397,13 +397,16 @@ impl LintStore { /// printing duplicate warnings. pub fn check_lint_name( &self, - sess: &Session, lint_name: &str, tool_name: Option<Symbol>, - crate_attrs: &[ast::Attribute], + registered_tools: &RegisteredTools, ) -> CheckLintNameResult<'_> { if let Some(tool_name) = tool_name { - if !is_known_lint_tool(tool_name, sess, crate_attrs) { + // FIXME: rustc and rustdoc are considered tools for lints, but not for attributes. + if tool_name != sym::rustc + && tool_name != sym::rustdoc + && !registered_tools.contains(&Ident::with_dummy_span(tool_name)) + { return CheckLintNameResult::NoTool; } } @@ -521,7 +524,7 @@ impl LintStore { } } -/// Context for lint checking after type checking. +/// Context for lint checking outside of type inference. pub struct LateContext<'tcx> { /// Type context we're checking in. pub tcx: TyCtxt<'tcx>, @@ -553,20 +556,9 @@ pub struct LateContext<'tcx> { pub only_module: bool, } -/// Context for lint checking of the AST, after expansion, before lowering to -/// HIR. +/// Context for lint checking of the AST, after expansion, before lowering to HIR. pub struct EarlyContext<'a> { - /// Type context we're checking in. - pub sess: &'a Session, - - /// The crate being checked. - pub krate: &'a ast::Crate, - pub builder: LintLevelsBuilder<'a>, - - /// The store of registered lints and the lint levels. - pub lint_store: &'a LintStore, - pub buffered: LintBuffer, } @@ -770,6 +762,7 @@ pub trait LintContext: Sized { } BuiltinLintDiagnostics::NamedAsmLabel(help) => { db.help(&help); + db.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information"); } } // Rewrap `db`, and pass control to the user. @@ -801,19 +794,20 @@ pub trait LintContext: Sized { } impl<'a> EarlyContext<'a> { - pub fn new( + pub(crate) fn new( sess: &'a Session, + warn_about_weird_lints: bool, lint_store: &'a LintStore, - krate: &'a ast::Crate, - crate_attrs: &'a [ast::Attribute], + registered_tools: &'a RegisteredTools, buffered: LintBuffer, - warn_about_weird_lints: bool, ) -> EarlyContext<'a> { EarlyContext { - sess, - krate, - lint_store, - builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store, crate_attrs), + builder: LintLevelsBuilder::new( + sess, + warn_about_weird_lints, + lint_store, + registered_tools, + ), buffered, } } @@ -851,11 +845,11 @@ impl LintContext for EarlyContext<'_> { /// Gets the overall compiler `Session` object. fn sess(&self) -> &Session { - &self.sess + &self.builder.sess() } fn lints(&self) -> &LintStore { - &*self.lint_store + self.builder.lint_store() } fn lookup<S: Into<MultiSpan>>( diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 0bba66d3838..1b2c88867d4 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -16,9 +16,11 @@ use crate::context::{EarlyContext, LintContext, LintStore}; use crate::passes::{EarlyLintPass, EarlyLintPassObject}; -use rustc_ast as ast; -use rustc_ast::visit as ast_visit; +use rustc_ast::ptr::P; +use rustc_ast::visit::{self as ast_visit, Visitor}; use rustc_ast::AstLike; +use rustc_ast::{self as ast, walk_list}; +use rustc_middle::ty::RegisteredTools; use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass}; use rustc_session::Session; use rustc_span::symbol::Ident; @@ -31,7 +33,7 @@ macro_rules! run_early_pass { ($cx:expr, $f:ident, $($args:expr),*) => ({ $cx.pass.$f(&$cx.context, $($args),*); }) } -struct EarlyContextAndPass<'a, T: EarlyLintPass> { +pub struct EarlyContextAndPass<'a, T: EarlyLintPass> { context: EarlyContext<'a>, pass: T, } @@ -57,7 +59,7 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { F: FnOnce(&mut Self), { let is_crate_node = id == ast::CRATE_NODE_ID; - let push = self.context.builder.push(attrs, &self.context.lint_store, is_crate_node); + let push = self.context.builder.push(attrs, is_crate_node); self.check_id(id); self.enter_attrs(attrs); f(self); @@ -325,48 +327,89 @@ macro_rules! early_lint_pass_impl { crate::early_lint_methods!(early_lint_pass_impl, []); -fn early_lint_crate<T: EarlyLintPass>( +/// Early lints work on different nodes - either on the crate root, or on freshly loaded modules. +/// This trait generalizes over those nodes. +pub trait EarlyCheckNode<'a>: Copy { + fn id(self) -> ast::NodeId; + fn attrs<'b>(self) -> &'b [ast::Attribute] + where + 'a: 'b; + fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>) + where + 'a: 'b; +} + +impl<'a> EarlyCheckNode<'a> for &'a ast::Crate { + fn id(self) -> ast::NodeId { + ast::CRATE_NODE_ID + } + fn attrs<'b>(self) -> &'b [ast::Attribute] + where + 'a: 'b, + { + &self.attrs + } + fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>) + where + 'a: 'b, + { + run_early_pass!(cx, check_crate, self); + ast_visit::walk_crate(cx, self); + run_early_pass!(cx, check_crate_post, self); + } +} + +impl<'a> EarlyCheckNode<'a> for (ast::NodeId, &'a [ast::Attribute], &'a [P<ast::Item>]) { + fn id(self) -> ast::NodeId { + self.0 + } + fn attrs<'b>(self) -> &'b [ast::Attribute] + where + 'a: 'b, + { + self.1 + } + fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>) + where + 'a: 'b, + { + walk_list!(cx, visit_attribute, self.1); + walk_list!(cx, visit_item, self.2); + } +} + +fn early_lint_node<'a>( sess: &Session, + warn_about_weird_lints: bool, lint_store: &LintStore, - krate: &ast::Crate, - crate_attrs: &[ast::Attribute], - pass: T, + registered_tools: &RegisteredTools, buffered: LintBuffer, - warn_about_weird_lints: bool, + pass: impl EarlyLintPass, + check_node: impl EarlyCheckNode<'a>, ) -> LintBuffer { let mut cx = EarlyContextAndPass { context: EarlyContext::new( sess, + warn_about_weird_lints, lint_store, - krate, - crate_attrs, + registered_tools, buffered, - warn_about_weird_lints, ), pass, }; - // Visit the whole crate. - cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| { - // since the root module isn't visited as an item (because it isn't an - // item), warn for it here. - run_early_pass!(cx, check_crate, krate); - - ast_visit::walk_crate(cx, krate); - - run_early_pass!(cx, check_crate_post, krate); - }); + cx.with_lint_attrs(check_node.id(), check_node.attrs(), |cx| check_node.check(cx)); cx.context.buffered } -pub fn check_ast_crate<T: EarlyLintPass>( +pub fn check_ast_node<'a>( sess: &Session, - lint_store: &LintStore, - krate: &ast::Crate, - crate_attrs: &[ast::Attribute], pre_expansion: bool, + lint_store: &LintStore, + registered_tools: &RegisteredTools, lint_buffer: Option<LintBuffer>, - builtin_lints: T, + builtin_lints: impl EarlyLintPass, + check_node: impl EarlyCheckNode<'a>, ) { let passes = if pre_expansion { &lint_store.pre_expansion_passes } else { &lint_store.early_passes }; @@ -374,39 +417,39 @@ pub fn check_ast_crate<T: EarlyLintPass>( let mut buffered = lint_buffer.unwrap_or_default(); if !sess.opts.debugging_opts.no_interleave_lints { - buffered = early_lint_crate( + buffered = early_lint_node( sess, + pre_expansion, lint_store, - krate, - crate_attrs, - builtin_lints, + registered_tools, buffered, - pre_expansion, + builtin_lints, + check_node, ); if !passes.is_empty() { - buffered = early_lint_crate( + buffered = early_lint_node( sess, + false, lint_store, - krate, - crate_attrs, - EarlyLintPassObjects { lints: &mut passes[..] }, + registered_tools, buffered, - false, + EarlyLintPassObjects { lints: &mut passes[..] }, + check_node, ); } } else { for (i, pass) in passes.iter_mut().enumerate() { buffered = sess.prof.extra_verbose_generic_activity("run_lint", pass.name()).run(|| { - early_lint_crate( + early_lint_node( sess, + pre_expansion && i == 0, lint_store, - krate, - crate_attrs, - EarlyLintPassObjects { lints: slice::from_mut(pass) }, + registered_tools, buffered, - pre_expansion && i == 0, + EarlyLintPassObjects { lints: slice::from_mut(pass) }, + check_node, ) }); } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 7353cd6b876..d8e1162890c 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { lint.build(&format!("usage of qualified `ty::{}`", t)) .span_suggestion( path.span, - "try using it unqualified", + "try importing it and using it unqualified", t, // The import probably needs to be changed Applicability::MaybeIncorrect, diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 6e95708b17f..8afbd462c14 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -5,7 +5,7 @@ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; -use rustc_hir::{intravisit, HirId, CRATE_HIR_ID}; +use rustc_hir::{intravisit, HirId}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::LevelAndSource; use rustc_middle::lint::LintDiagnosticBuilder; @@ -14,7 +14,7 @@ use rustc_middle::lint::{ COMMAND_LINE, }; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{RegisteredTools, TyCtxt}; use rustc_session::lint::{ builtin::{self, FORBIDDEN_LINT_GROUPS}, Level, Lint, LintId, @@ -27,14 +27,14 @@ use tracing::debug; fn lint_levels(tcx: TyCtxt<'_>, (): ()) -> LintLevelMap { let store = unerased_lint_store(tcx); - let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID); - let levels = LintLevelsBuilder::new(tcx.sess, false, &store, crate_attrs); - let mut builder = LintLevelMapBuilder { levels, tcx, store }; + let levels = + LintLevelsBuilder::new(tcx.sess, false, &store, &tcx.resolutions(()).registered_tools); + let mut builder = LintLevelMapBuilder { levels, tcx }; let krate = tcx.hir().krate(); builder.levels.id_to_set.reserve(krate.owners.len() + 1); - let push = builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), &store, true); + let push = builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), true); builder.levels.register_id(hir::CRATE_HIR_ID); tcx.hir().walk_toplevel_module(&mut builder); builder.levels.pop(push); @@ -49,7 +49,7 @@ pub struct LintLevelsBuilder<'s> { cur: LintStackIndex, warn_about_weird_lints: bool, store: &'s LintStore, - crate_attrs: &'s [ast::Attribute], + registered_tools: &'s RegisteredTools, } pub struct BuilderPush { @@ -62,7 +62,7 @@ impl<'s> LintLevelsBuilder<'s> { sess: &'s Session, warn_about_weird_lints: bool, store: &'s LintStore, - crate_attrs: &'s [ast::Attribute], + registered_tools: &'s RegisteredTools, ) -> Self { let mut builder = LintLevelsBuilder { sess, @@ -71,19 +71,27 @@ impl<'s> LintLevelsBuilder<'s> { id_to_set: Default::default(), warn_about_weird_lints, store, - crate_attrs, + registered_tools, }; builder.process_command_line(sess, store); assert_eq!(builder.sets.list.len(), 1); builder } + pub(crate) fn sess(&self) -> &Session { + self.sess + } + + pub(crate) fn lint_store(&self) -> &LintStore { + self.store + } + fn process_command_line(&mut self, sess: &Session, store: &LintStore) { let mut specs = FxHashMap::default(); self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid); for &(ref lint_name, level) in &sess.opts.lint_opts { - store.check_lint_name_cmdline(sess, &lint_name, level, self.crate_attrs); + store.check_lint_name_cmdline(sess, &lint_name, level, self.registered_tools); let orig_level = level; let lint_flag_val = Symbol::intern(lint_name); @@ -217,12 +225,7 @@ impl<'s> LintLevelsBuilder<'s> { /// `#[allow]` /// /// Don't forget to call `pop`! - pub(crate) fn push( - &mut self, - attrs: &[ast::Attribute], - store: &LintStore, - is_crate_node: bool, - ) -> BuilderPush { + pub(crate) fn push(&mut self, attrs: &[ast::Attribute], is_crate_node: bool) -> BuilderPush { let mut specs = FxHashMap::default(); let sess = self.sess; let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input"); @@ -310,7 +313,8 @@ impl<'s> LintLevelsBuilder<'s> { }; let tool_name = tool_ident.map(|ident| ident.name); let name = pprust::path_to_string(&meta_item.path); - let lint_result = store.check_lint_name(sess, &name, tool_name, self.crate_attrs); + let lint_result = + self.store.check_lint_name(&name, tool_name, self.registered_tools); match &lint_result { CheckLintNameResult::Ok(ids) => { let src = LintLevelSource::Node( @@ -459,7 +463,7 @@ impl<'s> LintLevelsBuilder<'s> { // Ignore any errors or warnings that happen because the new name is inaccurate // NOTE: `new_name` already includes the tool name, so we don't have to add it again. if let CheckLintNameResult::Ok(ids) = - store.check_lint_name(sess, &new_name, None, self.crate_attrs) + self.store.check_lint_name(&new_name, None, self.registered_tools) { let src = LintLevelSource::Node(Symbol::intern(&new_name), sp, reason); for &id in ids { @@ -562,34 +566,19 @@ impl<'s> LintLevelsBuilder<'s> { } } -pub fn is_known_lint_tool(m_item: Symbol, sess: &Session, attrs: &[ast::Attribute]) -> bool { - if [sym::clippy, sym::rustc, sym::rustdoc].contains(&m_item) { - return true; - } - // Look for registered tools - // NOTE: does no error handling; error handling is done by rustc_resolve. - sess.filter_by_name(attrs, sym::register_tool) - .filter_map(|attr| attr.meta_item_list()) - .flatten() - .filter_map(|nested_meta| nested_meta.ident()) - .map(|ident| ident.name) - .any(|name| name == m_item) -} - -struct LintLevelMapBuilder<'a, 'tcx> { +struct LintLevelMapBuilder<'tcx> { levels: LintLevelsBuilder<'tcx>, tcx: TyCtxt<'tcx>, - store: &'a LintStore, } -impl LintLevelMapBuilder<'_, '_> { +impl LintLevelMapBuilder<'_> { fn with_lint_attrs<F>(&mut self, id: hir::HirId, f: F) where F: FnOnce(&mut Self), { let is_crate_hir = id == hir::CRATE_HIR_ID; let attrs = self.tcx.hir().attrs(id); - let push = self.levels.push(attrs, self.store, is_crate_hir); + let push = self.levels.push(attrs, is_crate_hir); if push.changed { self.levels.register_id(id); } @@ -598,7 +587,7 @@ impl LintLevelMapBuilder<'_, '_> { } } -impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'_, 'tcx> { +impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> { type NestedFilter = nested_filter::All; fn nested_visit_map(&mut self) -> Self::Map { diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 4aa8505c940..a87f2b2768d 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -96,7 +96,7 @@ use unused::*; pub use builtin::SoftLints; pub use context::{CheckLintNameResult, FindLintError, LintStore}; pub use context::{EarlyContext, LateContext, LintContext}; -pub use early::check_ast_crate; +pub use early::{check_ast_node, EarlyCheckNode}; pub use late::check_crate; pub use passes::{EarlyLintPass, LateLintPass}; pub use rustc_session::lint::Level::{self, *}; @@ -481,6 +481,11 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { <https://github.com/rust-lang/rust/issues/59014> for more information", ); store.register_removed("plugin_as_library", "plugins have been deprecated and retired"); + store.register_removed( + "unsupported_naked_functions", + "converted into hard error, see RFC 2972 \ + <https://github.com/rust-lang/rfcs/blob/master/text/2972-constrained-naked.md> for more information", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index a570206f1ee..2dd6dbd67a8 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -166,7 +166,7 @@ impl EarlyLintPass for NonAsciiIdents { } let mut has_non_ascii_idents = false; - let symbols = cx.sess.parse_sess.symbol_gallery.symbols.lock(); + let symbols = cx.sess().parse_sess.symbol_gallery.symbols.lock(); // Sort by `Span` so that error messages make sense with respect to the // order of identifier locations in the code. diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index a919b3c82aa..6bf25732f60 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -336,5 +336,5 @@ fn is_arg_inside_call(arg: Span, call: Span) -> bool { // panic call in the source file, to avoid invalid suggestions when macros are involved. // We specifically check for the spans to not be identical, as that happens sometimes when // proc_macros lie about spans and apply the same span to all the tokens they produce. - call.contains(arg) && !call.source_equal(&arg) + call.contains(arg) && !call.source_equal(arg) } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index be7756b0f28..f73388c675e 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -164,7 +164,7 @@ impl EarlyLintPass for NonCamelCaseTypes { let has_repr_c = it .attrs .iter() - .any(|attr| attr::find_repr_attrs(&cx.sess, attr).contains(&attr::ReprC)); + .any(|attr| attr::find_repr_attrs(cx.sess(), attr).contains(&attr::ReprC)); if has_repr_c { return; diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index 26d0560bf89..2caf929788f 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -76,10 +76,10 @@ fn gen_args(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> String { .map(|arg| match arg { GenericArg::Lifetime(lt) => lt.name.ident().to_string(), GenericArg::Type(ty) => { - cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_default() + cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_else(|_| "_".into()) } GenericArg::Const(c) => { - cx.tcx.sess.source_map().span_to_snippet(c.span).unwrap_or_default() + cx.tcx.sess.source_map().span_to_snippet(c.span).unwrap_or_else(|_| "_".into()) } GenericArg::Infer(_) => String::from("_"), }) diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index dafff640b36..4c7f3482776 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -86,7 +86,6 @@ declare_lint_pass!( impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { - use rustc_middle::ty; use rustc_middle::ty::PredicateKind::*; let predicates = cx.tcx.explicit_predicates_of(item.def_id); @@ -94,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { let Trait(trait_predicate) = predicate.kind().skip_binder() else { continue }; - if trait_predicate.constness == ty::BoundConstness::ConstIfConst { + if trait_predicate.is_const_if_const() { // `~const Drop` definitely have meanings so avoid linting here. continue; } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index c2f6118227a..4af68233f0d 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2456,6 +2456,10 @@ declare_lint! { /// register size, to alert you of possibly using the incorrect width. To /// fix this, add the suggested modifier to the template, or cast the /// value to the correct size. + /// + /// See [register template modifiers] in the reference for more details. + /// + /// [register template modifiers]: https://doc.rust-lang.org/nightly/reference/inline-assembly.html#template-modifiers pub ASM_SUB_REGISTER, Warn, "using only a subset of a register for inline asm inputs", @@ -2760,52 +2764,6 @@ declare_lint! { } declare_lint! { - /// The `unsupported_naked_functions` lint detects naked function - /// definitions that are unsupported but were previously accepted. - /// - /// ### Example - /// - /// ```rust - /// #![feature(naked_functions)] - /// - /// #[naked] - /// pub extern "C" fn f() -> u32 { - /// 42 - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// The naked functions must be defined using a single inline assembly - /// block. - /// - /// The execution must never fall through past the end of the assembly - /// code so the block must use `noreturn` option. The asm block can also - /// use `att_syntax` option, but other options are not allowed. - /// - /// The asm block must not contain any operands other than `const` and - /// `sym`. Additionally, naked function should specify a non-Rust ABI. - /// - /// Naked functions cannot be inlined. All forms of the `inline` attribute - /// are prohibited. - /// - /// While other definitions of naked functions were previously accepted, - /// they are unsupported and might not work reliably. This is a - /// [future-incompatible] lint that will transition into hard error in - /// the future. - /// - /// [future-incompatible]: ../index.md#future-incompatible-lints - pub UNSUPPORTED_NAKED_FUNCTIONS, - Warn, - "unsupported naked function definitions", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #32408 <https://github.com/rust-lang/rust/issues/32408>", - }; -} - -declare_lint! { /// The `ineffective_unstable_trait_impl` lint detects `#[unstable]` attributes which are not used. /// /// ### Example @@ -3070,7 +3028,6 @@ declare_lint_pass! { UNINHABITED_STATIC, FUNCTION_ITEM_REFERENCES, USELESS_DEPRECATED, - UNSUPPORTED_NAKED_FUNCTIONS, MISSING_ABI, INVALID_DOC_ATTRIBUTES, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 97f6df51f88..3b5d636124d 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -282,7 +282,7 @@ pub enum ExternDepSpec { // This could be a closure, but then implementing derive trait // becomes hacky (and it gets allocated). -#[derive(PartialEq, Debug)] +#[derive(Debug)] pub enum BuiltinLintDiagnostics { Normal, AbsPathWithModule(Span), @@ -309,7 +309,6 @@ pub enum BuiltinLintDiagnostics { /// Lints that are buffered up early on in the `Session` before the /// `LintLevels` is calculated. -#[derive(PartialEq)] pub struct BufferedEarlyLint { /// The span of code that we are linting on. pub span: MultiSpan, @@ -336,9 +335,7 @@ pub struct LintBuffer { impl LintBuffer { pub fn add_early_lint(&mut self, early_lint: BufferedEarlyLint) { let arr = self.map.entry(early_lint.node_id).or_default(); - if !arr.contains(&early_lint) { - arr.push(early_lint); - } + arr.push(early_lint); } pub fn add_lint( diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index c21e4acbefe..dcd6327c92f 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -722,9 +722,12 @@ extern "C" bool LLVMRustIsRustLLVM() { #endif } -extern "C" void LLVMRustAddModuleFlag(LLVMModuleRef M, const char *Name, - uint32_t Value) { - unwrap(M)->addModuleFlag(Module::Warning, Name, Value); +extern "C" void LLVMRustAddModuleFlag( + LLVMModuleRef M, + Module::ModFlagBehavior MergeBehavior, + const char *Name, + uint32_t Value) { + unwrap(M)->addModuleFlag(MergeBehavior, Name, Value); } extern "C" LLVMValueRef LLVMRustMetadataAsValue(LLVMContextRef C, LLVMMetadataRef MD) { diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index 3351564299c..6c5461505fa 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -47,7 +47,7 @@ fn decodable_body( quote! { ::rustc_serialize::Decoder::read_struct( __decoder, - |__decoder| { ::std::result::Result::Ok(#construct) }, + |__decoder| { #construct }, ) } } @@ -57,7 +57,7 @@ fn decodable_body( .enumerate() .map(|(idx, vi)| { let construct = vi.construct(|field, index| decode_field(field, index, false)); - quote! { #idx => { ::std::result::Result::Ok(#construct) } } + quote! { #idx => { #construct } } }) .collect(); let names: TokenStream = variants @@ -82,8 +82,7 @@ fn decodable_body( |__decoder, __variant_idx| { match __variant_idx { #match_inner - _ => return ::std::result::Result::Err( - ::rustc_serialize::Decoder::error(__decoder, #message)), + _ => panic!(#message), } }) } @@ -95,9 +94,7 @@ fn decodable_body( s.bound_impl( quote!(::rustc_serialize::Decodable<#decoder_ty>), quote! { - fn decode( - __decoder: &mut #decoder_ty, - ) -> ::std::result::Result<Self, <#decoder_ty as ::rustc_serialize::Decoder>::Error> { + fn decode(__decoder: &mut #decoder_ty) -> Self { #decode_body } }, @@ -127,12 +124,7 @@ fn decode_field(field: &syn::Field, index: usize, is_struct: bool) -> proc_macro #__decoder, #opt_field_name #decode_inner_method) }; - quote! { - match #decode_call { - ::std::result::Result::Ok(__res) => __res, - ::std::result::Result::Err(__err) => return ::std::result::Result::Err(__err), - } - } + quote! { #decode_call } } pub fn type_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 220bc9c5f75..fb1c71fb8cd 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -263,7 +263,7 @@ impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Lazy<T> { fn decode<M: Metadata<'a, 'tcx>>(self, metadata: M) -> T { let mut dcx = metadata.decoder(self.position.get()); dcx.lazy_state = LazyState::NodeStart(self.position); - T::decode(&mut dcx).unwrap() + T::decode(&mut dcx) } } @@ -274,7 +274,7 @@ impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable<DecodeContext<'a, 'tcx>>> Lazy<[T]> { ) -> impl ExactSizeIterator<Item = T> + Captures<'a> + Captures<'tcx> + 'x { let mut dcx = metadata.decoder(self.position.get()); dcx.lazy_state = LazyState::NodeStart(self.position); - (0..self.meta).map(move |_| T::decode(&mut dcx).unwrap()) + (0..self.meta).map(move |_| T::decode(&mut dcx)) } } @@ -300,11 +300,8 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { if cnum == LOCAL_CRATE { self.cdata().cnum } else { self.cdata().cnum_map[cnum] } } - fn read_lazy_with_meta<T: ?Sized + LazyMeta>( - &mut self, - meta: T::Meta, - ) -> Result<Lazy<T>, <Self as Decoder>::Error> { - let distance = self.read_usize()?; + fn read_lazy_with_meta<T: ?Sized + LazyMeta>(&mut self, meta: T::Meta) -> Lazy<T> { + let distance = self.read_usize(); let position = match self.lazy_state { LazyState::NoNode => bug!("read_lazy_with_meta: outside of a metadata node"), LazyState::NodeStart(start) => { @@ -315,7 +312,7 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { LazyState::Previous(last_pos) => last_pos.get() + distance, }; self.lazy_state = LazyState::Previous(NonZeroUsize::new(position).unwrap()); - Ok(Lazy::from_position_and_meta(NonZeroUsize::new(position).unwrap(), meta)) + Lazy::from_position_and_meta(NonZeroUsize::new(position).unwrap(), meta) } #[inline] @@ -342,25 +339,21 @@ impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> { self.opaque.position() } - fn cached_ty_for_shorthand<F>( - &mut self, - shorthand: usize, - or_insert_with: F, - ) -> Result<Ty<'tcx>, Self::Error> + fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx> where - F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>, + F: FnOnce(&mut Self) -> Ty<'tcx>, { let tcx = self.tcx(); let key = ty::CReaderCacheKey { cnum: Some(self.cdata().cnum), pos: shorthand }; if let Some(&ty) = tcx.ty_rcache.borrow().get(&key) { - return Ok(ty); + return ty; } - let ty = or_insert_with(self)?; + let ty = or_insert_with(self); tcx.ty_rcache.borrow_mut().insert(key, ty); - Ok(ty) + ty } fn with_position<F, R>(&mut self, pos: usize, f: F) -> R @@ -376,7 +369,7 @@ impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> { r } - fn decode_alloc_id(&mut self) -> Result<rustc_middle::mir::interpret::AllocId, Self::Error> { + fn decode_alloc_id(&mut self) -> rustc_middle::mir::interpret::AllocId { if let Some(alloc_decoding_session) = self.alloc_decoding_session { alloc_decoding_session.decode_alloc_id(self) } else { @@ -386,48 +379,48 @@ impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> { } impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for CrateNum { - fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<CrateNum, String> { - let cnum = CrateNum::from_u32(d.read_u32()?); - Ok(d.map_encoded_cnum_to_current(cnum)) + fn decode(d: &mut DecodeContext<'a, 'tcx>) -> CrateNum { + let cnum = CrateNum::from_u32(d.read_u32()); + d.map_encoded_cnum_to_current(cnum) } } impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefIndex { - fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<DefIndex, String> { - Ok(DefIndex::from_u32(d.read_u32()?)) + fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefIndex { + DefIndex::from_u32(d.read_u32()) } } impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnIndex { - fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<ExpnIndex, String> { - Ok(ExpnIndex::from_u32(d.read_u32()?)) + fn decode(d: &mut DecodeContext<'a, 'tcx>) -> ExpnIndex { + ExpnIndex::from_u32(d.read_u32()) } } impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SyntaxContext { - fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<SyntaxContext, String> { + fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> SyntaxContext { let cdata = decoder.cdata(); let sess = decoder.sess.unwrap(); let cname = cdata.root.name; rustc_span::hygiene::decode_syntax_context(decoder, &cdata.hygiene_context, |_, id| { debug!("SpecializedDecoder<SyntaxContext>: decoding {}", id); - Ok(cdata + cdata .root .syntax_contexts .get(cdata, id) .unwrap_or_else(|| panic!("Missing SyntaxContext {:?} for crate {:?}", id, cname)) - .decode((cdata, sess))) + .decode((cdata, sess)) }) } } impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnId { - fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<ExpnId, String> { + fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> ExpnId { let local_cdata = decoder.cdata(); let sess = decoder.sess.unwrap(); - let cnum = CrateNum::decode(decoder)?; - let index = u32::decode(decoder)?; + let cnum = CrateNum::decode(decoder); + let index = u32::decode(decoder); let expn_id = rustc_span::hygiene::decode_expn_id(cnum, index, |expn_id| { let ExpnId { krate: cnum, local_id: index } = expn_id; @@ -453,23 +446,23 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnId { .decode((crate_data, sess)); (expn_data, expn_hash) }); - Ok(expn_id) + expn_id } } impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span { - fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<Span, String> { - let ctxt = SyntaxContext::decode(decoder)?; - let tag = u8::decode(decoder)?; + fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Span { + let ctxt = SyntaxContext::decode(decoder); + let tag = u8::decode(decoder); if tag == TAG_PARTIAL_SPAN { - return Ok(DUMMY_SP.with_ctxt(ctxt)); + return DUMMY_SP.with_ctxt(ctxt); } debug_assert!(tag == TAG_VALID_SPAN_LOCAL || tag == TAG_VALID_SPAN_FOREIGN); - let lo = BytePos::decode(decoder)?; - let len = BytePos::decode(decoder)?; + let lo = BytePos::decode(decoder); + let len = BytePos::decode(decoder); let hi = lo + len; let Some(sess) = decoder.sess else { @@ -512,7 +505,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span { if decoder.cdata().root.is_proc_macro_crate() { // Decode `CrateNum` as u32 - using `CrateNum::decode` will ICE // since we don't have `cnum_map` populated. - let cnum = u32::decode(decoder)?; + let cnum = u32::decode(decoder); panic!( "Decoding of crate {:?} tried to access proc-macro dep {:?}", decoder.cdata().root.name, @@ -520,7 +513,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span { ); } // tag is TAG_VALID_SPAN_FOREIGN, checked by `debug_assert` above - let cnum = CrateNum::decode(decoder)?; + let cnum = CrateNum::decode(decoder); debug!( "SpecializedDecoder<Span>::specialized_decode: loading source files from cnum {:?}", cnum @@ -582,18 +575,18 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span { (hi + source_file.translated_source_file.start_pos) - source_file.original_start_pos; // Do not try to decode parent for foreign spans. - Ok(Span::new(lo, hi, ctxt, None)) + Span::new(lo, hi, ctxt, None) } } impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] { - fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> { + fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self { ty::codec::RefDecodable::decode(d) } } impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] { - fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> { + fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self { ty::codec::RefDecodable::decode(d) } } @@ -601,7 +594,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeContext<'a, 'tcx>> for Lazy<T> { - fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> { + fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self { decoder.read_lazy_with_meta(()) } } @@ -609,9 +602,9 @@ impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeContext<'a impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeContext<'a, 'tcx>> for Lazy<[T]> { - fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> { - let len = decoder.read_usize()?; - if len == 0 { Ok(Lazy::empty()) } else { decoder.read_lazy_with_meta(len) } + fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self { + let len = decoder.read_usize(); + if len == 0 { Lazy::empty() } else { decoder.read_lazy_with_meta(len) } } } @@ -620,8 +613,8 @@ impl<'a, 'tcx, I: Idx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeCo where Option<T>: FixedSizeEncoding, { - fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> { - let len = decoder.read_usize()?; + fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self { + let len = decoder.read_usize(); decoder.read_lazy_with_meta(len) } } @@ -1286,7 +1279,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { }; ty::AssocItem { - ident, + name: ident.name, kind, vis: self.get_visibility(id), defaultness: container.defaultness(), @@ -1380,11 +1373,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.root.traits.decode(self).map(move |index| self.local_def_id(index)) } - fn get_trait_impls(self) -> impl Iterator<Item = (DefId, Option<SimplifiedType>)> + 'a { - self.cdata.trait_impls.values().flat_map(move |impls| { - impls - .decode(self) - .map(move |(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty)) + fn get_trait_impls(self) -> impl Iterator<Item = (DefId, DefId, Option<SimplifiedType>)> + 'a { + self.cdata.trait_impls.iter().flat_map(move |((trait_cnum_raw, trait_index), impls)| { + let trait_def_id = DefId { + krate: self.cnum_map[CrateNum::from_u32(*trait_cnum_raw)], + index: *trait_index, + }; + impls.decode(self).map(move |(impl_index, simplified_self_ty)| { + (trait_def_id, self.local_def_id(impl_index), simplified_self_ty) + }) }) } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 9b59c14c2fe..2f8e35648ec 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -493,7 +493,7 @@ impl CStore { pub fn trait_impls_in_crate_untracked( &self, cnum: CrateNum, - ) -> impl Iterator<Item = (DefId, Option<SimplifiedType>)> + '_ { + ) -> impl Iterator<Item = (DefId, DefId, Option<SimplifiedType>)> + '_ { self.get_crate_data(cnum).get_trait_impls() } } diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs index 054431169a2..d66f2b031a8 100644 --- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs +++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs @@ -39,11 +39,11 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for DefPathHashMapRef<'tcx> { } impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefPathHashMapRef<'static> { - fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<DefPathHashMapRef<'static>, String> { + fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefPathHashMapRef<'static> { // Import TyDecoder so we can access the DecodeContext::position() method use crate::rustc_middle::ty::codec::TyDecoder; - let len = d.read_usize()?; + let len = d.read_usize(); let pos = d.position(); let o = OwningRef::new(d.blob().clone()).map(|x| &x[pos..pos + len]); @@ -52,7 +52,9 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefPathHashMapRef<'static> // the method. We use read_raw_bytes() for that. let _ = d.read_raw_bytes(len); - let inner = odht::HashTable::from_raw_bytes(o).map_err(|e| format!("{}", e))?; - Ok(DefPathHashMapRef::OwnedFromMetadata(inner)) + let inner = odht::HashTable::from_raw_bytes(o).unwrap_or_else(|e| { + panic!("decode error: {}", e); + }); + DefPathHashMapRef::OwnedFromMetadata(inner) } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index ebb78adf343..3fae652ee2e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1291,7 +1291,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.kind[def_id] <- EntryKind::AssocType(container)); } } - self.encode_ident_span(def_id, impl_item.ident); + self.encode_ident_span(def_id, impl_item.ident(self.tcx)); self.encode_item_type(def_id); if let Some(trait_item_def_id) = impl_item.trait_item_def_id { record!(self.tables.trait_item_def_id[def_id] <- trait_item_def_id); @@ -1314,7 +1314,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { return; } - let mut keys_and_jobs = self + let keys_and_jobs = self .tcx .mir_keys(()) .iter() @@ -1327,8 +1327,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } }) .collect::<Vec<_>>(); - // Sort everything to ensure a stable order for diagnotics. - keys_and_jobs.sort_by_key(|&(def_id, _, _)| def_id.index()); for (def_id, encode_const, encode_opt) in keys_and_jobs.into_iter() { debug_assert!(encode_const || encode_opt); diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 82ea7ff6aab..1885df6ac5d 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -204,8 +204,11 @@ impl<'hir> Map<'hir> { if hir_id.local_id == ItemLocalId::new(0) { Some(hir_id.owner) } else { - // FIXME(#85914) is this access safe for incr. comp.? - self.tcx.untracked_resolutions.definitions.opt_hir_id_to_local_def_id(hir_id) + self.tcx + .hir_owner_nodes(hir_id.owner)? + .local_id_to_def_id + .get(&hir_id.local_id) + .copied() } } diff --git a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs index 5f028975bd0..e2f3d6e078f 100644 --- a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs +++ b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs @@ -45,8 +45,9 @@ impl<S: serialize::Encoder> serialize::Encodable<S> for GraphIsCyclicCache { impl<D: serialize::Decoder> serialize::Decodable<D> for GraphIsCyclicCache { #[inline] - fn decode(d: &mut D) -> Result<Self, D::Error> { - serialize::Decodable::decode(d).map(|_v: ()| Self::new()) + fn decode(d: &mut D) -> Self { + let () = serialize::Decodable::decode(d); + Self::new() } } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index b762a10da84..66f2c6e78a2 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -273,20 +273,20 @@ pub struct AllocDecodingSession<'s> { impl<'s> AllocDecodingSession<'s> { /// Decodes an `AllocId` in a thread-safe way. - pub fn decode_alloc_id<'tcx, D>(&self, decoder: &mut D) -> Result<AllocId, D::Error> + pub fn decode_alloc_id<'tcx, D>(&self, decoder: &mut D) -> AllocId where D: TyDecoder<'tcx>, { // Read the index of the allocation. - let idx = usize::try_from(decoder.read_u32()?).unwrap(); + let idx = usize::try_from(decoder.read_u32()).unwrap(); let pos = usize::try_from(self.state.data_offsets[idx]).unwrap(); // Decode the `AllocDiscriminant` now so that we know if we have to reserve an // `AllocId`. let (alloc_kind, pos) = decoder.with_position(pos, |decoder| { - let alloc_kind = AllocDiscriminant::decode(decoder)?; - Ok((alloc_kind, decoder.position())) - })?; + let alloc_kind = AllocDiscriminant::decode(decoder); + (alloc_kind, decoder.position()) + }); // Check the decoding state to see if it's already decoded or if we should // decode it here. @@ -295,7 +295,7 @@ impl<'s> AllocDecodingSession<'s> { match *entry { State::Done(alloc_id) => { - return Ok(alloc_id); + return alloc_id; } ref mut entry @ State::Empty => { // We are allowed to decode. @@ -329,7 +329,7 @@ impl<'s> AllocDecodingSession<'s> { State::InProgress(ref mut sessions, alloc_id) => { if sessions.contains(&self.session_id) { // Don't recurse. - return Ok(alloc_id); + return alloc_id; } else { // Start decoding concurrently. sessions.insert(self.session_id); @@ -343,37 +343,37 @@ impl<'s> AllocDecodingSession<'s> { let alloc_id = decoder.with_position(pos, |decoder| { match alloc_kind { AllocDiscriminant::Alloc => { - let alloc = <&'tcx Allocation as Decodable<_>>::decode(decoder)?; + let alloc = <&'tcx Allocation as Decodable<_>>::decode(decoder); // We already have a reserved `AllocId`. let alloc_id = alloc_id.unwrap(); trace!("decoded alloc {:?}: {:#?}", alloc_id, alloc); decoder.tcx().set_alloc_id_same_memory(alloc_id, alloc); - Ok(alloc_id) + alloc_id } AllocDiscriminant::Fn => { assert!(alloc_id.is_none()); trace!("creating fn alloc ID"); - let instance = ty::Instance::decode(decoder)?; + let instance = ty::Instance::decode(decoder); trace!("decoded fn alloc instance: {:?}", instance); let alloc_id = decoder.tcx().create_fn_alloc(instance); - Ok(alloc_id) + alloc_id } AllocDiscriminant::Static => { assert!(alloc_id.is_none()); trace!("creating extern static alloc ID"); - let did = <DefId as Decodable<D>>::decode(decoder)?; + let did = <DefId as Decodable<D>>::decode(decoder); trace!("decoded static def-ID: {:?}", did); let alloc_id = decoder.tcx().create_static_alloc(did); - Ok(alloc_id) + alloc_id } } - })?; + }); self.state.decoding_state[idx].with_lock(|entry| { *entry = State::Done(alloc_id); }); - Ok(alloc_id) + alloc_id } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 48f39b26152..b1ab0f5b533 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -619,20 +619,20 @@ impl<'tcx, E: TyEncoder<'tcx>, T: Encodable<E>> Encodable<E> for ClearCrossCrate } impl<'tcx, D: TyDecoder<'tcx>, T: Decodable<D>> Decodable<D> for ClearCrossCrate<T> { #[inline] - fn decode(d: &mut D) -> Result<ClearCrossCrate<T>, D::Error> { + fn decode(d: &mut D) -> ClearCrossCrate<T> { if D::CLEAR_CROSS_CRATE { - return Ok(ClearCrossCrate::Clear); + return ClearCrossCrate::Clear; } - let discr = u8::decode(d)?; + let discr = u8::decode(d); match discr { - TAG_CLEAR_CROSS_CRATE_CLEAR => Ok(ClearCrossCrate::Clear), + TAG_CLEAR_CROSS_CRATE_CLEAR => ClearCrossCrate::Clear, TAG_CLEAR_CROSS_CRATE_SET => { - let val = T::decode(d)?; - Ok(ClearCrossCrate::Set(val)) + let val = T::decode(d); + ClearCrossCrate::Set(val) } - tag => Err(d.error(&format!("Invalid tag for ClearCrossCrate: {:?}", tag))), + tag => panic!("Invalid tag for ClearCrossCrate: {:?}", tag), } } } @@ -894,7 +894,7 @@ pub struct LocalDecl<'tcx> { /// across a suspension point against the type components of the generator /// which type checking knows are live across a suspension point. We need to /// flag drop flags to avoid triggering this check as they are introduced - /// after typeck. + /// outside of type inference. /// /// This should be sound because the drop flags are fully algebraic, and /// therefore don't affect the auto-trait or outlives properties of the diff --git a/compiler/rustc_middle/src/mir/predecessors.rs b/compiler/rustc_middle/src/mir/predecessors.rs index fd6bb76dc43..2562baac911 100644 --- a/compiler/rustc_middle/src/mir/predecessors.rs +++ b/compiler/rustc_middle/src/mir/predecessors.rs @@ -57,14 +57,15 @@ impl PredecessorCache { impl<S: serialize::Encoder> serialize::Encodable<S> for PredecessorCache { #[inline] fn encode(&self, s: &mut S) -> Result<(), S::Error> { - serialize::Encodable::encode(&(), s) + s.emit_unit() } } impl<D: serialize::Decoder> serialize::Decodable<D> for PredecessorCache { #[inline] - fn decode(d: &mut D) -> Result<Self, D::Error> { - serialize::Decodable::decode(d).map(|_v: ()| Self::new()) + fn decode(d: &mut D) -> Self { + let () = d.read_unit(); + Self::new() } } diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs index 06cbc3383ef..965d30a7b92 100644 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ b/compiler/rustc_middle/src/mir/spanview.rs @@ -230,7 +230,7 @@ where } /// Format a string showing the start line and column, and end line and column within a file. -pub fn source_range_no_file<'tcx>(tcx: TyCtxt<'tcx>, span: &Span) -> String { +pub fn source_range_no_file<'tcx>(tcx: TyCtxt<'tcx>, span: Span) -> String { let source_map = tcx.sess.source_map(); let start = source_map.lookup_char_pos(span.lo()); let end = source_map.lookup_char_pos(span.hi()); @@ -629,7 +629,7 @@ fn tooltip<'tcx>( let mut text = Vec::new(); text.push(format!("{}: {}:", spanview_id, &source_map.span_to_embeddable_string(span))); for statement in statements { - let source_range = source_range_no_file(tcx, &statement.source_info.span); + let source_range = source_range_no_file(tcx, statement.source_info.span); text.push(format!( "\n{}{}: {}: {:?}", TOOLTIP_INDENT, @@ -639,7 +639,7 @@ fn tooltip<'tcx>( )); } if let Some(term) = terminator { - let source_range = source_range_no_file(tcx, &term.source_info.span); + let source_range = source_range_no_file(tcx, term.source_info.span); text.push(format!( "\n{}{}: {}: {:?}", TOOLTIP_INDENT, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 5dc7b219642..54391bd649e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -252,7 +252,7 @@ rustc_queries! { /// Set of all the `DefId`s in this crate that have MIR associated with /// them. This includes all the body owners, but also things like struct /// constructors. - query mir_keys(_: ()) -> FxHashSet<LocalDefId> { + query mir_keys(_: ()) -> rustc_data_structures::fx::FxIndexSet<LocalDefId> { storage(ArenaCacheSelector<'tcx>) desc { "getting a list of all mir_keys" } } @@ -784,24 +784,11 @@ rustc_queries! { desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) } cache_on_disk_if { true } load_cached(tcx, id) { - #[cfg(bootstrap)] - { - match match tcx.on_disk_cache().as_ref() { - Some(c) => c.try_load_query_result(*tcx, id), - None => None, - } { - Some(x) => Some(&*tcx.arena.alloc(x)), - None => None, - } - } - #[cfg(not(bootstrap))] - { - let typeck_results: Option<ty::TypeckResults<'tcx>> = tcx - .on_disk_cache().as_ref() - .and_then(|c| c.try_load_query_result(*tcx, id)); + let typeck_results: Option<ty::TypeckResults<'tcx>> = tcx + .on_disk_cache().as_ref() + .and_then(|c| c.try_load_query_result(*tcx, id)); - typeck_results.map(|x| &*tcx.arena.alloc(x)) - } + typeck_results.map(|x| &*tcx.arena.alloc(x)) } } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index de5beffb5c5..1123cab8076 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -402,7 +402,7 @@ impl ObligationCauseCode<'_> { // `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(ObligationCauseCode<'_>, 40); +static_assert_size!(ObligationCauseCode<'_>, 48); #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum StatementAsExpression { @@ -440,11 +440,11 @@ pub struct IfExpressionCause { #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] pub struct DerivedObligationCause<'tcx> { - /// The trait reference of the parent obligation that led to the + /// The trait predicate of the parent obligation that led to the /// current obligation. Note that only trait obligations lead to - /// derived obligations, so we just store the trait reference here + /// derived obligations, so we just store the trait predicate here /// directly. - pub parent_trait_ref: ty::PolyTraitRef<'tcx>, + pub parent_trait_pred: ty::PolyTraitPredicate<'tcx>, /// The parent trait had this cause. pub parent_code: Lrc<ObligationCauseCode<'tcx>>, @@ -566,7 +566,7 @@ pub enum ImplSource<'tcx, N> { TraitAlias(ImplSourceTraitAliasData<'tcx, N>), /// ImplSource for a `const Drop` implementation. - ConstDrop(ImplSourceConstDropData), + ConstDrop(ImplSourceConstDropData<N>), } impl<'tcx, N> ImplSource<'tcx, N> { @@ -581,10 +581,10 @@ impl<'tcx, N> ImplSource<'tcx, N> { ImplSource::Object(d) => d.nested, ImplSource::FnPointer(d) => d.nested, ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) - | ImplSource::Pointee(ImplSourcePointeeData) - | ImplSource::ConstDrop(ImplSourceConstDropData) => Vec::new(), + | ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(), ImplSource::TraitAlias(d) => d.nested, ImplSource::TraitUpcasting(d) => d.nested, + ImplSource::ConstDrop(i) => i.nested, } } @@ -599,10 +599,10 @@ impl<'tcx, N> ImplSource<'tcx, N> { ImplSource::Object(d) => &d.nested, ImplSource::FnPointer(d) => &d.nested, ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) - | ImplSource::Pointee(ImplSourcePointeeData) - | ImplSource::ConstDrop(ImplSourceConstDropData) => &[], + | ImplSource::Pointee(ImplSourcePointeeData) => &[], ImplSource::TraitAlias(d) => &d.nested, ImplSource::TraitUpcasting(d) => &d.nested, + ImplSource::ConstDrop(i) => &i.nested, } } @@ -661,9 +661,9 @@ impl<'tcx, N> ImplSource<'tcx, N> { nested: d.nested.into_iter().map(f).collect(), }) } - ImplSource::ConstDrop(ImplSourceConstDropData) => { - ImplSource::ConstDrop(ImplSourceConstDropData) - } + ImplSource::ConstDrop(i) => ImplSource::ConstDrop(ImplSourceConstDropData { + nested: i.nested.into_iter().map(f).collect(), + }), } } } @@ -755,8 +755,10 @@ pub struct ImplSourceDiscriminantKindData; #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] pub struct ImplSourcePointeeData; -#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] -pub struct ImplSourceConstDropData; +#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)] +pub struct ImplSourceConstDropData<N> { + pub nested: Vec<N>, +} #[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)] pub struct ImplSourceTraitAliasData<'tcx, N> { diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 71ee00c602a..e18f04d92ee 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -146,8 +146,8 @@ pub enum SelectionCandidate<'tcx> { BuiltinUnsizeCandidate, - /// Implementation of `const Drop`. - ConstDropCandidate, + /// Implementation of `const Drop`, optionally from a custom `impl const Drop`. + ConstDropCandidate(Option<DefId>), } /// The result of trait evaluation. The order is important diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs index aa2f37bd81a..6ce9f5eea34 100644 --- a/compiler/rustc_middle/src/traits/structural_impls.rs +++ b/compiler/rustc_middle/src/traits/structural_impls.rs @@ -120,6 +120,12 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx, } } +impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceConstDropData<N> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "ImplSourceConstDropData(nested={:?})", self.nested) + } +} + /////////////////////////////////////////////////////////////////////////// // Lift implementations @@ -127,5 +133,4 @@ TrivialTypeFoldableAndLiftImpls! { super::IfExpressionCause, super::ImplSourceDiscriminantKindData, super::ImplSourcePointeeData, - super::ImplSourceConstDropData, } diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 2776370ba6f..c23d4eae1a4 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -44,8 +44,7 @@ impl AssocItemContainer { #[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)] pub struct AssocItem { pub def_id: DefId, - #[stable_hasher(project(name))] - pub ident: Ident, + pub name: Symbol, pub kind: AssocKind, pub vis: Visibility, pub defaultness: hir::Defaultness, @@ -61,6 +60,10 @@ pub struct AssocItem { } impl AssocItem { + pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident { + Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap()) + } + pub fn signature(&self, tcx: TyCtxt<'_>) -> String { match self.kind { ty::AssocKind::Fn => { @@ -70,9 +73,9 @@ impl AssocItem { // regions just fine, showing `fn(&MyType)`. tcx.fn_sig(self.def_id).skip_binder().to_string() } - ty::AssocKind::Type => format!("type {};", self.ident), + ty::AssocKind::Type => format!("type {};", self.name), ty::AssocKind::Const => { - format!("const {}: {:?};", self.ident, tcx.type_of(self.def_id)) + format!("const {}: {:?};", self.name, tcx.type_of(self.def_id)) } } } @@ -115,7 +118,7 @@ pub struct AssocItems<'tcx> { impl<'tcx> AssocItems<'tcx> { /// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order. pub fn new(items_in_def_order: impl IntoIterator<Item = &'tcx ty::AssocItem>) -> Self { - let items = items_in_def_order.into_iter().map(|item| (item.ident.name, item)).collect(); + let items = items_in_def_order.into_iter().map(|item| (item.name, item)).collect(); AssocItems { items } } @@ -149,7 +152,7 @@ impl<'tcx> AssocItems<'tcx> { ) -> Option<&ty::AssocItem> { self.filter_by_name_unhygienic(ident.name) .filter(|item| item.kind == kind) - .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id)) + .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id)) } /// Returns the associated item with the given name and any of `AssocKind`, if one exists. @@ -162,7 +165,7 @@ impl<'tcx> AssocItems<'tcx> { ) -> Option<&ty::AssocItem> { self.filter_by_name_unhygienic(ident.name) .filter(|item| kinds.contains(&item.kind)) - .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id)) + .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id)) } /// Returns the associated item with the given name in the given `Namespace`, if one exists. @@ -175,6 +178,6 @@ impl<'tcx> AssocItems<'tcx> { ) -> Option<&ty::AssocItem> { self.filter_by_name_unhygienic(ident.name) .filter(|item| item.kind.namespace() == ns) - .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id)) + .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id)) } } diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index db37d98614e..65b91eedf8a 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -14,7 +14,7 @@ use crate::mir::{ }; use crate::thir; use crate::ty::subst::SubstsRef; -use crate::ty::{self, List, Ty, TyCtxt}; +use crate::ty::{self, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashMap; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::Span; @@ -71,7 +71,7 @@ pub trait TyEncoder<'tcx>: Encoder { /// `Decodable` can still be implemented in cases where `Decodable` is required /// by a trait bound. pub trait RefDecodable<'tcx, D: TyDecoder<'tcx>> { - fn decode(d: &mut D) -> Result<&'tcx Self, D::Error>; + fn decode(d: &mut D) -> &'tcx Self; } /// Encode the given value or a previously cached shorthand. @@ -172,13 +172,9 @@ pub trait TyDecoder<'tcx>: Decoder { fn position(&self) -> usize; - fn cached_ty_for_shorthand<F>( - &mut self, - shorthand: usize, - or_insert_with: F, - ) -> Result<Ty<'tcx>, Self::Error> + fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx> where - F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>; + F: FnOnce(&mut Self) -> Ty<'tcx>; fn with_position<F, R>(&mut self, pos: usize, f: F) -> R where @@ -188,35 +184,35 @@ pub trait TyDecoder<'tcx>: Decoder { (self.peek_byte() & (SHORTHAND_OFFSET as u8)) != 0 } - fn decode_alloc_id(&mut self) -> Result<AllocId, Self::Error>; + fn decode_alloc_id(&mut self) -> AllocId; } #[inline] fn decode_arena_allocable<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable<D>>( decoder: &mut D, -) -> Result<&'tcx T, D::Error> +) -> &'tcx T where D: TyDecoder<'tcx>, { - Ok(decoder.tcx().arena.alloc(Decodable::decode(decoder)?)) + decoder.tcx().arena.alloc(Decodable::decode(decoder)) } #[inline] fn decode_arena_allocable_slice<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable<D>>( decoder: &mut D, -) -> Result<&'tcx [T], D::Error> +) -> &'tcx [T] where D: TyDecoder<'tcx>, { - Ok(decoder.tcx().arena.alloc_from_iter(<Vec<T> as Decodable<D>>::decode(decoder)?)) + decoder.tcx().arena.alloc_from_iter(<Vec<T> as Decodable<D>>::decode(decoder)) } impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for Ty<'tcx> { #[allow(rustc::usage_of_ty_tykind)] - fn decode(decoder: &mut D) -> Result<Ty<'tcx>, D::Error> { + fn decode(decoder: &mut D) -> Ty<'tcx> { // Handle shorthands first, if we have a usize > 0x80. if decoder.positioned_at_shorthand() { - let pos = decoder.read_usize()?; + let pos = decoder.read_usize(); assert!(pos >= SHORTHAND_OFFSET); let shorthand = pos - SHORTHAND_OFFSET; @@ -225,87 +221,89 @@ impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for Ty<'tcx> { }) } else { let tcx = decoder.tcx(); - Ok(tcx.mk_ty(ty::TyKind::decode(decoder)?)) + tcx.mk_ty(ty::TyKind::decode(decoder)) } } } impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<'tcx, ty::PredicateKind<'tcx>> { - fn decode(decoder: &mut D) -> Result<ty::Binder<'tcx, ty::PredicateKind<'tcx>>, D::Error> { - let bound_vars = Decodable::decode(decoder)?; + fn decode(decoder: &mut D) -> ty::Binder<'tcx, ty::PredicateKind<'tcx>> { + let bound_vars = Decodable::decode(decoder); // Handle shorthands first, if we have a usize > 0x80. - Ok(ty::Binder::bind_with_vars( + ty::Binder::bind_with_vars( if decoder.positioned_at_shorthand() { - let pos = decoder.read_usize()?; + let pos = decoder.read_usize(); assert!(pos >= SHORTHAND_OFFSET); let shorthand = pos - SHORTHAND_OFFSET; - decoder.with_position(shorthand, ty::PredicateKind::decode)? + decoder.with_position(shorthand, ty::PredicateKind::decode) } else { - ty::PredicateKind::decode(decoder)? + ty::PredicateKind::decode(decoder) }, bound_vars, - )) + ) } } impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Predicate<'tcx> { - fn decode(decoder: &mut D) -> Result<ty::Predicate<'tcx>, D::Error> { - let predicate_kind = Decodable::decode(decoder)?; - let predicate = decoder.tcx().mk_predicate(predicate_kind); - Ok(predicate) + fn decode(decoder: &mut D) -> ty::Predicate<'tcx> { + let predicate_kind = Decodable::decode(decoder); + decoder.tcx().mk_predicate(predicate_kind) } } impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for SubstsRef<'tcx> { - fn decode(decoder: &mut D) -> Result<Self, D::Error> { - let len = decoder.read_usize()?; + fn decode(decoder: &mut D) -> Self { + let len = decoder.read_usize(); let tcx = decoder.tcx(); - tcx.mk_substs((0..len).map(|_| Decodable::decode(decoder))) + tcx.mk_substs( + (0..len).map::<ty::subst::GenericArg<'tcx>, _>(|_| Decodable::decode(decoder)), + ) } } impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for mir::Place<'tcx> { - fn decode(decoder: &mut D) -> Result<Self, D::Error> { - let local: mir::Local = Decodable::decode(decoder)?; - let len = decoder.read_usize()?; - let projection: &'tcx List<mir::PlaceElem<'tcx>> = - decoder.tcx().mk_place_elems((0..len).map(|_| Decodable::decode(decoder)))?; - Ok(mir::Place { local, projection }) + fn decode(decoder: &mut D) -> Self { + let local: mir::Local = Decodable::decode(decoder); + let len = decoder.read_usize(); + let projection = decoder.tcx().mk_place_elems( + (0..len).map::<mir::PlaceElem<'tcx>, _>(|_| Decodable::decode(decoder)), + ); + mir::Place { local, projection } } } impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Region<'tcx> { - fn decode(decoder: &mut D) -> Result<Self, D::Error> { - Ok(decoder.tcx().mk_region(Decodable::decode(decoder)?)) + fn decode(decoder: &mut D) -> Self { + decoder.tcx().mk_region(Decodable::decode(decoder)) } } impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for CanonicalVarInfos<'tcx> { - fn decode(decoder: &mut D) -> Result<Self, D::Error> { - let len = decoder.read_usize()?; - let interned: Result<Vec<CanonicalVarInfo<'tcx>>, _> = + fn decode(decoder: &mut D) -> Self { + let len = decoder.read_usize(); + let interned: Vec<CanonicalVarInfo<'tcx>> = (0..len).map(|_| Decodable::decode(decoder)).collect(); - Ok(decoder.tcx().intern_canonical_var_infos(interned?.as_slice())) + decoder.tcx().intern_canonical_var_infos(interned.as_slice()) } } impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for AllocId { - fn decode(decoder: &mut D) -> Result<Self, D::Error> { + fn decode(decoder: &mut D) -> Self { decoder.decode_alloc_id() } } impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::SymbolName<'tcx> { - fn decode(decoder: &mut D) -> Result<Self, D::Error> { - Ok(ty::SymbolName::new(decoder.tcx(), &decoder.read_str()?)) + fn decode(decoder: &mut D) -> Self { + ty::SymbolName::new(decoder.tcx(), &decoder.read_str()) } } macro_rules! impl_decodable_via_ref { ($($t:ty),+) => { $(impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for $t { - fn decode(decoder: &mut D) -> Result<Self, D::Error> { + fn decode(decoder: &mut D) -> Self { RefDecodable::decode(decoder) } })* @@ -313,77 +311,73 @@ macro_rules! impl_decodable_via_ref { } impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<Ty<'tcx>> { - fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { - let len = decoder.read_usize()?; - decoder.tcx().mk_type_list((0..len).map(|_| Decodable::decode(decoder))) + fn decode(decoder: &mut D) -> &'tcx Self { + let len = decoder.read_usize(); + decoder.tcx().mk_type_list((0..len).map::<Ty<'tcx>, _>(|_| Decodable::decode(decoder))) } } impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> { - fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { - let len = decoder.read_usize()?; - decoder.tcx().mk_poly_existential_predicates((0..len).map(|_| Decodable::decode(decoder))) + fn decode(decoder: &mut D) -> &'tcx Self { + let len = decoder.read_usize(); + decoder.tcx().mk_poly_existential_predicates( + (0..len).map::<ty::Binder<'tcx, _>, _>(|_| Decodable::decode(decoder)), + ) } } impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::Const<'tcx> { - fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { - Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?)) + fn decode(decoder: &mut D) -> &'tcx Self { + decoder.tcx().mk_const(Decodable::decode(decoder)) } } impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] { - fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { - Ok(decoder.tcx().arena.alloc_from_iter( - (0..decoder.read_usize()?) - .map(|_| Decodable::decode(decoder)) - .collect::<Result<Vec<_>, _>>()?, - )) + fn decode(decoder: &mut D) -> &'tcx Self { + decoder.tcx().arena.alloc_from_iter( + (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(), + ) } } impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for Allocation { - fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { - Ok(decoder.tcx().intern_const_alloc(Decodable::decode(decoder)?)) + fn decode(decoder: &mut D) -> &'tcx Self { + decoder.tcx().intern_const_alloc(Decodable::decode(decoder)) } } impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>, Span)] { - fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { - Ok(decoder.tcx().arena.alloc_from_iter( - (0..decoder.read_usize()?) - .map(|_| Decodable::decode(decoder)) - .collect::<Result<Vec<_>, _>>()?, - )) + fn decode(decoder: &mut D) -> &'tcx Self { + decoder.tcx().arena.alloc_from_iter( + (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(), + ) } } impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::Node<'tcx>] { - fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { - Ok(decoder.tcx().arena.alloc_from_iter( - (0..decoder.read_usize()?) - .map(|_| Decodable::decode(decoder)) - .collect::<Result<Vec<_>, _>>()?, - )) + fn decode(decoder: &mut D) -> &'tcx Self { + decoder.tcx().arena.alloc_from_iter( + (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(), + ) } } impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::NodeId] { - fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { - Ok(decoder.tcx().arena.alloc_from_iter( - (0..decoder.read_usize()?) - .map(|_| Decodable::decode(decoder)) - .collect::<Result<Vec<_>, _>>()?, - )) + fn decode(decoder: &mut D) -> &'tcx Self { + decoder.tcx().arena.alloc_from_iter( + (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(), + ) } } impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<ty::BoundVariableKind> { - fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { - let len = decoder.read_usize()?; - decoder.tcx().mk_bound_variable_kinds((0..len).map(|_| Decodable::decode(decoder))) + fn decode(decoder: &mut D) -> &'tcx Self { + let len = decoder.read_usize(); + decoder.tcx().mk_bound_variable_kinds( + (0..len).map::<ty::BoundVariableKind, _>(|_| Decodable::decode(decoder)), + ) } } @@ -405,7 +399,7 @@ macro_rules! __impl_decoder_methods { ($($name:ident -> $ty:ty;)*) => { $( #[inline] - fn $name(&mut self) -> Result<$ty, Self::Error> { + fn $name(&mut self) -> $ty { self.opaque.$name() } )* @@ -418,14 +412,14 @@ macro_rules! impl_arena_allocatable_decoder { [$name:ident: $ty:ty]) => { impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for $ty { #[inline] - fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { + fn decode(decoder: &mut D) -> &'tcx Self { decode_arena_allocable(decoder) } } impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [$ty] { #[inline] - fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { + fn decode(decoder: &mut D) -> &'tcx Self { decode_arena_allocable_slice(decoder) } } @@ -456,10 +450,8 @@ macro_rules! implement_ty_decoder { use super::$DecoderName; impl<$($typaram ),*> Decoder for $DecoderName<$($typaram),*> { - type Error = String; - $crate::__impl_decoder_methods! { - read_nil -> (); + read_unit -> (); read_u128 -> u128; read_u64 -> u64; @@ -483,13 +475,9 @@ macro_rules! implement_ty_decoder { } #[inline] - fn read_raw_bytes_into(&mut self, bytes: &mut [u8]) -> Result<(), Self::Error> { + fn read_raw_bytes_into(&mut self, bytes: &mut [u8]) { self.opaque.read_raw_bytes_into(bytes) } - - fn error(&mut self, err: &str) -> Self::Error { - self.opaque.error(err) - } } } } @@ -505,9 +493,9 @@ macro_rules! impl_binder_encode_decode { } } impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<'tcx, $t> { - fn decode(decoder: &mut D) -> Result<Self, D::Error> { - let bound_vars = Decodable::decode(decoder)?; - Ok(ty::Binder::bind_with_vars(Decodable::decode(decoder)?, bound_vars)) + fn decode(decoder: &mut D) -> Self { + let bound_vars = Decodable::decode(decoder); + ty::Binder::bind_with_vars(Decodable::decode(decoder), bound_vars) } } )* diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 1f4ebd03676..de45e1bb851 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -147,8 +147,8 @@ impl<S: Encoder> Encodable<S> for ScalarInt { } impl<D: Decoder> Decodable<D> for ScalarInt { - fn decode(d: &mut D) -> Result<ScalarInt, D::Error> { - Ok(ScalarInt { data: d.read_u128()?, size: d.read_u8()? }) + fn decode(d: &mut D) -> ScalarInt { + ScalarInt { data: d.read_u128(), size: d.read_u8() } } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index a7d7ee5efc8..d063494f2bc 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -113,6 +113,12 @@ pub struct CtxtInterners<'tcx> { bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>, layout: InternedSet<'tcx, Layout>, adt_def: InternedSet<'tcx, AdtDef>, + + /// `#[stable]` and `#[unstable]` attributes + stability: InternedSet<'tcx, attr::Stability>, + + /// `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes + const_stability: InternedSet<'tcx, attr::ConstStability>, } impl<'tcx> CtxtInterners<'tcx> { @@ -134,6 +140,8 @@ impl<'tcx> CtxtInterners<'tcx> { bound_variable_kinds: Default::default(), layout: Default::default(), adt_def: Default::default(), + stability: Default::default(), + const_stability: Default::default(), } } @@ -212,7 +220,7 @@ pub struct CommonLifetimes<'tcx> { /// `ReStatic` pub re_static: Region<'tcx>, - /// Erased region, used after type-checking + /// Erased region, used outside of type inference. pub re_erased: Region<'tcx>, } @@ -352,7 +360,7 @@ pub struct TypeckResults<'tcx> { field_indices: ItemLocalMap<usize>, /// Stores the types for various nodes in the AST. Note that this table - /// is not guaranteed to be populated until after typeck. See + /// is not guaranteed to be populated outside inference. See /// typeck::check::fn_ctxt for details. node_types: ItemLocalMap<Ty<'tcx>>, @@ -1035,12 +1043,6 @@ pub struct GlobalCtxt<'tcx> { /// Data layout specification for the current target. pub data_layout: TargetDataLayout, - /// `#[stable]` and `#[unstable]` attributes - stability_interner: ShardedHashMap<&'tcx attr::Stability, ()>, - - /// `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes - const_stability_interner: ShardedHashMap<&'tcx attr::ConstStability, ()>, - /// Stores memory for globals (statics/consts). pub(crate) alloc_map: Lock<interpret::AllocMap<'tcx>>, @@ -1092,16 +1094,6 @@ impl<'tcx> TyCtxt<'tcx> { self.create_memory_alloc(alloc) } - // FIXME(eddyb) move to `direct_interners!`. - pub fn intern_stability(self, stab: attr::Stability) -> &'tcx attr::Stability { - self.stability_interner.intern(stab, |stab| self.arena.alloc(stab)) - } - - // FIXME(eddyb) move to `direct_interners!`. - pub fn intern_const_stability(self, stab: attr::ConstStability) -> &'tcx attr::ConstStability { - self.const_stability_interner.intern(stab, |stab| self.arena.alloc(stab)) - } - /// Returns a range of the start/end indices specified with the /// `rustc_layout_scalar_valid_range` attribute. // FIXME(eddyb) this is an awkward spot for this method, maybe move it? @@ -1185,8 +1177,6 @@ impl<'tcx> TyCtxt<'tcx> { evaluation_cache: Default::default(), crate_name: Symbol::intern(crate_name), data_layout, - stability_interner: Default::default(), - const_stability_interner: Default::default(), alloc_map: Lock::new(interpret::AllocMap::new()), output_filenames: Arc::new(output_filenames), } @@ -1952,11 +1942,11 @@ impl<'tcx> TyCtxt<'tcx> { writeln!(fmt, "InternalSubsts interner: #{}", self.0.interners.substs.len())?; writeln!(fmt, "Region interner: #{}", self.0.interners.region.len())?; - writeln!(fmt, "Stability interner: #{}", self.0.stability_interner.len())?; + writeln!(fmt, "Stability interner: #{}", self.0.interners.stability.len())?; writeln!( fmt, "Const Stability interner: #{}", - self.0.const_stability_interner.len() + self.0.interners.const_stability.len() )?; writeln!( fmt, @@ -1973,7 +1963,10 @@ impl<'tcx> TyCtxt<'tcx> { } } -/// An entry in an interner. +// This type holds a `T` in the interner. The `T` is stored in the arena and +// this type just holds a pointer to it, but it still effectively owns it. It +// impls `Borrow` so that it can be looked up using the original +// (non-arena-memory-owning) types. struct Interned<'tcx, T: ?Sized>(&'tcx T); impl<'tcx, T: 'tcx + ?Sized> Clone for Interned<'tcx, T> { @@ -1981,6 +1974,7 @@ impl<'tcx, T: 'tcx + ?Sized> Clone for Interned<'tcx, T> { Interned(self.0) } } + impl<'tcx, T: 'tcx + ?Sized> Copy for Interned<'tcx, T> {} impl<'tcx, T: 'tcx + ?Sized> IntoPointer for Interned<'tcx, T> { @@ -1988,9 +1982,18 @@ impl<'tcx, T: 'tcx + ?Sized> IntoPointer for Interned<'tcx, T> { self.0 as *const _ as *const () } } -// N.B., an `Interned<Ty>` compares and hashes as a `TyKind`. + +#[allow(rustc::usage_of_ty_tykind)] +impl<'tcx> Borrow<TyKind<'tcx>> for Interned<'tcx, TyS<'tcx>> { + fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> { + &self.0.kind() + } +} + impl<'tcx> PartialEq for Interned<'tcx, TyS<'tcx>> { fn eq(&self, other: &Interned<'tcx, TyS<'tcx>>) -> bool { + // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals + // `x == y`. self.0.kind() == other.0.kind() } } @@ -1999,19 +2002,21 @@ impl<'tcx> Eq for Interned<'tcx, TyS<'tcx>> {} impl<'tcx> Hash for Interned<'tcx, TyS<'tcx>> { fn hash<H: Hasher>(&self, s: &mut H) { + // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`. self.0.kind().hash(s) } } -#[allow(rustc::usage_of_ty_tykind)] -impl<'tcx> Borrow<TyKind<'tcx>> for Interned<'tcx, TyS<'tcx>> { - fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> { - &self.0.kind() +impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for Interned<'tcx, PredicateInner<'tcx>> { + fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> { + &self.0.kind } } -// N.B., an `Interned<PredicateInner>` compares and hashes as a `PredicateKind`. + impl<'tcx> PartialEq for Interned<'tcx, PredicateInner<'tcx>> { fn eq(&self, other: &Interned<'tcx, PredicateInner<'tcx>>) -> bool { + // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals + // `x == y`. self.0.kind == other.0.kind } } @@ -2020,19 +2025,21 @@ impl<'tcx> Eq for Interned<'tcx, PredicateInner<'tcx>> {} impl<'tcx> Hash for Interned<'tcx, PredicateInner<'tcx>> { fn hash<H: Hasher>(&self, s: &mut H) { + // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`. self.0.kind.hash(s) } } -impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for Interned<'tcx, PredicateInner<'tcx>> { - fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> { - &self.0.kind +impl<'tcx, T> Borrow<[T]> for Interned<'tcx, List<T>> { + fn borrow<'a>(&'a self) -> &'a [T] { + &self.0[..] } } -// N.B., an `Interned<List<T>>` compares and hashes as its elements. impl<'tcx, T: PartialEq> PartialEq for Interned<'tcx, List<T>> { fn eq(&self, other: &Interned<'tcx, List<T>>) -> bool { + // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals + // `x == y`. self.0[..] == other.0[..] } } @@ -2041,20 +2048,23 @@ impl<'tcx, T: Eq> Eq for Interned<'tcx, List<T>> {} impl<'tcx, T: Hash> Hash for Interned<'tcx, List<T>> { fn hash<H: Hasher>(&self, s: &mut H) { + // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`. self.0[..].hash(s) } } -impl<'tcx, T> Borrow<[T]> for Interned<'tcx, List<T>> { - fn borrow<'a>(&'a self) -> &'a [T] { - &self.0[..] - } -} - macro_rules! direct_interners { ($($name:ident: $method:ident($ty:ty),)+) => { - $(impl<'tcx> PartialEq for Interned<'tcx, $ty> { + $(impl<'tcx> Borrow<$ty> for Interned<'tcx, $ty> { + fn borrow<'a>(&'a self) -> &'a $ty { + &self.0 + } + } + + impl<'tcx> PartialEq for Interned<'tcx, $ty> { fn eq(&self, other: &Self) -> bool { + // The `Borrow` trait requires that `x.borrow() == y.borrow()` + // equals `x == y`. self.0 == other.0 } } @@ -2063,16 +2073,12 @@ macro_rules! direct_interners { impl<'tcx> Hash for Interned<'tcx, $ty> { fn hash<H: Hasher>(&self, s: &mut H) { + // The `Borrow` trait requires that `x.borrow().hash(s) == + // x.hash(s)`. self.0.hash(s) } } - impl<'tcx> Borrow<$ty> for Interned<'tcx, $ty> { - fn borrow<'a>(&'a self) -> &'a $ty { - &self.0 - } - } - impl<'tcx> TyCtxt<'tcx> { pub fn $method(self, v: $ty) -> &'tcx $ty { self.interners.$name.intern(v, |v| { @@ -2089,6 +2095,8 @@ direct_interners! { const_allocation: intern_const_alloc(Allocation), layout: intern_layout(Layout), adt_def: intern_adt_def(AdtDef), + stability: intern_stability(attr::Stability), + const_stability: intern_const_stability(attr::ConstStability), } macro_rules! slice_interners { @@ -2786,8 +2794,33 @@ pub trait InternIteratorElement<T, R>: Sized { impl<T, R> InternIteratorElement<T, R> for T { type Output = R; - fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output { - f(&iter.collect::<SmallVec<[_; 8]>>()) + fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>( + mut iter: I, + f: F, + ) -> Self::Output { + // This code is hot enough that it's worth specializing for the most + // common length lists, to avoid the overhead of `SmallVec` creation. + // Lengths 0, 1, and 2 typically account for ~95% of cases. If + // `size_hint` is incorrect a panic will occur via an `unwrap` or an + // `assert`. + match iter.size_hint() { + (0, Some(0)) => { + assert!(iter.next().is_none()); + f(&[]) + } + (1, Some(1)) => { + let t0 = iter.next().unwrap(); + assert!(iter.next().is_none()); + f(&[t0]) + } + (2, Some(2)) => { + let t0 = iter.next().unwrap(); + let t1 = iter.next().unwrap(); + assert!(iter.next().is_none()); + f(&[t0, t1]) + } + _ => f(&iter.collect::<SmallVec<[_; 8]>>()), + } } } @@ -2797,6 +2830,7 @@ where { type Output = R; fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output { + // This code isn't hot. f(&iter.cloned().collect::<SmallVec<[_; 8]>>()) } } @@ -2809,10 +2843,15 @@ impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> { ) -> Self::Output { // This code is hot enough that it's worth specializing for the most // common length lists, to avoid the overhead of `SmallVec` creation. - // The match arms are in order of frequency. The 1, 2, and 0 cases are - // typically hit in ~95% of cases. We assume that if the upper and - // lower bounds from `size_hint` agree they are correct. + // Lengths 0, 1, and 2 typically account for ~95% of cases. If + // `size_hint` is incorrect a panic will occur via an `unwrap` or an + // `assert`, unless a failure happens first, in which case the result + // will be an error anyway. Ok(match iter.size_hint() { + (0, Some(0)) => { + assert!(iter.next().is_none()); + f(&[]) + } (1, Some(1)) => { let t0 = iter.next().unwrap()?; assert!(iter.next().is_none()); @@ -2824,10 +2863,6 @@ impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> { assert!(iter.next().is_none()); f(&[t0, t1]) } - (0, Some(0)) => { - assert!(iter.next().is_none()); - f(&[]) - } _ => f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?), }) } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 5bb687512f3..5c4a4cdde25 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -972,10 +972,10 @@ fn foo(&self) -> Self::T { String::new() } let (span, sugg) = if has_params { let pos = span.hi() - BytePos(1); let span = Span::new(pos, pos, span.ctxt(), span.parent()); - (span, format!(", {} = {}", assoc.ident, ty)) + (span, format!(", {} = {}", assoc.ident(self), ty)) } else { let item_args = self.format_generic_args(assoc_substs); - (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident, item_args, ty)) + (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident(self), item_args, ty)) }; db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect); return true; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 4bc3e23f4a5..e7a8e71ce71 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -119,6 +119,8 @@ mod sty; // Data types +pub type RegisteredTools = FxHashSet<Ident>; + #[derive(Debug)] pub struct ResolverOutputs { pub definitions: rustc_hir::definitions::Definitions, @@ -141,6 +143,7 @@ pub struct ResolverOutputs { /// Mapping from ident span to path span for paths that don't exist as written, but that /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. pub confused_type_with_std_module: FxHashMap<Span, Span>, + pub registered_tools: RegisteredTools, } #[derive(Clone, Copy, Debug)] @@ -376,15 +379,28 @@ pub struct CReaderCacheKey { pub pos: usize, } +/// Represents a type. +/// +/// IMPORTANT: Every `TyS` is *required* to have unique contents. The type's +/// correctness relies on this, *but it does not enforce it*. Therefore, any +/// code that creates a `TyS` must ensure uniqueness itself. In practice this +/// is achieved by interning. #[allow(rustc::usage_of_ty_tykind)] pub struct TyS<'tcx> { /// This field shouldn't be used directly and may be removed in the future. /// Use `TyS::kind()` instead. kind: TyKind<'tcx>, + + /// This field provides fast access to information that is also contained + /// in `kind`. + /// /// This field shouldn't be used directly and may be removed in the future. /// Use `TyS::flags()` instead. flags: TypeFlags, + /// This field provides fast access to information that is also contained + /// in `kind`. + /// /// This is a kind of confusing thing: it stores the smallest /// binder such that /// @@ -436,6 +452,8 @@ impl<'tcx> PartialOrd for TyS<'tcx> { impl<'tcx> PartialEq for TyS<'tcx> { #[inline] fn eq(&self, other: &TyS<'tcx>) -> bool { + // Pointer equality implies equality (due to the unique contents + // assumption). ptr::eq(self, other) } } @@ -443,6 +461,8 @@ impl<'tcx> Eq for TyS<'tcx> {} impl<'tcx> Hash for TyS<'tcx> { fn hash<H: Hasher>(&self, s: &mut H) { + // Pointer hashing is sufficient (due to the unique contents + // assumption). (self as *const TyS<'_>).hash(s) } } @@ -746,6 +766,17 @@ impl<'tcx> TraitPredicate<'tcx> { *param_env = param_env.with_constness(self.constness.and(param_env.constness())) } } + + /// Remap the constness of this predicate before emitting it for diagnostics. + pub fn remap_constness_diag(&mut self, param_env: ParamEnv<'tcx>) { + // this is different to `remap_constness` that callees want to print this predicate + // in case of selection errors. `T: ~const Drop` bounds cannot end up here when the + // param_env is not const because we it is always satisfied in non-const contexts. + if let hir::Constness::NotConst = param_env.constness() { + self.constness = ty::BoundConstness::NotConst; + } + } + pub fn def_id(self) -> DefId { self.trait_ref.def_id } @@ -753,6 +784,11 @@ impl<'tcx> TraitPredicate<'tcx> { pub fn self_ty(self) -> Ty<'tcx> { self.trait_ref.self_ty() } + + #[inline] + pub fn is_const_if_const(self) -> bool { + self.constness == BoundConstness::ConstIfConst + } } impl<'tcx> PolyTraitPredicate<'tcx> { @@ -764,6 +800,19 @@ impl<'tcx> PolyTraitPredicate<'tcx> { pub fn self_ty(self) -> ty::Binder<'tcx, Ty<'tcx>> { self.map_bound(|trait_ref| trait_ref.self_ty()) } + + /// Remap the constness of this predicate before emitting it for diagnostics. + pub fn remap_constness_diag(&mut self, param_env: ParamEnv<'tcx>) { + *self = self.map_bound(|mut p| { + p.remap_constness_diag(param_env); + p + }); + } + + #[inline] + pub fn is_const_if_const(self) -> bool { + self.skip_binder().is_const_if_const() + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] @@ -1349,6 +1398,11 @@ impl<'tcx> ParamEnv<'tcx> { self.packed.tag().constness } + #[inline] + pub fn is_const(self) -> bool { + self.packed.tag().constness == hir::Constness::Const + } + /// Construct a trait environment with no where-clauses in scope /// where the values of all `impl Trait` and other hidden types /// are revealed. This is suitable for monomorphized, post-typeck @@ -1464,6 +1518,7 @@ impl<'tcx> PolyTraitRef<'tcx> { polarity: ty::ImplPolarity::Positive, }) } + #[inline] pub fn without_const(self) -> PolyTraitPredicate<'tcx> { self.with_constness(BoundConstness::NotConst) diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 84ab42a760b..b3b2bb4459f 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -34,8 +34,8 @@ impl<'tcx> TyCtxt<'tcx> { /// Erase the regions in `value` and then fully normalize all the /// types found within. The result will also have regions erased. /// - /// This is appropriate to use only after type-check: it assumes - /// that normalization will succeed, for example. + /// This should only be used outside of type inference. For example, + /// it assumes that normalization will succeed. pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T where T: TypeFoldable<'tcx>, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index bbdaf248a9e..ddcc8680d83 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -908,7 +908,7 @@ pub trait PrettyPrinter<'tcx>: if !first { p!(", "); } - p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).ident)); + p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).name)); match term.skip_binder() { Term::Ty(ty) => { @@ -2413,6 +2413,29 @@ impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> { } } +#[derive(Copy, Clone, TypeFoldable, Lift)] +pub struct TraitPredPrintModifiersAndPath<'tcx>(ty::TraitPredicate<'tcx>); + +impl<'tcx> fmt::Debug for TraitPredPrintModifiersAndPath<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +impl<'tcx> ty::TraitPredicate<'tcx> { + pub fn print_modifiers_and_trait_path(self) -> TraitPredPrintModifiersAndPath<'tcx> { + TraitPredPrintModifiersAndPath(self) + } +} + +impl<'tcx> ty::PolyTraitPredicate<'tcx> { + pub fn print_modifiers_and_trait_path( + self, + ) -> ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>> { + self.map_bound(TraitPredPrintModifiersAndPath) + } +} + forward_display_to_print! { Ty<'tcx>, &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, @@ -2427,6 +2450,7 @@ forward_display_to_print! { ty::Binder<'tcx, TraitRefPrintOnlyTraitName<'tcx>>, ty::Binder<'tcx, ty::FnSig<'tcx>>, ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, + ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>, ty::Binder<'tcx, ty::SubtypePredicate<'tcx>>, ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>, ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>, @@ -2455,7 +2479,7 @@ define_print_and_forward_display! { } ty::ExistentialProjection<'tcx> { - let name = cx.tcx().associated_item(self.item_def_id).ident; + let name = cx.tcx().associated_item(self.item_def_id).name; p!(write("{} = ", name), print(self.term)) } @@ -2491,6 +2515,18 @@ define_print_and_forward_display! { p!(print_def_path(self.0.def_id, &[])); } + TraitPredPrintModifiersAndPath<'tcx> { + if let ty::BoundConstness::ConstIfConst = self.0.constness { + p!("~const ") + } + + if let ty::ImplPolarity::Negative = self.0.polarity { + p!("!") + } + + p!(print(self.0.trait_ref.print_only_trait_path())); + } + ty::ParamTy { p!(write("{}", self.name)) } @@ -2508,8 +2544,11 @@ define_print_and_forward_display! { } ty::TraitPredicate<'tcx> { - p!(print(self.trait_ref.self_ty()), ": ", - print(self.trait_ref.print_only_trait_path())) + p!(print(self.trait_ref.self_ty()), ": "); + if let ty::BoundConstness::ConstIfConst = self.constness { + p!("~const "); + } + p!(print(self.trait_ref.print_only_trait_path())) } ty::ProjectionPredicate<'tcx> { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 20db25f7899..7d4af6cfa40 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1464,11 +1464,11 @@ pub enum RegionKind { /// Static data that has an "infinite" lifetime. Top in the region lattice. ReStatic, - /// A region variable. Should not exist after typeck. + /// A region variable. Should not exist outside of type inference. ReVar(RegionVid), /// A placeholder region -- basically, the higher-ranked version of `ReFree`. - /// Should not exist after typeck. + /// Should not exist outside of type inference. RePlaceholder(ty::PlaceholderRegion), /// Empty lifetime is for data that is never accessed. We tag the @@ -1810,7 +1810,7 @@ impl<'tcx> TyS<'tcx> { pub fn sequence_element_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self.kind() { Array(ty, _) | Slice(ty) => ty, - Str => tcx.mk_mach_uint(ty::UintTy::U8), + Str => tcx.types.u8, _ => bug!("`sequence_element_type` called on non-sequence value: {}", self), } } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 63e9b58584c..cf97344f18e 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -180,8 +180,8 @@ impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for GenericArg<'tcx> { } impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for GenericArg<'tcx> { - fn decode(d: &mut D) -> Result<GenericArg<'tcx>, D::Error> { - Ok(GenericArgKind::decode(d)?.pack()) + fn decode(d: &mut D) -> GenericArg<'tcx> { + GenericArgKind::decode(d).pack() } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 8793264a47f..96c27d649e4 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1041,6 +1041,42 @@ pub fn needs_drop_components<'tcx>( } } +pub fn is_trivially_const_drop<'tcx>(ty: Ty<'tcx>) -> bool { + match *ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Infer(ty::IntVar(_)) + | ty::Infer(ty::FloatVar(_)) + | ty::Str + | ty::RawPtr(_) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Never + | ty::Foreign(_) => true, + + ty::Opaque(..) + | ty::Dynamic(..) + | ty::Error(_) + | ty::Bound(..) + | ty::Param(_) + | ty::Placeholder(_) + | ty::Projection(_) + | ty::Infer(_) => false, + + // Not trivial because they have components, and instead of looking inside, + // we'll just perform trait selection. + ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(_) | ty::Adt(..) => false, + + ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty), + + ty::Tuple(tys) => tys.iter().all(|ty| is_trivially_const_drop(ty.expect_ty())), + } +} + // Does the equivalent of // ``` // let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>(); diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 85950d82419..3294f2cf641 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1347,23 +1347,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut otherwise = None; for match_pair in match_pairs { - if let PatKind::Or { ref pats } = *match_pair.pattern.kind { - let or_span = match_pair.pattern.span; - let place = match_pair.place; - - first_candidate.visit_leaves(|leaf_candidate| { - self.test_or_pattern( - leaf_candidate, - &mut otherwise, - pats, - or_span, - place.clone(), - fake_borrows, - ); - }); - } else { + let PatKind::Or { ref pats } = &*match_pair.pattern.kind else { bug!("Or-patterns should have been sorted to the end"); - } + }; + let or_span = match_pair.pattern.span; + let place = match_pair.place; + + first_candidate.visit_leaves(|leaf_candidate| { + self.test_or_pattern( + leaf_candidate, + &mut otherwise, + pats, + or_span, + place.clone(), + fake_borrows, + ); + }); } let remainder_start = otherwise.unwrap_or_else(|| self.cfg.start_new_block()); diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 7ed5d1d67ab..f4bf28bfa5c 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -88,11 +88,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { switch_ty: Ty<'tcx>, options: &mut FxIndexMap<&'tcx ty::Const<'tcx>, u128>, ) -> bool { - let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) { - Some(match_pair) => match_pair, - _ => { - return false; - } + let Some(match_pair) = candidate.match_pairs.iter().find(|mp| mp.place == *test_place) else { + return false; }; match *match_pair.pattern.kind { diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index d348aaa899e..b21ca6028a2 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -33,6 +33,9 @@ crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { if let Some(NonRecursive) = TriColorDepthFirstSearch::new(&body).run_from_start(&mut vis) { return; } + if vis.reachable_recursive_calls.is_empty() { + return; + } vis.reachable_recursive_calls.sort(); @@ -148,13 +151,14 @@ impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> { } fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool { + let terminator = self.body[bb].terminator(); + if terminator.unwind() == Some(&Some(target)) && terminator.successors().count() > 1 { + return true; + } // Don't traverse successors of recursive calls or false CFG edges. match self.body[bb].terminator().kind { TerminatorKind::Call { ref func, .. } => self.is_recursive_call(func), - - TerminatorKind::FalseUnwind { unwind: Some(imaginary_target), .. } - | TerminatorKind::FalseEdge { imaginary_target, .. } => imaginary_target == target, - + TerminatorKind::FalseEdge { imaginary_target, .. } => imaginary_target == target, _ => false, } } diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs index c61ee6f7e6c..ce8b187a744 100644 --- a/compiler/rustc_mir_transform/src/coverage/debug.rs +++ b/compiler/rustc_mir_transform/src/coverage/debug.rs @@ -111,6 +111,7 @@ use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; use super::spans::CoverageSpan; +use itertools::Itertools; use rustc_middle::mir::create_dump_file; use rustc_middle::mir::generic_graphviz::GraphvizWriter; use rustc_middle::mir::spanview::{self, SpanViewable}; @@ -739,7 +740,6 @@ pub(super) fn dump_coverage_graphviz<'tcx>( ) } }) - .collect::<Vec<_>>() .join("\n ") )); } @@ -768,7 +768,6 @@ fn bcb_to_string_sections<'tcx>( .map(|expression| { format!("Intermediate {}", debug_counters.format_counter(expression)) }) - .collect::<Vec<_>>() .join("\n"), ); } @@ -783,7 +782,6 @@ fn bcb_to_string_sections<'tcx>( covspan.format(tcx, mir_body) ) }) - .collect::<Vec<_>>() .join("\n"), ); } @@ -793,7 +791,6 @@ fn bcb_to_string_sections<'tcx>( dependency_counters .iter() .map(|counter| debug_counters.format_counter(counter)) - .collect::<Vec<_>>() .join(" \n"), )); } diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index a25402a1ff9..57862b6628d 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -1,5 +1,6 @@ use super::Error; +use itertools::Itertools; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::dominators::{self, Dominators}; use rustc_data_structures::graph::{self, GraphSuccessors, WithNumNodes, WithStartNode}; @@ -418,18 +419,11 @@ impl BasicCoverageBlockData { pub fn take_edge_counters( &mut self, ) -> Option<impl Iterator<Item = (BasicCoverageBlock, CoverageKind)>> { - self.edge_from_bcbs.take().map_or(None, |m| Some(m.into_iter())) + self.edge_from_bcbs.take().map(|m| m.into_iter()) } pub fn id(&self) -> String { - format!( - "@{}", - self.basic_blocks - .iter() - .map(|bb| bb.index().to_string()) - .collect::<Vec<_>>() - .join(ID_SEPARATOR) - ) + format!("@{}", self.basic_blocks.iter().map(|bb| bb.index().to_string()).join(ID_SEPARATOR)) } } diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index a9161580bc6..d1cb2826ded 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,6 +1,7 @@ use super::debug::term_type; use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB}; +use itertools::Itertools; use rustc_data_structures::graph::WithNumNodes; use rustc_middle::mir::spanview::source_range_no_file; use rustc_middle::mir::{ @@ -27,7 +28,7 @@ impl CoverageStatement { let stmt = &mir_body[bb].statements[stmt_index]; format!( "{}: @{}[{}]: {:?}", - source_range_no_file(tcx, &span), + source_range_no_file(tcx, span), bb.index(), stmt_index, stmt @@ -37,7 +38,7 @@ impl CoverageStatement { let term = mir_body[bb].terminator(); format!( "{}: @{}.{}: {:?}", - source_range_no_file(tcx, &span), + source_range_no_file(tcx, span), bb.index(), term_type(&term.kind), term.kind @@ -154,7 +155,7 @@ impl CoverageSpan { pub fn format<'tcx>(&self, tcx: TyCtxt<'tcx>, mir_body: &mir::Body<'tcx>) -> String { format!( "{}\n {}", - source_range_no_file(tcx, &self.span), + source_range_no_file(tcx, self.span), self.format_coverage_statements(tcx, mir_body).replace('\n', "\n "), ) } @@ -169,11 +170,7 @@ impl CoverageSpan { CoverageStatement::Statement(bb, _, index) => (bb, index), CoverageStatement::Terminator(bb, _) => (bb, usize::MAX), }); - sorted_coverage_statements - .iter() - .map(|covstmt| covstmt.format(tcx, mir_body)) - .collect::<Vec<_>>() - .join("\n") + sorted_coverage_statements.iter().map(|covstmt| covstmt.format(tcx, mir_body)).join("\n") } /// If the span is part of a macro, returns the macro name symbol. diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index b9c79d4cf2d..62ea2538ff0 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -31,6 +31,7 @@ use super::spans; use coverage_test_macros::let_bcb; +use itertools::Itertools; use rustc_data_structures::graph::WithNumNodes; use rustc_data_structures::graph::WithSuccessors; use rustc_index::vec::{Idx, IndexVec}; @@ -232,11 +233,9 @@ fn print_mir_graphviz(name: &str, mir_body: &Body<'_>) { mir_body .successors(bb) .map(|successor| { format!(" {:?} -> {:?};", bb, successor) }) - .collect::<Vec<_>>() .join("\n") ) }) - .collect::<Vec<_>>() .join("\n") ); } @@ -262,11 +261,9 @@ fn print_coverage_graphviz( basic_coverage_blocks .successors(bcb) .map(|successor| { format!(" {:?} -> {:?};", bcb, successor) }) - .collect::<Vec<_>>() .join("\n") ) }) - .collect::<Vec<_>>() .join("\n") ); } diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index ac88060f0d3..9a6b6532ce8 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -1,12 +1,12 @@ use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::*; -use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use std::fmt::Debug; use super::simplify::simplify_cfg; /// This pass optimizes something like -/// ```text +/// ```ignore (syntax-highlighting-only) /// let x: Option<()>; /// let y: Option<()>; /// match (x,y) { @@ -15,144 +15,201 @@ use super::simplify::simplify_cfg; /// } /// ``` /// into something like -/// ```text +/// ```ignore (syntax-highlighting-only) /// let x: Option<()>; /// let y: Option<()>; -/// let discriminant_x = // get discriminant of x -/// let discriminant_y = // get discriminant of y -/// if discriminant_x != discriminant_y || discriminant_x == None {1} else {0} +/// let discriminant_x = std::mem::discriminant(x); +/// let discriminant_y = std::mem::discriminant(y); +/// if discriminant_x == discriminant_y { +/// match x { +/// Some(_) => 0, +/// _ => 1, // <---- +/// } // | Actually the same bb +/// } else { // | +/// 1 // <-------------- +/// } +/// ``` +/// +/// Specifically, it looks for instances of control flow like this: +/// ```text +/// +/// ================= +/// | BB1 | +/// |---------------| ============================ +/// | ... | /------> | BBC | +/// |---------------| | |--------------------------| +/// | switchInt(Q) | | | _cl = discriminant(P) | +/// | c | --------/ |--------------------------| +/// | d | -------\ | switchInt(_cl) | +/// | ... | | | c | ---> BBC.2 +/// | otherwise | --\ | /--- | otherwise | +/// ================= | | | ============================ +/// | | | +/// ================= | | | +/// | BBU | <-| | | ============================ +/// |---------------| | \-------> | BBD | +/// |---------------| | | |--------------------------| +/// | unreachable | | | | _dl = discriminant(P) | +/// ================= | | |--------------------------| +/// | | | switchInt(_dl) | +/// ================= | | | d | ---> BBD.2 +/// | BB9 | <--------------- | otherwise | +/// |---------------| ============================ +/// | ... | +/// ================= /// ``` +/// Where the `otherwise` branch on `BB1` is permitted to either go to `BBU` or to `BB9`. In the +/// code: +/// - `BB1` is `parent` and `BBC, BBD` are children +/// - `P` is `child_place` +/// - `child_ty` is the type of `_cl`. +/// - `Q` is `parent_op`. +/// - `parent_ty` is the type of `Q`. +/// - `BB9` is `destination` +/// All this is then transformed into: +/// ```text +/// +/// ======================= +/// | BB1 | +/// |---------------------| ============================ +/// | ... | /------> | BBEq | +/// | _s = discriminant(P)| | |--------------------------| +/// | _t = Ne(Q, _s) | | |--------------------------| +/// |---------------------| | | switchInt(Q) | +/// | switchInt(_t) | | | c | ---> BBC.2 +/// | false | --------/ | d | ---> BBD.2 +/// | otherwise | ---------------- | otherwise | +/// ======================= | ============================ +/// | +/// ================= | +/// | BB9 | <-----------/ +/// |---------------| +/// | ... | +/// ================= +/// ``` +/// +/// This is only correct for some `P`, since `P` is now computed outside the original `switchInt`. +/// The filter on which `P` are allowed (together with discussion of its correctness) is found in +/// `may_hoist`. pub struct EarlyOtherwiseBranch; impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - // FIXME(#78496) - sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() >= 3 + sess.mir_opt_level() >= 2 } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("running EarlyOtherwiseBranch on {:?}", body.source); - // we are only interested in this bb if the terminator is a switchInt - let bbs_with_switch = - body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator())); + let mut should_cleanup = false; - let opts_to_apply: Vec<OptimizationToApply<'tcx>> = bbs_with_switch - .flat_map(|(bb_idx, bb)| { - let switch = bb.terminator(); - let helper = Helper { body, tcx }; - let infos = helper.go(bb, switch)?; - Some(OptimizationToApply { infos, basic_block_first_switch: bb_idx }) - }) - .collect(); - - let should_cleanup = !opts_to_apply.is_empty(); + // Also consider newly generated bbs in the same pass + for i in 0..body.basic_blocks().len() { + let bbs = body.basic_blocks(); + let parent = BasicBlock::from_usize(i); + let Some(opt_data) = evaluate_candidate(tcx, body, parent) else { + continue + }; - for opt_to_apply in opts_to_apply { - if !tcx.consider_optimizing(|| format!("EarlyOtherwiseBranch {:?}", &opt_to_apply)) { + if !tcx.consider_optimizing(|| format!("EarlyOtherwiseBranch {:?}", &opt_data)) { break; } - trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_to_apply); + trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_data); - let statements_before = - body.basic_blocks()[opt_to_apply.basic_block_first_switch].statements.len(); - let end_of_block_location = Location { - block: opt_to_apply.basic_block_first_switch, - statement_index: statements_before, + should_cleanup = true; + + let TerminatorKind::SwitchInt { + discr: parent_op, + switch_ty: parent_ty, + targets: parent_targets + } = &bbs[parent].terminator().kind else { + unreachable!() + }; + // Always correct since we can only switch on `Copy` types + let parent_op = match parent_op { + Operand::Move(x) => Operand::Copy(*x), + Operand::Copy(x) => Operand::Copy(*x), + Operand::Constant(x) => Operand::Constant(x.clone()), }; + let statements_before = bbs[parent].statements.len(); + let parent_end = Location { block: parent, statement_index: statements_before }; let mut patch = MirPatch::new(body); - // create temp to store second discriminant in - let discr_type = opt_to_apply.infos[0].second_switch_info.discr_ty; - let discr_span = opt_to_apply.infos[0].second_switch_info.discr_source_info.span; - let second_discriminant_temp = patch.new_temp(discr_type, discr_span); + // create temp to store second discriminant in, `_s` in example above + let second_discriminant_temp = + patch.new_temp(opt_data.child_ty, opt_data.child_source.span); - patch.add_statement( - end_of_block_location, - StatementKind::StorageLive(second_discriminant_temp), - ); + patch.add_statement(parent_end, StatementKind::StorageLive(second_discriminant_temp)); // create assignment of discriminant - let place_of_adt_to_get_discriminant_of = - opt_to_apply.infos[0].second_switch_info.place_of_adt_discr_read; patch.add_assign( - end_of_block_location, + parent_end, Place::from(second_discriminant_temp), - Rvalue::Discriminant(place_of_adt_to_get_discriminant_of), + Rvalue::Discriminant(opt_data.child_place), ); - // create temp to store NotEqual comparison between the two discriminants - let not_equal = BinOp::Ne; - let not_equal_res_type = not_equal.ty(tcx, discr_type, discr_type); - let not_equal_temp = patch.new_temp(not_equal_res_type, discr_span); - patch.add_statement(end_of_block_location, StatementKind::StorageLive(not_equal_temp)); - - // create NotEqual comparison between the two discriminants - let first_descriminant_place = - opt_to_apply.infos[0].first_switch_info.discr_used_in_switch; - let not_equal_rvalue = Rvalue::BinaryOp( - not_equal, - Box::new(( - Operand::Copy(Place::from(second_discriminant_temp)), - Operand::Copy(first_descriminant_place), - )), + // create temp to store inequality comparison between the two discriminants, `_t` in + // example above + let nequal = BinOp::Ne; + let comp_res_type = nequal.ty(tcx, parent_ty, opt_data.child_ty); + let comp_temp = patch.new_temp(comp_res_type, opt_data.child_source.span); + patch.add_statement(parent_end, StatementKind::StorageLive(comp_temp)); + + // create inequality comparison between the two discriminants + let comp_rvalue = Rvalue::BinaryOp( + nequal, + Box::new((parent_op.clone(), Operand::Move(Place::from(second_discriminant_temp)))), ); patch.add_statement( - end_of_block_location, - StatementKind::Assign(Box::new((Place::from(not_equal_temp), not_equal_rvalue))), + parent_end, + StatementKind::Assign(Box::new((Place::from(comp_temp), comp_rvalue))), ); - let new_targets = opt_to_apply - .infos - .iter() - .flat_map(|x| x.second_switch_info.targets_with_values.iter()) - .cloned(); - - let targets = SwitchTargets::new( - new_targets, - opt_to_apply.infos[0].first_switch_info.otherwise_bb, - ); - - // new block that jumps to the correct discriminant case. This block is switched to if the discriminants are equal - let new_switch_data = BasicBlockData::new(Some(Terminator { - source_info: opt_to_apply.infos[0].second_switch_info.discr_source_info, + let eq_new_targets = parent_targets.iter().map(|(value, child)| { + let TerminatorKind::SwitchInt{ targets, .. } = &bbs[child].terminator().kind else { + unreachable!() + }; + (value, targets.target_for_value(value)) + }); + let eq_targets = SwitchTargets::new(eq_new_targets, opt_data.destination); + + // Create `bbEq` in example above + let eq_switch = BasicBlockData::new(Some(Terminator { + source_info: bbs[parent].terminator().source_info, kind: TerminatorKind::SwitchInt { - // the first and second discriminants are equal, so just pick one - discr: Operand::Copy(first_descriminant_place), - switch_ty: discr_type, - targets, + // switch on the first discriminant, so we can mark the second one as dead + discr: parent_op, + switch_ty: opt_data.child_ty, + targets: eq_targets, }, })); - let new_switch_bb = patch.new_block(new_switch_data); + let eq_bb = patch.new_block(eq_switch); - // switch on the NotEqual. If true, then jump to the `otherwise` case. - // If false, then jump to a basic block that then jumps to the correct disciminant case - let true_case = opt_to_apply.infos[0].first_switch_info.otherwise_bb; - let false_case = new_switch_bb; + // Jump to it on the basis of the inequality comparison + let true_case = opt_data.destination; + let false_case = eq_bb; patch.patch_terminator( - opt_to_apply.basic_block_first_switch, + parent, TerminatorKind::if_( tcx, - Operand::Move(Place::from(not_equal_temp)), + Operand::Move(Place::from(comp_temp)), true_case, false_case, ), ); // generate StorageDead for the second_discriminant_temp not in use anymore - patch.add_statement( - end_of_block_location, - StatementKind::StorageDead(second_discriminant_temp), - ); + patch.add_statement(parent_end, StatementKind::StorageDead(second_discriminant_temp)); - // Generate a StorageDead for not_equal_temp in each of the targets, since we moved it into the switch + // Generate a StorageDead for comp_temp in each of the targets, since we moved it into + // the switch for bb in [false_case, true_case].iter() { patch.add_statement( Location { block: *bb, statement_index: 0 }, - StatementKind::StorageDead(not_equal_temp), + StatementKind::StorageDead(comp_temp), ); } @@ -167,201 +224,177 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { } } -fn is_switch(terminator: &Terminator<'_>) -> bool { - matches!(terminator.kind, TerminatorKind::SwitchInt { .. }) -} - -struct Helper<'a, 'tcx> { - body: &'a Body<'tcx>, - tcx: TyCtxt<'tcx>, -} - -#[derive(Debug, Clone)] -struct SwitchDiscriminantInfo<'tcx> { - /// Type of the discriminant being switched on - discr_ty: Ty<'tcx>, - /// The basic block that the otherwise branch points to - otherwise_bb: BasicBlock, - /// Target along with the value being branched from. Otherwise is not included - targets_with_values: Vec<(u128, BasicBlock)>, - discr_source_info: SourceInfo, - /// The place of the discriminant used in the switch - discr_used_in_switch: Place<'tcx>, - /// The place of the adt that has its discriminant read - place_of_adt_discr_read: Place<'tcx>, - /// The type of the adt that has its discriminant read - type_adt_matched_on: Ty<'tcx>, -} - -#[derive(Debug)] -struct OptimizationToApply<'tcx> { - infos: Vec<OptimizationInfo<'tcx>>, - /// Basic block of the original first switch - basic_block_first_switch: BasicBlock, +/// Returns true if computing the discriminant of `place` may be hoisted out of the branch +fn may_hoist<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, place: Place<'tcx>) -> bool { + for (place, proj) in place.iter_projections() { + match proj { + // Dereferencing in the computation of `place` might cause issues from one of two + // cateogires. First, the referrent might be invalid. We protect against this by + // dereferencing references only (not pointers). Second, the use of a reference may + // invalidate other references that are used later (for aliasing reasons). Consider + // where such an invalidated reference may appear: + // - In `Q`: Not possible since `Q` is used as the operand of a `SwitchInt` and so + // cannot contain referenced data. + // - In `BBU`: Not possible since that block contains only the `unreachable` terminator + // - In `BBC.2, BBD.2`: Not possible, since `discriminant(P)` was computed prior to + // reaching that block in the input to our transformation, and so any data + // invalidated by that computation could not have been used there. + // - In `BB9`: Not possible since control flow might have reached `BB9` via the + // `otherwise` branch in `BBC, BBD` in the input to our transformation, which would + // have invalidated the data when computing `discriminant(P)` + // So dereferencing here is correct. + ProjectionElem::Deref => match place.ty(body.local_decls(), tcx).ty.kind() { + ty::Ref(..) => {} + _ => return false, + }, + // Field projections are always valid + ProjectionElem::Field(..) => {} + // We cannot allow + // downcasts either, since the correctness of the downcast may depend on the parent + // branch being taken. An easy example of this is + // ``` + // Q = discriminant(_3) + // P = (_3 as Variant) + // ``` + // However, checking if the child and parent place are the same and only erroring then + // is not sufficient either, since the `discriminant(_3) == 1` (or whatever) check may + // be replaced by another optimization pass with any other condition that can be proven + // equivalent. + ProjectionElem::Downcast(..) => { + return false; + } + // We cannot allow indexing since the index may be out of bounds. + _ => { + return false; + } + } + } + true } #[derive(Debug)] -struct OptimizationInfo<'tcx> { - /// Info about the first switch and discriminant - first_switch_info: SwitchDiscriminantInfo<'tcx>, - /// Info about the second switch and discriminant - second_switch_info: SwitchDiscriminantInfo<'tcx>, +struct OptimizationData<'tcx> { + destination: BasicBlock, + child_place: Place<'tcx>, + child_ty: Ty<'tcx>, + child_source: SourceInfo, } -impl<'tcx> Helper<'_, 'tcx> { - pub fn go( - &self, - bb: &BasicBlockData<'tcx>, - switch: &Terminator<'tcx>, - ) -> Option<Vec<OptimizationInfo<'tcx>>> { - // try to find the statement that defines the discriminant that is used for the switch - let discr = self.find_switch_discriminant_info(bb, switch)?; - - // go through each target, finding a discriminant read, and a switch - let results = discr - .targets_with_values - .iter() - .map(|(value, target)| self.find_discriminant_switch_pairing(&discr, *target, *value)); - - // if the optimization did not apply for one of the targets, then abort - if results.clone().any(|x| x.is_none()) || results.len() == 0 { - trace!("NO: not all of the targets matched the pattern for optimization"); - return None; +fn evaluate_candidate<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + parent: BasicBlock, +) -> Option<OptimizationData<'tcx>> { + let bbs = body.basic_blocks(); + let TerminatorKind::SwitchInt { + targets, + switch_ty: parent_ty, + .. + } = &bbs[parent].terminator().kind else { + return None + }; + let parent_dest = { + let poss = targets.otherwise(); + // If the fallthrough on the parent is trivially unreachable, we can let the + // children choose the destination + if bbs[poss].statements.len() == 0 + && bbs[poss].terminator().kind == TerminatorKind::Unreachable + { + None + } else { + Some(poss) } - - Some(results.flatten().collect()) + }; + let Some((_, child)) = targets.iter().next() else { + return None + }; + let child_terminator = &bbs[child].terminator(); + let TerminatorKind::SwitchInt { + switch_ty: child_ty, + targets: child_targets, + .. + } = &child_terminator.kind else { + return None + }; + if child_ty != parent_ty { + return None; + } + let Some(StatementKind::Assign(boxed)) + = &bbs[child].statements.first().map(|x| &x.kind) else { + return None; + }; + let (_, Rvalue::Discriminant(child_place)) = &**boxed else { + return None; + }; + let destination = parent_dest.unwrap_or(child_targets.otherwise()); + + // Verify that the optimization is legal in general + // We can hoist evaluating the child discriminant out of the branch + if !may_hoist(tcx, body, *child_place) { + return None; } - fn find_discriminant_switch_pairing( - &self, - discr_info: &SwitchDiscriminantInfo<'tcx>, - target: BasicBlock, - value: u128, - ) -> Option<OptimizationInfo<'tcx>> { - let bb = &self.body.basic_blocks()[target]; - // find switch - let terminator = bb.terminator(); - if is_switch(terminator) { - let this_bb_discr_info = self.find_switch_discriminant_info(bb, terminator)?; - - // the types of the two adts matched on have to be equalfor this optimization to apply - if discr_info.type_adt_matched_on != this_bb_discr_info.type_adt_matched_on { - trace!( - "NO: types do not match. LHS: {:?}, RHS: {:?}", - discr_info.type_adt_matched_on, - this_bb_discr_info.type_adt_matched_on - ); - return None; - } - - // the otherwise branch of the two switches have to point to the same bb - if discr_info.otherwise_bb != this_bb_discr_info.otherwise_bb { - trace!("NO: otherwise target is not the same"); - return None; - } - - // check that the value being matched on is the same. The - if !this_bb_discr_info.targets_with_values.iter().any(|x| x.0 == value) { - trace!("NO: values being matched on are not the same"); - return None; - } - - // only allow optimization if the left and right of the tuple being matched are the same variants. - // so the following should not optimize - // ```rust - // let x: Option<()>; - // let y: Option<()>; - // match (x,y) { - // (Some(_), None) => {}, - // _ => {} - // } - // ``` - // We check this by seeing that the value of the first discriminant is the only other discriminant value being used as a target in the second switch - if !(this_bb_discr_info.targets_with_values.len() == 1 - && this_bb_discr_info.targets_with_values[0].0 == value) - { - trace!( - "NO: The second switch did not have only 1 target (besides otherwise) that had the same value as the value from the first switch that got us here" - ); - return None; - } - - // when the second place is a projection of the first one, it's not safe to calculate their discriminant values sequentially. - // for example, this should not be optimized: - // - // ```rust - // enum E<'a> { Empty, Some(&'a E<'a>), } - // let Some(Some(_)) = e; - // ``` - // - // ```mir - // bb0: { - // _2 = discriminant(*_1) - // switchInt(_2) -> [...] - // } - // bb1: { - // _3 = discriminant(*(((*_1) as Some).0: &E)) - // switchInt(_3) -> [...] - // } - // ``` - let discr_place = discr_info.place_of_adt_discr_read; - let this_discr_place = this_bb_discr_info.place_of_adt_discr_read; - if discr_place.local == this_discr_place.local - && this_discr_place.projection.starts_with(discr_place.projection) - { - trace!("NO: one target is the projection of another"); - return None; - } - - // if we reach this point, the optimization applies, and we should be able to optimize this case - // store the info that is needed to apply the optimization - - Some(OptimizationInfo { - first_switch_info: discr_info.clone(), - second_switch_info: this_bb_discr_info, - }) - } else { - None + // Verify that the optimization is legal for each branch + for (value, child) in targets.iter() { + if !verify_candidate_branch(&bbs[child], value, *child_place, destination) { + return None; } } + Some(OptimizationData { + destination, + child_place: *child_place, + child_ty, + child_source: child_terminator.source_info, + }) +} - fn find_switch_discriminant_info( - &self, - bb: &BasicBlockData<'tcx>, - switch: &Terminator<'tcx>, - ) -> Option<SwitchDiscriminantInfo<'tcx>> { - match &switch.kind { - TerminatorKind::SwitchInt { discr, targets, .. } => { - let discr_local = discr.place()?.as_local()?; - // the declaration of the discriminant read. Place of this read is being used in the switch - let discr_decl = &self.body.local_decls()[discr_local]; - let discr_ty = discr_decl.ty; - // the otherwise target lies as the last element - let otherwise_bb = targets.otherwise(); - let targets_with_values = targets.iter().collect(); - - // find the place of the adt where the discriminant is being read from - // assume this is the last statement of the block - let place_of_adt_discr_read = match bb.statements.last()?.kind { - StatementKind::Assign(box (_, Rvalue::Discriminant(adt_place))) => { - Some(adt_place) - } - _ => None, - }?; - - let type_adt_matched_on = place_of_adt_discr_read.ty(self.body, self.tcx).ty; - - Some(SwitchDiscriminantInfo { - discr_used_in_switch: discr.place()?, - discr_ty, - otherwise_bb, - targets_with_values, - discr_source_info: discr_decl.source_info, - place_of_adt_discr_read, - type_adt_matched_on, - }) - } - _ => unreachable!("must only be passed terminator that is a switch"), - } +fn verify_candidate_branch<'tcx>( + branch: &BasicBlockData<'tcx>, + value: u128, + place: Place<'tcx>, + destination: BasicBlock, +) -> bool { + // In order for the optimization to be correct, the branch must... + // ...have exactly one statement + if branch.statements.len() != 1 { + return false; + } + // ...assign the descriminant of `place` in that statement + let StatementKind::Assign(boxed) = &branch.statements[0].kind else { + return false + }; + let (discr_place, Rvalue::Discriminant(from_place)) = &**boxed else { + return false + }; + if *from_place != place { + return false; + } + // ...make that assignment to a local + if discr_place.projection.len() != 0 { + return false; + } + // ...terminate on a `SwitchInt` that invalidates that local + let TerminatorKind::SwitchInt{ discr: switch_op, targets, .. } = &branch.terminator().kind else { + return false + }; + if *switch_op != Operand::Move(*discr_place) { + return false; + } + // ...fall through to `destination` if the switch misses + if destination != targets.otherwise() { + return false; + } + // ...have a branch for value `value` + let mut iter = targets.iter(); + let Some((target_value, _)) = iter.next() else { + return false; + }; + if target_value != value { + return false; + } + // ...and have no more branches + if let Some(_) = iter.next() { + return false; } + return true; } diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index f364a332a78..1b9fddec2be 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -1,3 +1,4 @@ +use itertools::Itertools; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_middle::mir::visit::Visitor; @@ -42,54 +43,28 @@ impl<'tcx> Visitor<'tcx> for FunctionItemRefChecker<'_, 'tcx> { } = &terminator.kind { let source_info = *self.body.source_info(location); - // Only handle function calls outside macros - if !source_info.span.from_expansion() { - let func_ty = func.ty(self.body, self.tcx); - if let ty::FnDef(def_id, substs_ref) = *func_ty.kind() { - // Handle calls to `transmute` - if self.tcx.is_diagnostic_item(sym::transmute, def_id) { - let arg_ty = args[0].ty(self.body, self.tcx); - for generic_inner_ty in arg_ty.walk() { - if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { - if let Some((fn_id, fn_substs)) = - FunctionItemRefChecker::is_fn_ref(inner_ty) - { - let span = self.nth_arg_span(&args, 0); - self.emit_lint(fn_id, fn_substs, source_info, span); - } + let func_ty = func.ty(self.body, self.tcx); + if let ty::FnDef(def_id, substs_ref) = *func_ty.kind() { + // Handle calls to `transmute` + if self.tcx.is_diagnostic_item(sym::transmute, def_id) { + let arg_ty = args[0].ty(self.body, self.tcx); + for generic_inner_ty in arg_ty.walk() { + if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { + if let Some((fn_id, fn_substs)) = + FunctionItemRefChecker::is_fn_ref(inner_ty) + { + let span = self.nth_arg_span(&args, 0); + self.emit_lint(fn_id, fn_substs, source_info, span); } } - } else { - self.check_bound_args(def_id, substs_ref, &args, source_info); } + } else { + self.check_bound_args(def_id, substs_ref, &args, source_info); } } } self.super_terminator(terminator, location); } - - /// Emits a lint for function references formatted with `fmt::Pointer::fmt` by macros. These - /// cases are handled as operands instead of call terminators to avoid any dependence on - /// unstable, internal formatting details like whether `fmt` is called directly or not. - fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { - let source_info = *self.body.source_info(location); - if source_info.span.from_expansion() { - let op_ty = operand.ty(self.body, self.tcx); - if let ty::FnDef(def_id, substs_ref) = *op_ty.kind() { - if self.tcx.is_diagnostic_item(sym::pointer_trait_fmt, def_id) { - let param_ty = substs_ref.type_at(0); - if let Some((fn_id, fn_substs)) = FunctionItemRefChecker::is_fn_ref(param_ty) { - // The operand's ctxt wouldn't display the lint since it's inside a macro so - // we have to use the callsite's ctxt. - let callsite_ctxt = source_info.span.source_callsite().ctxt(); - let span = source_info.span.with_ctxt(callsite_ctxt); - self.emit_lint(fn_id, fn_substs, source_info, span); - } - } - } - } - self.super_operand(operand, location); - } } impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { @@ -119,7 +94,13 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { if let Some((fn_id, fn_substs)) = FunctionItemRefChecker::is_fn_ref(subst_ty) { - let span = self.nth_arg_span(args, arg_num); + let mut span = self.nth_arg_span(args, arg_num); + if span.from_expansion() { + // The operand's ctxt wouldn't display the lint since it's inside a macro so + // we have to use the callsite's ctxt. + let callsite_ctxt = span.source_callsite().ctxt(); + span = span.with_ctxt(callsite_ctxt); + } self.emit_lint(fn_id, fn_substs, source_info, span); } } @@ -197,7 +178,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { let ident = self.tcx.item_name(fn_id).to_ident_string(); let ty_params = fn_substs.types().map(|ty| format!("{}", ty)); let const_params = fn_substs.consts().map(|c| format!("{}", c)); - let params = ty_params.chain(const_params).collect::<Vec<String>>().join(", "); + let params = ty_params.chain(const_params).join(", "); let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder(); let variadic = if fn_sig.c_variadic() { ", ..." } else { "" }; let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" }; diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index bf6f13fa67b..8e1601fb719 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -18,7 +18,7 @@ extern crate rustc_middle; use required_consts::RequiredConstsVisitor; use rustc_const_eval::util; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::steal::Steal; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -136,8 +136,8 @@ fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool { /// Finds the full set of `DefId`s within the current crate that have /// MIR associated with them. -fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxHashSet<LocalDefId> { - let mut set = FxHashSet::default(); +fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> { + let mut set = FxIndexSet::default(); // All body-owners have MIR associated with them. set.extend(tcx.hir().body_owners()); @@ -146,7 +146,7 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxHashSet<LocalDefId> { // they don't have a BodyId, so we need to build them separately. struct GatherCtors<'a, 'tcx> { tcx: TyCtxt<'tcx>, - set: &'a mut FxHashSet<LocalDefId>, + set: &'a mut FxIndexSet<LocalDefId>, } impl<'tcx> Visitor<'tcx> for GatherCtors<'_, 'tcx> { fn visit_variant_data( diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 7e7f6938706..7f13da5d38f 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -807,10 +807,18 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.output.push(create_fn_mono_item(tcx, instance, source)); } } + mir::TerminatorKind::Abort { .. } => { + let instance = Instance::mono( + tcx, + tcx.require_lang_item(LangItem::PanicNoUnwind, Some(source)), + ); + if should_codegen_locally(tcx, &instance) { + self.output.push(create_fn_mono_item(tcx, instance, source)); + } + } mir::TerminatorKind::Goto { .. } | mir::TerminatorKind::SwitchInt { .. } | mir::TerminatorKind::Resume - | mir::TerminatorKind::Abort | mir::TerminatorKind::Return | mir::TerminatorKind::Unreachable => {} mir::TerminatorKind::GeneratorDrop diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index c41f2d3299b..17bac362ec8 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -731,28 +731,22 @@ impl<'a> Parser<'a> { match x { Ok((_, _, false)) => { if self.eat(&token::Gt) { - let turbo_err = e.span_suggestion_verbose( + e.span_suggestion_verbose( binop.span.shrink_to_lo(), TURBOFISH_SUGGESTION_STR, "::".to_string(), Applicability::MaybeIncorrect, - ); - if self.check(&TokenKind::Semi) { - turbo_err.emit(); - *expr = self.mk_expr_err(expr.span); - return Ok(()); - } else { - match self.parse_expr() { - Ok(_) => { - turbo_err.emit(); - *expr = self - .mk_expr_err(expr.span.to(self.prev_token.span)); - return Ok(()); - } - Err(mut err) => { - turbo_err.cancel(); - err.cancel(); - } + ) + .emit(); + match self.parse_expr() { + Ok(_) => { + *expr = + self.mk_expr_err(expr.span.to(self.prev_token.span)); + return Ok(()); + } + Err(mut err) => { + *expr = self.mk_expr_err(expr.span); + err.cancel(); } } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 192e87b4c01..693dd0051da 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1458,7 +1458,7 @@ impl<'a> Parser<'a> { self.parse_block_expr(label, lo, BlockCheckMode::Default, attrs) } else if !ate_colon && (self.check(&TokenKind::Comma) || self.check(&TokenKind::Gt)) { // We're probably inside of a `Path<'a>` that needs a turbofish, so suppress the - // "must be followed by a colon" error. + // "must be followed by a colon" error, and the "expected one of" error. self.diagnostic().delay_span_bug(lo, "this label wasn't parsed correctly"); consume_colon = false; Ok(self.mk_expr_err(lo)) @@ -2383,6 +2383,17 @@ impl<'a> Parser<'a> { } pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> { + fn check_let_expr(expr: &Expr) -> (bool, bool) { + match expr.kind { + ExprKind::Binary(_, ref lhs, ref rhs) => { + let lhs_rslt = check_let_expr(lhs); + let rhs_rslt = check_let_expr(rhs); + (lhs_rslt.0 || rhs_rslt.0, false) + } + ExprKind::Let(..) => (true, true), + _ => (false, true), + } + } let attrs = self.parse_outer_attributes()?; self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { let lo = this.token.span; @@ -2390,9 +2401,12 @@ impl<'a> Parser<'a> { let guard = if this.eat_keyword(kw::If) { let if_span = this.prev_token.span; let cond = this.parse_expr()?; - if let ExprKind::Let(..) = cond.kind { - // Remove the last feature gating of a `let` expression since it's stable. - this.sess.gated_spans.ungate_last(sym::let_chains, cond.span); + let (has_let_expr, does_not_have_bin_op) = check_let_expr(&cond); + if has_let_expr { + if does_not_have_bin_op { + // Remove the last feature gating of a `let` expression since it's stable. + this.sess.gated_spans.ungate_last(sym::let_chains, cond.span); + } let span = if_span.to(cond.span); this.sess.gated_spans.gate(sym::if_let_guard, span); } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index ade441b0e7d..06849b31256 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -423,7 +423,7 @@ impl<'a> Parser<'a> { // Maybe the user misspelled `macro_rules` (issue #91227) if self.token.is_ident() && path.segments.len() == 1 - && lev_distance("macro_rules", &path.segments[0].ident.to_string()) <= 3 + && lev_distance("macro_rules", &path.segments[0].ident.to_string(), 3).is_some() { err.span_suggestion( path.span, diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 0228196d1a1..00a93ccc9aa 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -1,6 +1,7 @@ //! Checks validity of naked functions. use rustc_ast::{Attribute, InlineAsmOptions}; +use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{FnKind, Visitor}; @@ -8,7 +9,6 @@ use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI; -use rustc_session::lint::builtin::UNSUPPORTED_NAKED_FUNCTIONS; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::spec::abi::Abi; @@ -64,18 +64,16 @@ impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> { check_abi(self.tcx, hir_id, fn_header.abi, ident_span); check_no_patterns(self.tcx, body.params); check_no_parameters_use(self.tcx, body); - check_asm(self.tcx, hir_id, body, span); - check_inline(self.tcx, hir_id, attrs); + check_asm(self.tcx, body, span); + check_inline(self.tcx, attrs); } } } /// Check that the function isn't inlined. -fn check_inline(tcx: TyCtxt<'_>, hir_id: HirId, attrs: &[Attribute]) { +fn check_inline(tcx: TyCtxt<'_>, attrs: &[Attribute]) { for attr in attrs.iter().filter(|attr| attr.has_name(sym::inline)) { - tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, attr.span, |lint| { - lint.build("naked functions cannot be inlined").emit(); - }); + tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit(); } } @@ -146,31 +144,31 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> { } /// Checks that function body contains a single inline assembly block. -fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId, body: &'tcx hir::Body<'tcx>, fn_span: Span) { +fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>, fn_span: Span) { let mut this = CheckInlineAssembly { tcx, items: Vec::new() }; this.visit_body(body); if let [(ItemKind::Asm, _)] = this.items[..] { // Ok. } else { - tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, fn_span, |lint| { - let mut diag = lint.build("naked functions must contain a single asm block"); - let mut has_asm = false; - for &(kind, span) in &this.items { - match kind { - ItemKind::Asm if has_asm => { - diag.span_label( - span, - "multiple asm blocks are unsupported in naked functions", - ); - } - ItemKind::Asm => has_asm = true, - ItemKind::NonAsm => { - diag.span_label(span, "non-asm is unsupported in naked functions"); - } + let mut diag = struct_span_err!( + tcx.sess, + fn_span, + E0787, + "naked functions must contain a single asm block" + ); + let mut has_asm = false; + for &(kind, span) in &this.items { + match kind { + ItemKind::Asm if has_asm => { + diag.span_label(span, "multiple asm blocks are unsupported in naked functions"); + } + ItemKind::Asm => has_asm = true, + ItemKind::NonAsm => { + diag.span_label(span, "non-asm is unsupported in naked functions"); } } - diag.emit(); - }); + } + diag.emit(); } } @@ -221,7 +219,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> { ExprKind::InlineAsm(ref asm) => { self.items.push((ItemKind::Asm, span)); - self.check_inline_asm(expr.hir_id, asm, span); + self.check_inline_asm(asm, span); } ExprKind::DropTemps(..) | ExprKind::Block(..) | ExprKind::Err => { @@ -230,7 +228,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> { } } - fn check_inline_asm(&self, hir_id: HirId, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) { + fn check_inline_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) { let unsupported_operands: Vec<Span> = asm .operands .iter() @@ -243,18 +241,17 @@ impl<'tcx> CheckInlineAssembly<'tcx> { }) .collect(); if !unsupported_operands.is_empty() { - self.tcx.struct_span_lint_hir( - UNSUPPORTED_NAKED_FUNCTIONS, - hir_id, + struct_span_err!( + self.tcx.sess, unsupported_operands, - |lint| { - lint.build("only `const` and `sym` operands are supported in naked functions") - .emit(); - }, - ); + E0787, + "only `const` and `sym` operands are supported in naked functions", + ) + .emit(); } let unsupported_options: Vec<&'static str> = [ + (InlineAsmOptions::MAY_UNWIND, "`may_unwind`"), (InlineAsmOptions::NOMEM, "`nomem`"), (InlineAsmOptions::NOSTACK, "`nostack`"), (InlineAsmOptions::PRESERVES_FLAGS, "`preserves_flags`"), @@ -266,19 +263,24 @@ impl<'tcx> CheckInlineAssembly<'tcx> { .collect(); if !unsupported_options.is_empty() { - self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| { - lint.build(&format!( - "asm options unsupported in naked functions: {}", - unsupported_options.join(", ") - )) - .emit(); - }); + struct_span_err!( + self.tcx.sess, + span, + E0787, + "asm options unsupported in naked functions: {}", + unsupported_options.join(", ") + ) + .emit(); } if !asm.options.contains(InlineAsmOptions::NORETURN) { - self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| { - lint.build("asm in naked functions must use `noreturn` option").emit(); - }); + struct_span_err!( + self.tcx.sess, + span, + E0787, + "asm in naked functions must use `noreturn` option" + ) + .emit(); } } } diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index 5f6d9b050b2..06e276ab42b 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -163,15 +163,12 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { // Decode the *position* of the footer, which can be found in the // last 8 bytes of the file. decoder.set_position(data.len() - IntEncodedWithFixedSize::ENCODED_SIZE); - let footer_pos = IntEncodedWithFixedSize::decode(&mut decoder) - .expect("error while trying to decode footer position") - .0 as usize; + let footer_pos = IntEncodedWithFixedSize::decode(&mut decoder).0 as usize; // Decode the file footer, which contains all the lookup tables, etc. decoder.set_position(footer_pos); decode_tagged(&mut decoder, TAG_FILE_FOOTER) - .expect("error while trying to decode footer position") }; Self { @@ -372,7 +369,7 @@ impl<'sess> OnDiskCache<'sess> { dep_node_index: SerializedDepNodeIndex, ) -> QuerySideEffects { let side_effects: Option<QuerySideEffects> = - self.load_indexed(tcx, dep_node_index, &self.prev_side_effects_index, "side_effects"); + self.load_indexed(tcx, dep_node_index, &self.prev_side_effects_index); side_effects.unwrap_or_default() } @@ -398,7 +395,7 @@ impl<'sess> OnDiskCache<'sess> { where T: for<'a> Decodable<CacheDecoder<'a, 'tcx>>, { - self.load_indexed(tcx, dep_node_index, &self.query_result_index, "query result") + self.load_indexed(tcx, dep_node_index, &self.query_result_index) } /// Stores side effect emitted during computation of an anonymous query. @@ -423,17 +420,13 @@ impl<'sess> OnDiskCache<'sess> { tcx: TyCtxt<'tcx>, dep_node_index: SerializedDepNodeIndex, index: &FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>, - debug_tag: &'static str, ) -> Option<T> where T: for<'a> Decodable<CacheDecoder<'a, 'tcx>>, { let pos = index.get(&dep_node_index).cloned()?; - self.with_decoder(tcx, pos, |decoder| match decode_tagged(decoder, dep_node_index) { - Ok(v) => Some(v), - Err(e) => bug!("could not decode cached {}: {}", debug_tag, e), - }) + self.with_decoder(tcx, pos, |decoder| Some(decode_tagged(decoder, dep_node_index))) } fn with_decoder<'a, 'tcx, T, F: for<'s> FnOnce(&mut CacheDecoder<'s, 'tcx>) -> T>( @@ -535,7 +528,7 @@ impl<'a, 'tcx> DecoderWithPosition for CacheDecoder<'a, 'tcx> { // Decodes something that was encoded with `encode_tagged()` and verify that the // tag matches and the correct amount of bytes was read. -fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> Result<V, D::Error> +fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> V where T: Decodable<D> + Eq + std::fmt::Debug, V: Decodable<D>, @@ -543,15 +536,15 @@ where { let start_pos = decoder.position(); - let actual_tag = T::decode(decoder)?; + let actual_tag = T::decode(decoder); assert_eq!(actual_tag, expected_tag); - let value = V::decode(decoder)?; + let value = V::decode(decoder); let end_pos = decoder.position(); - let expected_len: u64 = Decodable::decode(decoder)?; + let expected_len: u64 = Decodable::decode(decoder); assert_eq!((end_pos - start_pos) as u64, expected_len); - Ok(value) + value } impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { @@ -572,26 +565,22 @@ impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { self.opaque.data[self.opaque.position()] } - fn cached_ty_for_shorthand<F>( - &mut self, - shorthand: usize, - or_insert_with: F, - ) -> Result<Ty<'tcx>, Self::Error> + fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx> where - F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>, + F: FnOnce(&mut Self) -> Ty<'tcx>, { let tcx = self.tcx(); let cache_key = ty::CReaderCacheKey { cnum: None, pos: shorthand }; if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) { - return Ok(ty); + return ty; } - let ty = or_insert_with(self)?; + let ty = or_insert_with(self); // This may overwrite the entry, but it should overwrite with the same value. tcx.ty_rcache.borrow_mut().insert_same(cache_key, ty); - Ok(ty) + ty } fn with_position<F, R>(&mut self, pos: usize, f: F) -> R @@ -607,7 +596,7 @@ impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { r } - fn decode_alloc_id(&mut self) -> Result<interpret::AllocId, Self::Error> { + fn decode_alloc_id(&mut self) -> interpret::AllocId { let alloc_decoding_session = self.alloc_decoding_session; alloc_decoding_session.decode_alloc_id(self) } @@ -619,35 +608,35 @@ rustc_middle::implement_ty_decoder!(CacheDecoder<'a, 'tcx>); // when a `CacheDecoder` is passed to `Decodable::decode`. Unfortunately, we have to manually opt // into specializations this way, given how `CacheDecoder` and the decoding traits currently work. impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Vec<u8> { - fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { Decodable::decode(&mut d.opaque) } } impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for SyntaxContext { - fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { + fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self { let syntax_contexts = decoder.syntax_contexts; rustc_span::hygiene::decode_syntax_context(decoder, decoder.hygiene_context, |this, id| { // This closure is invoked if we haven't already decoded the data for the `SyntaxContext` we are deserializing. // We look up the position of the associated `SyntaxData` and decode it. let pos = syntax_contexts.get(&id).unwrap(); this.with_position(pos.to_usize(), |decoder| { - let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT)?; - Ok(data) + let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT); + data }) }) } } impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId { - fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { - let hash = ExpnHash::decode(decoder)?; + fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self { + let hash = ExpnHash::decode(decoder); if hash.is_root() { - return Ok(ExpnId::root()); + return ExpnId::root(); } if let Some(expn_id) = ExpnId::from_hash(hash) { - return Ok(expn_id); + return expn_id; } let krate = decoder.tcx.stable_crate_id_to_crate_num(hash.stable_crate_id()); @@ -660,7 +649,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId { .unwrap_or_else(|| panic!("Bad hash {:?} (map {:?})", hash, decoder.expn_data)); let data: ExpnData = decoder - .with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA))?; + .with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA)); let expn_id = rustc_span::hygiene::register_local_expn_id(data, hash); #[cfg(debug_assertions)] @@ -687,21 +676,21 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId { }; debug_assert_eq!(expn_id.krate, krate); - Ok(expn_id) + expn_id } } impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span { - fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { - let ctxt = SyntaxContext::decode(decoder)?; - let parent = Option::<LocalDefId>::decode(decoder)?; - let tag: u8 = Decodable::decode(decoder)?; + fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self { + let ctxt = SyntaxContext::decode(decoder); + let parent = Option::<LocalDefId>::decode(decoder); + let tag: u8 = Decodable::decode(decoder); if tag == TAG_PARTIAL_SPAN { - return Ok(Span::new(BytePos(0), BytePos(0), ctxt, parent)); + return Span::new(BytePos(0), BytePos(0), ctxt, parent); } else if tag == TAG_RELATIVE_SPAN { - let dlo = u32::decode(decoder)?; - let dto = u32::decode(decoder)?; + let dlo = u32::decode(decoder); + let dto = u32::decode(decoder); let enclosing = decoder.tcx.definitions_untracked().def_span(parent.unwrap()).data_untracked(); @@ -712,29 +701,29 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span { parent, ); - return Ok(span); + return span; } else { debug_assert_eq!(tag, TAG_FULL_SPAN); } - let file_lo_index = SourceFileIndex::decode(decoder)?; - let line_lo = usize::decode(decoder)?; - let col_lo = BytePos::decode(decoder)?; - let len = BytePos::decode(decoder)?; + let file_lo_index = SourceFileIndex::decode(decoder); + let line_lo = usize::decode(decoder); + let col_lo = BytePos::decode(decoder); + let len = BytePos::decode(decoder); let file_lo = decoder.file_index_to_file(file_lo_index); let lo = file_lo.lines[line_lo - 1] + col_lo; let hi = lo + len; - Ok(Span::new(lo, hi, ctxt, parent)) + Span::new(lo, hi, ctxt, parent) } } impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for CrateNum { - fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { - let stable_id = StableCrateId::decode(d)?; + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { + let stable_id = StableCrateId::decode(d); let cnum = d.tcx.stable_crate_id_to_crate_num(stable_id); - Ok(cnum) + cnum } } @@ -743,8 +732,8 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for CrateNum { // because we would not know how to transform the `DefIndex` to the current // context. impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefIndex { - fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<DefIndex, String> { - Err(d.error("trying to decode `DefIndex` outside the context of a `DefId`")) + fn decode(_d: &mut CacheDecoder<'a, 'tcx>) -> DefIndex { + panic!("trying to decode `DefIndex` outside the context of a `DefId`") } } @@ -752,23 +741,23 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefIndex { // compilation sessions. We use the `DefPathHash`, which is stable across // sessions, to map the old `DefId` to the new one. impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId { - fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { // Load the `DefPathHash` which is was we encoded the `DefId` as. - let def_path_hash = DefPathHash::decode(d)?; + let def_path_hash = DefPathHash::decode(d); // Using the `DefPathHash`, we can lookup the new `DefId`. // Subtle: We only encode a `DefId` as part of a query result. // If we get to this point, then all of the query inputs were green, // which means that the definition with this hash is guaranteed to // still exist in the current compilation session. - Ok(d.tcx().def_path_hash_to_def_id(def_path_hash, &mut || { + d.tcx().def_path_hash_to_def_id(def_path_hash, &mut || { panic!("Failed to convert DefPathHash {:?}", def_path_hash) - })) + }) } } impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashSet<LocalDefId> { - fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { RefDecodable::decode(d) } } @@ -776,31 +765,31 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashSet<LocalDefId> impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> { - fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { RefDecodable::decode(d) } } impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] { - fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { RefDecodable::decode(d) } } impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] { - fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { RefDecodable::decode(d) } } impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [rustc_ast::InlineAsmTemplatePiece] { - fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { RefDecodable::decode(d) } } impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [Span] { - fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { RefDecodable::decode(d) } } diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 47197a1e492..283eda7c85e 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -100,7 +100,7 @@ impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder< for SerializedDepGraph<K> { #[instrument(level = "debug", skip(d))] - fn decode(d: &mut opaque::Decoder<'a>) -> Result<SerializedDepGraph<K>, String> { + fn decode(d: &mut opaque::Decoder<'a>) -> SerializedDepGraph<K> { let start_position = d.position(); // The last 16 bytes are the node count and edge count. @@ -108,8 +108,8 @@ impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder< d.set_position(d.data.len() - 2 * IntEncodedWithFixedSize::ENCODED_SIZE); debug!("position: {:?}", d.position()); - let node_count = IntEncodedWithFixedSize::decode(d)?.0 as usize; - let edge_count = IntEncodedWithFixedSize::decode(d)?.0 as usize; + let node_count = IntEncodedWithFixedSize::decode(d).0 as usize; + let edge_count = IntEncodedWithFixedSize::decode(d).0 as usize; debug!(?node_count, ?edge_count); debug!("position: {:?}", d.position()); @@ -123,12 +123,12 @@ impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder< for _index in 0..node_count { d.read_struct(|d| { - let dep_node: DepNode<K> = d.read_struct_field("node", Decodable::decode)?; + let dep_node: DepNode<K> = d.read_struct_field("node", Decodable::decode); let _i: SerializedDepNodeIndex = nodes.push(dep_node); debug_assert_eq!(_i.index(), _index); let fingerprint: Fingerprint = - d.read_struct_field("fingerprint", Decodable::decode)?; + d.read_struct_field("fingerprint", Decodable::decode); let _i: SerializedDepNodeIndex = fingerprints.push(fingerprint); debug_assert_eq!(_i.index(), _index); @@ -136,22 +136,21 @@ impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder< d.read_seq(|d, len| { let start = edge_list_data.len().try_into().unwrap(); for _ in 0..len { - let edge = d.read_seq_elt(Decodable::decode)?; + let edge = d.read_seq_elt(Decodable::decode); edge_list_data.push(edge); } let end = edge_list_data.len().try_into().unwrap(); let _i: SerializedDepNodeIndex = edge_list_indices.push((start, end)); debug_assert_eq!(_i.index(), _index); - Ok(()) }) }) - })?; + }); } let index: FxHashMap<_, _> = nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect(); - Ok(SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index }) + SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index } } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 631b8fef668..e4d8b7d5283 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -108,7 +108,7 @@ impl<'a> Resolver<'a> { /// Reachable macros with block module parents exist due to `#[macro_export] macro_rules!`, /// but they cannot use def-site hygiene, so the assumption holds /// (<https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508>). - crate fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'a> { + pub fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'a> { loop { match self.get_module(def_id) { Some(module) => return module, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 7b4fe6f0e07..7e1e5c78805 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1171,9 +1171,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { ident: Symbol, kind: &AssocItemKind, ) -> Option<Symbol> { - let module = if let Some((module, _)) = self.current_trait_ref { - module - } else { + let Some((module, _)) = &self.current_trait_ref else { return None; }; if ident == kw::Underscore { diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index b077a5c9144..4c7bdb33fb8 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1000,46 +1000,45 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // `fn foo<'a>() -> MyAnonTy<'a> { ... }` // ^ ^this gets resolved in the current scope for lifetime in lifetimes { - if let hir::GenericArg::Lifetime(lifetime) = lifetime { - self.visit_lifetime(lifetime); + let hir::GenericArg::Lifetime(lifetime) = lifetime else { + continue + }; + self.visit_lifetime(lifetime); + + // Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>` + // and ban them. Type variables instantiated inside binders aren't + // well-supported at the moment, so this doesn't work. + // In the future, this should be fixed and this error should be removed. + let def = self.map.defs.get(&lifetime.hir_id).cloned(); + let Some(Region::LateBound(_, _, def_id, _)) = def else { + continue + }; + let Some(def_id) = def_id.as_local() else { + continue + }; + let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); + // Ensure that the parent of the def is an item, not HRTB + let parent_id = self.tcx.hir().get_parent_node(hir_id); + // FIXME(cjgillot) Can this check be replaced by + // `let parent_is_item = parent_id.is_owner();`? + let parent_is_item = if let Some(parent_def_id) = parent_id.as_owner() { + matches!(self.tcx.hir().krate().owners.get(parent_def_id), Some(Some(_)),) + } else { + false + }; - // Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>` - // and ban them. Type variables instantiated inside binders aren't - // well-supported at the moment, so this doesn't work. - // In the future, this should be fixed and this error should be removed. - let def = self.map.defs.get(&lifetime.hir_id).cloned(); - if let Some(Region::LateBound(_, _, def_id, _)) = def { - if let Some(def_id) = def_id.as_local() { - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); - // Ensure that the parent of the def is an item, not HRTB - let parent_id = self.tcx.hir().get_parent_node(hir_id); - // FIXME(cjgillot) Can this check be replaced by - // `let parent_is_item = parent_id.is_owner();`? - let parent_is_item = - if let Some(parent_def_id) = parent_id.as_owner() { - matches!( - self.tcx.hir().krate().owners.get(parent_def_id), - Some(Some(_)), - ) - } else { - false - }; - - if !parent_is_item { - if !self.trait_definition_only { - struct_span_err!( - self.tcx.sess, - lifetime.span, - E0657, - "`impl Trait` can only capture lifetimes \ - bound at the fn or impl level" - ) - .emit(); - } - self.uninsert_lifetime_on_error(lifetime, def.unwrap()); - } - } + if !parent_is_item { + if !self.trait_definition_only { + struct_span_err!( + self.tcx.sess, + lifetime.span, + E0657, + "`impl Trait` can only capture lifetimes \ + bound at the fn or impl level" + ) + .emit(); } + self.uninsert_lifetime_on_error(lifetime, def.unwrap()); } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index f5b2ba8fd72..45cc64ea194 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -53,7 +53,7 @@ use rustc_middle::metadata::ModChild; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::span_bug; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs}; +use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools, ResolverOutputs}; use rustc_query_system::ich::StableHashingContext; use rustc_session::cstore::{CrateStore, MetadataLoaderDyn}; use rustc_session::lint; @@ -614,7 +614,8 @@ impl<'a> ModuleData<'a> { } } - fn def_id(&self) -> DefId { + // Public for rustdoc. + pub fn def_id(&self) -> DefId { self.opt_def_id().expect("`ModuleData::def_id` is called on a block module") } @@ -989,7 +990,7 @@ pub struct Resolver<'a> { macro_names: FxHashSet<Ident>, builtin_macros: FxHashMap<Symbol, BuiltinMacroState>, registered_attrs: FxHashSet<Ident>, - registered_tools: FxHashSet<Ident>, + registered_tools: RegisteredTools, macro_use_prelude: FxHashMap<Symbol, &'a NameBinding<'a>>, all_macros: FxHashMap<Symbol, Res>, macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>, @@ -1487,6 +1488,7 @@ impl<'a> Resolver<'a> { trait_impls: self.trait_impls, proc_macros, confused_type_with_std_module, + registered_tools: self.registered_tools, } } @@ -1511,6 +1513,7 @@ impl<'a> Resolver<'a> { trait_impls: self.trait_impls.clone(), proc_macros, confused_type_with_std_module: self.confused_type_with_std_module.clone(), + registered_tools: self.registered_tools.clone(), } } @@ -3405,6 +3408,16 @@ impl<'a> Resolver<'a> { &self.all_macros } + /// For rustdoc. + /// For local modules returns only reexports, for external modules returns all children. + pub fn module_children_or_reexports(&self, def_id: DefId) -> Vec<ModChild> { + if let Some(def_id) = def_id.as_local() { + self.reexport_map.get(&def_id).cloned().unwrap_or_default() + } else { + self.cstore().module_children_untracked(def_id, self.session) + } + } + /// Retrieves the span of the given `DefId` if `DefId` is in the local crate. #[inline] pub fn opt_span(&self, def_id: DefId) -> Option<Span> { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 52685ec697c..82807e2d0a2 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -23,7 +23,7 @@ use rustc_hir::def::{self, DefKind, NonMacroAttrKind}; use rustc_hir::def_id::{CrateNum, LocalDefId}; use rustc_hir::PrimTy; use rustc_middle::middle::stability; -use rustc_middle::ty; +use rustc_middle::ty::{self, RegisteredTools}; use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK}; use rustc_session::lint::builtin::{SOFT_UNSTABLE, UNUSED_MACROS}; use rustc_session::lint::BuiltinLintDiagnostics; @@ -447,6 +447,10 @@ impl<'a> ResolverExpand for Resolver<'a> { fn declare_proc_macro(&mut self, id: NodeId) { self.proc_macros.push(id) } + + fn registered_tools(&self) -> &RegisteredTools { + &self.registered_tools + } } impl<'a> Resolver<'a> { diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index b95fe1b0549..570fa873a23 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -984,7 +984,7 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>( tcx.dep_graph.with_ignore(|| { info!("Dumping crate {}", cratename); - // Privacy checking requires and is done after type checking; use a + // Privacy checking must be done outside of type inference; use a // fallback in case the access levels couldn't have been correctly computed. let access_levels = match tcx.sess.compile_status() { Ok(..) => tcx.privacy_access_levels(()), diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml index 49778f82253..f6b9e17e58e 100644 --- a/compiler/rustc_serialize/Cargo.toml +++ b/compiler/rustc_serialize/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" edition = "2021" [dependencies] -indexmap = "1" +indexmap = "1.8.0" smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } [dev-dependencies] diff --git a/compiler/rustc_serialize/src/collection_impls.rs b/compiler/rustc_serialize/src/collection_impls.rs index 80a7f650188..02b28f7c626 100644 --- a/compiler/rustc_serialize/src/collection_impls.rs +++ b/compiler/rustc_serialize/src/collection_impls.rs @@ -17,15 +17,8 @@ impl<S: Encoder, A: Array<Item: Encodable<S>>> Encodable<S> for SmallVec<A> { } impl<D: Decoder, A: Array<Item: Decodable<D>>> Decodable<D> for SmallVec<A> { - fn decode(d: &mut D) -> Result<SmallVec<A>, D::Error> { - d.read_seq(|d, len| { - let mut vec = SmallVec::with_capacity(len); - // FIXME(#48994) - could just be collected into a Result<SmallVec, D::Error> - for _ in 0..len { - vec.push(d.read_seq_elt(|d| Decodable::decode(d))?); - } - Ok(vec) - }) + fn decode(d: &mut D) -> SmallVec<A> { + d.read_seq(|d, len| (0..len).map(|_| d.read_seq_elt(|d| Decodable::decode(d))).collect()) } } @@ -41,14 +34,8 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for LinkedList<T> { } impl<D: Decoder, T: Decodable<D>> Decodable<D> for LinkedList<T> { - fn decode(d: &mut D) -> Result<LinkedList<T>, D::Error> { - d.read_seq(|d, len| { - let mut list = LinkedList::new(); - for _ in 0..len { - list.push_back(d.read_seq_elt(|d| Decodable::decode(d))?); - } - Ok(list) - }) + fn decode(d: &mut D) -> LinkedList<T> { + d.read_seq(|d, len| (0..len).map(|_| d.read_seq_elt(|d| Decodable::decode(d))).collect()) } } @@ -64,14 +51,8 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for VecDeque<T> { } impl<D: Decoder, T: Decodable<D>> Decodable<D> for VecDeque<T> { - fn decode(d: &mut D) -> Result<VecDeque<T>, D::Error> { - d.read_seq(|d, len| { - let mut deque: VecDeque<T> = VecDeque::with_capacity(len); - for _ in 0..len { - deque.push_back(d.read_seq_elt(|d| Decodable::decode(d))?); - } - Ok(deque) - }) + fn decode(d: &mut D) -> VecDeque<T> { + d.read_seq(|d, len| (0..len).map(|_| d.read_seq_elt(|d| Decodable::decode(d))).collect()) } } @@ -96,15 +77,15 @@ where K: Decodable<D> + PartialEq + Ord, V: Decodable<D>, { - fn decode(d: &mut D) -> Result<BTreeMap<K, V>, D::Error> { + fn decode(d: &mut D) -> BTreeMap<K, V> { d.read_map(|d, len| { let mut map = BTreeMap::new(); for _ in 0..len { - let key = d.read_map_elt_key(|d| Decodable::decode(d))?; - let val = d.read_map_elt_val(|d| Decodable::decode(d))?; + let key = d.read_map_elt_key(|d| Decodable::decode(d)); + let val = d.read_map_elt_val(|d| Decodable::decode(d)); map.insert(key, val); } - Ok(map) + map }) } } @@ -127,13 +108,13 @@ impl<D: Decoder, T> Decodable<D> for BTreeSet<T> where T: Decodable<D> + PartialEq + Ord, { - fn decode(d: &mut D) -> Result<BTreeSet<T>, D::Error> { + fn decode(d: &mut D) -> BTreeSet<T> { d.read_seq(|d, len| { let mut set = BTreeSet::new(); for _ in 0..len { - set.insert(d.read_seq_elt(|d| Decodable::decode(d))?); + set.insert(d.read_seq_elt(|d| Decodable::decode(d))); } - Ok(set) + set }) } } @@ -161,16 +142,16 @@ where V: Decodable<D>, S: BuildHasher + Default, { - fn decode(d: &mut D) -> Result<HashMap<K, V, S>, D::Error> { + fn decode(d: &mut D) -> HashMap<K, V, S> { d.read_map(|d, len| { let state = Default::default(); let mut map = HashMap::with_capacity_and_hasher(len, state); for _ in 0..len { - let key = d.read_map_elt_key(|d| Decodable::decode(d))?; - let val = d.read_map_elt_val(|d| Decodable::decode(d))?; + let key = d.read_map_elt_key(|d| Decodable::decode(d)); + let val = d.read_map_elt_val(|d| Decodable::decode(d)); map.insert(key, val); } - Ok(map) + map }) } } @@ -205,14 +186,14 @@ where T: Decodable<D> + Hash + Eq, S: BuildHasher + Default, { - fn decode(d: &mut D) -> Result<HashSet<T, S>, D::Error> { + fn decode(d: &mut D) -> HashSet<T, S> { d.read_seq(|d, len| { let state = Default::default(); let mut set = HashSet::with_capacity_and_hasher(len, state); for _ in 0..len { - set.insert(d.read_seq_elt(|d| Decodable::decode(d))?); + set.insert(d.read_seq_elt(|d| Decodable::decode(d))); } - Ok(set) + set }) } } @@ -240,16 +221,16 @@ where V: Decodable<D>, S: BuildHasher + Default, { - fn decode(d: &mut D) -> Result<indexmap::IndexMap<K, V, S>, D::Error> { + fn decode(d: &mut D) -> indexmap::IndexMap<K, V, S> { d.read_map(|d, len| { let state = Default::default(); let mut map = indexmap::IndexMap::with_capacity_and_hasher(len, state); for _ in 0..len { - let key = d.read_map_elt_key(|d| Decodable::decode(d))?; - let val = d.read_map_elt_val(|d| Decodable::decode(d))?; + let key = d.read_map_elt_key(|d| Decodable::decode(d)); + let val = d.read_map_elt_val(|d| Decodable::decode(d)); map.insert(key, val); } - Ok(map) + map }) } } @@ -274,14 +255,14 @@ where T: Decodable<D> + Hash + Eq, S: BuildHasher + Default, { - fn decode(d: &mut D) -> Result<indexmap::IndexSet<T, S>, D::Error> { + fn decode(d: &mut D) -> indexmap::IndexSet<T, S> { d.read_seq(|d, len| { let state = Default::default(); let mut set = indexmap::IndexSet::with_capacity_and_hasher(len, state); for _ in 0..len { - set.insert(d.read_seq_elt(|d| Decodable::decode(d))?); + set.insert(d.read_seq_elt(|d| Decodable::decode(d))); } - Ok(set) + set }) } } @@ -294,9 +275,9 @@ impl<E: Encoder, T: Encodable<E>> Encodable<E> for Rc<[T]> { } impl<D: Decoder, T: Decodable<D>> Decodable<D> for Rc<[T]> { - fn decode(d: &mut D) -> Result<Rc<[T]>, D::Error> { - let vec: Vec<T> = Decodable::decode(d)?; - Ok(vec.into()) + fn decode(d: &mut D) -> Rc<[T]> { + let vec: Vec<T> = Decodable::decode(d); + vec.into() } } @@ -308,8 +289,8 @@ impl<E: Encoder, T: Encodable<E>> Encodable<E> for Arc<[T]> { } impl<D: Decoder, T: Decodable<D>> Decodable<D> for Arc<[T]> { - fn decode(d: &mut D) -> Result<Arc<[T]>, D::Error> { - let vec: Vec<T> = Decodable::decode(d)?; - Ok(vec.into()) + fn decode(d: &mut D) -> Arc<[T]> { + let vec: Vec<T> = Decodable::decode(d); + vec.into() } } diff --git a/compiler/rustc_serialize/src/json.rs b/compiler/rustc_serialize/src/json.rs index cb9df3c3389..044de8e4e24 100644 --- a/compiler/rustc_serialize/src/json.rs +++ b/compiler/rustc_serialize/src/json.rs @@ -89,7 +89,7 @@ //! let encoded = json::encode(&object).unwrap(); //! //! // Deserialize using `json::decode` -//! let decoded: TestStruct = json::decode(&encoded[..]).unwrap(); +//! let decoded: TestStruct = json::decode(&encoded[..]); //! ``` //! //! ## Using the `ToJson` trait @@ -173,7 +173,7 @@ //! let json_str: String = json_obj.to_string(); //! //! // Deserialize like before -//! let decoded: TestStruct = json::decode(&json_str).unwrap(); +//! let decoded: TestStruct = json::decode(&json_str); //! ``` use self::DecoderError::*; @@ -265,6 +265,12 @@ pub enum DecoderError { ApplicationError(string::String), } +macro_rules! bad { + ($e:expr) => {{ + panic!("json decode error: {:?}", $e); + }}; +} + #[derive(Copy, Clone, Debug)] pub enum EncoderError { FmtError(fmt::Error), @@ -295,10 +301,10 @@ pub fn error_str(error: ErrorCode) -> &'static str { } /// Shortcut function to decode a JSON `&str` into an object -pub fn decode<T: crate::Decodable<Decoder>>(s: &str) -> DecodeResult<T> { +pub fn decode<T: crate::Decodable<Decoder>>(s: &str) -> T { let json = match from_str(s) { Ok(x) => x, - Err(e) => return Err(ParseError(e)), + Err(e) => bad!(ParseError(e)), }; let mut decoder = Decoder::new(json); @@ -334,15 +340,6 @@ impl fmt::Display for ParserError { } } -impl fmt::Display for DecoderError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // FIXME this should be a nicer error - fmt::Debug::fmt(self, f) - } -} - -impl std::error::Error for DecoderError {} - impl fmt::Display for EncoderError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // FIXME this should be a nicer error @@ -2206,41 +2203,39 @@ impl Decoder { macro_rules! expect { ($e:expr, Null) => {{ match $e { - Json::Null => Ok(()), - other => Err(ExpectedError("Null".to_owned(), other.to_string())), + Json::Null => (), + other => bad!(ExpectedError("Null".to_owned(), other.to_string())), } }}; ($e:expr, $t:ident) => {{ match $e { - Json::$t(v) => Ok(v), - other => Err(ExpectedError(stringify!($t).to_owned(), other.to_string())), + Json::$t(v) => v, + other => bad!(ExpectedError(stringify!($t).to_owned(), other.to_string())), } }}; } macro_rules! read_primitive { ($name:ident, $ty:ty) => { - fn $name(&mut self) -> DecodeResult<$ty> { + fn $name(&mut self) -> $ty { match self.pop() { - Json::I64(f) => Ok(f as $ty), - Json::U64(f) => Ok(f as $ty), - Json::F64(f) => Err(ExpectedError("Integer".to_owned(), f.to_string())), + Json::I64(f) => f as $ty, + Json::U64(f) => f as $ty, + Json::F64(f) => bad!(ExpectedError("Integer".to_owned(), f.to_string())), // re: #12967.. a type w/ numeric keys (ie HashMap<usize, V> etc) // is going to have a string here, as per JSON spec. Json::String(s) => match s.parse().ok() { - Some(f) => Ok(f), - None => Err(ExpectedError("Number".to_owned(), s)), + Some(f) => f, + None => bad!(ExpectedError("Number".to_owned(), s)), }, - value => Err(ExpectedError("Number".to_owned(), value.to_string())), + value => bad!(ExpectedError("Number".to_owned(), value.to_string())), } } }; } impl crate::Decoder for Decoder { - type Error = DecoderError; - - fn read_nil(&mut self) -> DecodeResult<()> { + fn read_unit(&mut self) -> () { expect!(self.pop(), Null) } @@ -2257,156 +2252,150 @@ impl crate::Decoder for Decoder { read_primitive! { read_i64, i64 } read_primitive! { read_i128, i128 } - fn read_f32(&mut self) -> DecodeResult<f32> { - self.read_f64().map(|x| x as f32) + fn read_f32(&mut self) -> f32 { + self.read_f64() as f32 } - fn read_f64(&mut self) -> DecodeResult<f64> { + fn read_f64(&mut self) -> f64 { match self.pop() { - Json::I64(f) => Ok(f as f64), - Json::U64(f) => Ok(f as f64), - Json::F64(f) => Ok(f), + Json::I64(f) => f as f64, + Json::U64(f) => f as f64, + Json::F64(f) => f, Json::String(s) => { // re: #12967.. a type w/ numeric keys (ie HashMap<usize, V> etc) // is going to have a string here, as per JSON spec. match s.parse().ok() { - Some(f) => Ok(f), - None => Err(ExpectedError("Number".to_owned(), s)), + Some(f) => f, + None => bad!(ExpectedError("Number".to_owned(), s)), } } - Json::Null => Ok(f64::NAN), - value => Err(ExpectedError("Number".to_owned(), value.to_string())), + Json::Null => f64::NAN, + value => bad!(ExpectedError("Number".to_owned(), value.to_string())), } } - fn read_bool(&mut self) -> DecodeResult<bool> { + fn read_bool(&mut self) -> bool { expect!(self.pop(), Boolean) } - fn read_char(&mut self) -> DecodeResult<char> { - let s = self.read_str()?; - { - let mut it = s.chars(); - if let (Some(c), None) = (it.next(), it.next()) { - // exactly one character - return Ok(c); - } + fn read_char(&mut self) -> char { + let s = self.read_str(); + let mut it = s.chars(); + if let (Some(c), None) = (it.next(), it.next()) { + // exactly one character + return c; } - Err(ExpectedError("single character string".to_owned(), s.to_string())) + bad!(ExpectedError("single character string".to_owned(), s.to_string())); } - fn read_str(&mut self) -> DecodeResult<Cow<'_, str>> { - expect!(self.pop(), String).map(Cow::Owned) + fn read_str(&mut self) -> Cow<'_, str> { + Cow::Owned(expect!(self.pop(), String)) } - fn read_raw_bytes_into(&mut self, s: &mut [u8]) -> Result<(), Self::Error> { + fn read_raw_bytes_into(&mut self, s: &mut [u8]) { for c in s.iter_mut() { - *c = self.read_u8()?; + *c = self.read_u8(); } - Ok(()) } - fn read_enum<T, F>(&mut self, f: F) -> DecodeResult<T> + fn read_enum<T, F>(&mut self, f: F) -> T where - F: FnOnce(&mut Decoder) -> DecodeResult<T>, + F: FnOnce(&mut Decoder) -> T, { f(self) } - fn read_enum_variant<T, F>(&mut self, names: &[&str], mut f: F) -> DecodeResult<T> + fn read_enum_variant<T, F>(&mut self, names: &[&str], mut f: F) -> T where - F: FnMut(&mut Decoder, usize) -> DecodeResult<T>, + F: FnMut(&mut Decoder, usize) -> T, { let name = match self.pop() { Json::String(s) => s, Json::Object(mut o) => { let n = match o.remove("variant") { Some(Json::String(s)) => s, - Some(val) => return Err(ExpectedError("String".to_owned(), val.to_string())), - None => return Err(MissingFieldError("variant".to_owned())), + Some(val) => bad!(ExpectedError("String".to_owned(), val.to_string())), + None => bad!(MissingFieldError("variant".to_owned())), }; match o.remove("fields") { Some(Json::Array(l)) => { self.stack.extend(l.into_iter().rev()); } - Some(val) => return Err(ExpectedError("Array".to_owned(), val.to_string())), - None => return Err(MissingFieldError("fields".to_owned())), + Some(val) => bad!(ExpectedError("Array".to_owned(), val.to_string())), + None => bad!(MissingFieldError("fields".to_owned())), } n } - json => return Err(ExpectedError("String or Object".to_owned(), json.to_string())), + json => bad!(ExpectedError("String or Object".to_owned(), json.to_string())), }; let idx = match names.iter().position(|n| *n == &name[..]) { Some(idx) => idx, - None => return Err(UnknownVariantError(name)), + None => bad!(UnknownVariantError(name)), }; f(self, idx) } - fn read_enum_variant_arg<T, F>(&mut self, f: F) -> DecodeResult<T> + fn read_enum_variant_arg<T, F>(&mut self, f: F) -> T where - F: FnOnce(&mut Decoder) -> DecodeResult<T>, + F: FnOnce(&mut Decoder) -> T, { f(self) } - fn read_struct<T, F>(&mut self, f: F) -> DecodeResult<T> + fn read_struct<T, F>(&mut self, f: F) -> T where - F: FnOnce(&mut Decoder) -> DecodeResult<T>, + F: FnOnce(&mut Decoder) -> T, { - let value = f(self)?; + let value = f(self); self.pop(); - Ok(value) + value } - fn read_struct_field<T, F>(&mut self, name: &str, f: F) -> DecodeResult<T> + fn read_struct_field<T, F>(&mut self, name: &str, f: F) -> T where - F: FnOnce(&mut Decoder) -> DecodeResult<T>, + F: FnOnce(&mut Decoder) -> T, { - let mut obj = expect!(self.pop(), Object)?; + let mut obj = expect!(self.pop(), Object); let value = match obj.remove(name) { None => { // Add a Null and try to parse it as an Option<_> // to get None as a default value. self.stack.push(Json::Null); - match f(self) { - Ok(x) => x, - Err(_) => return Err(MissingFieldError(name.to_string())), - } + f(self) } Some(json) => { self.stack.push(json); - f(self)? + f(self) } }; self.stack.push(Json::Object(obj)); - Ok(value) + value } - fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F) -> DecodeResult<T> + fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F) -> T where - F: FnOnce(&mut Decoder) -> DecodeResult<T>, + F: FnOnce(&mut Decoder) -> T, { self.read_seq(move |d, len| { if len == tuple_len { f(d) } else { - Err(ExpectedError(format!("Tuple{}", tuple_len), format!("Tuple{}", len))) + bad!(ExpectedError(format!("Tuple{}", tuple_len), format!("Tuple{}", len))); } }) } - fn read_tuple_arg<T, F>(&mut self, f: F) -> DecodeResult<T> + fn read_tuple_arg<T, F>(&mut self, f: F) -> T where - F: FnOnce(&mut Decoder) -> DecodeResult<T>, + F: FnOnce(&mut Decoder) -> T, { self.read_seq_elt(f) } - fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T> + fn read_option<T, F>(&mut self, mut f: F) -> T where - F: FnMut(&mut Decoder, bool) -> DecodeResult<T>, + F: FnMut(&mut Decoder, bool) -> T, { match self.pop() { Json::Null => f(self, false), @@ -2417,28 +2406,28 @@ impl crate::Decoder for Decoder { } } - fn read_seq<T, F>(&mut self, f: F) -> DecodeResult<T> + fn read_seq<T, F>(&mut self, f: F) -> T where - F: FnOnce(&mut Decoder, usize) -> DecodeResult<T>, + F: FnOnce(&mut Decoder, usize) -> T, { - let array = expect!(self.pop(), Array)?; + let array = expect!(self.pop(), Array); let len = array.len(); self.stack.extend(array.into_iter().rev()); f(self, len) } - fn read_seq_elt<T, F>(&mut self, f: F) -> DecodeResult<T> + fn read_seq_elt<T, F>(&mut self, f: F) -> T where - F: FnOnce(&mut Decoder) -> DecodeResult<T>, + F: FnOnce(&mut Decoder) -> T, { f(self) } - fn read_map<T, F>(&mut self, f: F) -> DecodeResult<T> + fn read_map<T, F>(&mut self, f: F) -> T where - F: FnOnce(&mut Decoder, usize) -> DecodeResult<T>, + F: FnOnce(&mut Decoder, usize) -> T, { - let obj = expect!(self.pop(), Object)?; + let obj = expect!(self.pop(), Object); let len = obj.len(); for (key, value) in obj { self.stack.push(value); @@ -2447,23 +2436,19 @@ impl crate::Decoder for Decoder { f(self, len) } - fn read_map_elt_key<T, F>(&mut self, f: F) -> DecodeResult<T> + fn read_map_elt_key<T, F>(&mut self, f: F) -> T where - F: FnOnce(&mut Decoder) -> DecodeResult<T>, + F: FnOnce(&mut Decoder) -> T, { f(self) } - fn read_map_elt_val<T, F>(&mut self, f: F) -> DecodeResult<T> + fn read_map_elt_val<T, F>(&mut self, f: F) -> T where - F: FnOnce(&mut Decoder) -> DecodeResult<T>, + F: FnOnce(&mut Decoder) -> T, { f(self) } - - fn error(&mut self, err: &str) -> DecoderError { - ApplicationError(err.to_string()) - } } /// A trait for converting values to JSON diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 078237801be..c272c687a7e 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -560,134 +560,126 @@ impl<'a> Decoder<'a> { } macro_rules! read_leb128 { - ($dec:expr, $fun:ident) => {{ Ok(leb128::$fun($dec.data, &mut $dec.position)) }}; + ($dec:expr, $fun:ident) => {{ leb128::$fun($dec.data, &mut $dec.position) }}; } impl<'a> serialize::Decoder for Decoder<'a> { - type Error = String; - #[inline] - fn read_nil(&mut self) -> Result<(), Self::Error> { - Ok(()) + fn read_unit(&mut self) -> () { + () } #[inline] - fn read_u128(&mut self) -> Result<u128, Self::Error> { + fn read_u128(&mut self) -> u128 { read_leb128!(self, read_u128_leb128) } #[inline] - fn read_u64(&mut self) -> Result<u64, Self::Error> { + fn read_u64(&mut self) -> u64 { read_leb128!(self, read_u64_leb128) } #[inline] - fn read_u32(&mut self) -> Result<u32, Self::Error> { + fn read_u32(&mut self) -> u32 { read_leb128!(self, read_u32_leb128) } #[inline] - fn read_u16(&mut self) -> Result<u16, Self::Error> { + fn read_u16(&mut self) -> u16 { let bytes = [self.data[self.position], self.data[self.position + 1]]; let value = u16::from_le_bytes(bytes); self.position += 2; - Ok(value) + value } #[inline] - fn read_u8(&mut self) -> Result<u8, Self::Error> { + fn read_u8(&mut self) -> u8 { let value = self.data[self.position]; self.position += 1; - Ok(value) + value } #[inline] - fn read_usize(&mut self) -> Result<usize, Self::Error> { + fn read_usize(&mut self) -> usize { read_leb128!(self, read_usize_leb128) } #[inline] - fn read_i128(&mut self) -> Result<i128, Self::Error> { + fn read_i128(&mut self) -> i128 { read_leb128!(self, read_i128_leb128) } #[inline] - fn read_i64(&mut self) -> Result<i64, Self::Error> { + fn read_i64(&mut self) -> i64 { read_leb128!(self, read_i64_leb128) } #[inline] - fn read_i32(&mut self) -> Result<i32, Self::Error> { + fn read_i32(&mut self) -> i32 { read_leb128!(self, read_i32_leb128) } #[inline] - fn read_i16(&mut self) -> Result<i16, Self::Error> { + fn read_i16(&mut self) -> i16 { let bytes = [self.data[self.position], self.data[self.position + 1]]; let value = i16::from_le_bytes(bytes); self.position += 2; - Ok(value) + value } #[inline] - fn read_i8(&mut self) -> Result<i8, Self::Error> { + fn read_i8(&mut self) -> i8 { let as_u8 = self.data[self.position]; self.position += 1; - unsafe { Ok(::std::mem::transmute(as_u8)) } + unsafe { ::std::mem::transmute(as_u8) } } #[inline] - fn read_isize(&mut self) -> Result<isize, Self::Error> { + fn read_isize(&mut self) -> isize { read_leb128!(self, read_isize_leb128) } #[inline] - fn read_bool(&mut self) -> Result<bool, Self::Error> { - let value = self.read_u8()?; - Ok(value != 0) + fn read_bool(&mut self) -> bool { + let value = self.read_u8(); + value != 0 } #[inline] - fn read_f64(&mut self) -> Result<f64, Self::Error> { - let bits = self.read_u64()?; - Ok(f64::from_bits(bits)) + fn read_f64(&mut self) -> f64 { + let bits = self.read_u64(); + f64::from_bits(bits) } #[inline] - fn read_f32(&mut self) -> Result<f32, Self::Error> { - let bits = self.read_u32()?; - Ok(f32::from_bits(bits)) + fn read_f32(&mut self) -> f32 { + let bits = self.read_u32(); + f32::from_bits(bits) } #[inline] - fn read_char(&mut self) -> Result<char, Self::Error> { - let bits = self.read_u32()?; - Ok(std::char::from_u32(bits).unwrap()) + fn read_char(&mut self) -> char { + let bits = self.read_u32(); + std::char::from_u32(bits).unwrap() } #[inline] - fn read_str(&mut self) -> Result<Cow<'_, str>, Self::Error> { - let len = self.read_usize()?; + fn read_str(&mut self) -> Cow<'_, str> { + let len = self.read_usize(); let sentinel = self.data[self.position + len]; assert!(sentinel == STR_SENTINEL); let s = unsafe { std::str::from_utf8_unchecked(&self.data[self.position..self.position + len]) }; self.position += len + 1; - Ok(Cow::Borrowed(s)) - } - - #[inline] - fn error(&mut self, err: &str) -> Self::Error { - err.to_string() + Cow::Borrowed(s) } #[inline] - fn read_raw_bytes_into(&mut self, s: &mut [u8]) -> Result<(), String> { + fn read_raw_bytes_into(&mut self, s: &mut [u8]) { let start = self.position; self.position += s.len(); s.copy_from_slice(&self.data[start..self.position]); - Ok(()) } } @@ -715,9 +707,9 @@ impl serialize::Encodable<FileEncoder> for [u8] { // Specialize decoding `Vec<u8>`. This specialization also applies to decoding `Box<[u8]>`s, etc., // since the default implementations call `decode` to produce a `Vec<u8>` internally. impl<'a> serialize::Decodable<Decoder<'a>> for Vec<u8> { - fn decode(d: &mut Decoder<'a>) -> Result<Self, String> { - let len = serialize::Decoder::read_usize(d)?; - Ok(d.read_raw_bytes(len).to_owned()) + fn decode(d: &mut Decoder<'a>) -> Self { + let len = serialize::Decoder::read_usize(d); + d.read_raw_bytes(len).to_owned() } } @@ -752,13 +744,13 @@ impl serialize::Encodable<FileEncoder> for IntEncodedWithFixedSize { impl<'a> serialize::Decodable<Decoder<'a>> for IntEncodedWithFixedSize { #[inline] - fn decode(decoder: &mut Decoder<'a>) -> Result<IntEncodedWithFixedSize, String> { + fn decode(decoder: &mut Decoder<'a>) -> IntEncodedWithFixedSize { let _start_pos = decoder.position(); let bytes = decoder.read_raw_bytes(IntEncodedWithFixedSize::ENCODED_SIZE); let _end_pos = decoder.position(); debug_assert_eq!((_end_pos - _start_pos), IntEncodedWithFixedSize::ENCODED_SIZE); let value = u64::from_le_bytes(bytes.try_into().unwrap()); - Ok(IntEncodedWithFixedSize(value)) + IntEncodedWithFixedSize(value) } } diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index 96a2231b590..a6172403fd6 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -173,144 +173,145 @@ pub trait Encoder { } } +// Note: all the methods in this trait are infallible, which may be surprising. +// They used to be fallible (i.e. return a `Result`) but many of the impls just +// panicked when something went wrong, and for the cases that didn't the +// top-level invocation would also just panic on failure. Switching to +// infallibility made things faster and lots of code a little simpler and more +// concise. pub trait Decoder { - type Error; - // Primitive types: - fn read_nil(&mut self) -> Result<(), Self::Error>; - fn read_usize(&mut self) -> Result<usize, Self::Error>; - fn read_u128(&mut self) -> Result<u128, Self::Error>; - fn read_u64(&mut self) -> Result<u64, Self::Error>; - fn read_u32(&mut self) -> Result<u32, Self::Error>; - fn read_u16(&mut self) -> Result<u16, Self::Error>; - fn read_u8(&mut self) -> Result<u8, Self::Error>; - fn read_isize(&mut self) -> Result<isize, Self::Error>; - fn read_i128(&mut self) -> Result<i128, Self::Error>; - fn read_i64(&mut self) -> Result<i64, Self::Error>; - fn read_i32(&mut self) -> Result<i32, Self::Error>; - fn read_i16(&mut self) -> Result<i16, Self::Error>; - fn read_i8(&mut self) -> Result<i8, Self::Error>; - fn read_bool(&mut self) -> Result<bool, Self::Error>; - fn read_f64(&mut self) -> Result<f64, Self::Error>; - fn read_f32(&mut self) -> Result<f32, Self::Error>; - fn read_char(&mut self) -> Result<char, Self::Error>; - fn read_str(&mut self) -> Result<Cow<'_, str>, Self::Error>; - fn read_raw_bytes_into(&mut self, s: &mut [u8]) -> Result<(), Self::Error>; + fn read_unit(&mut self) -> (); + fn read_usize(&mut self) -> usize; + fn read_u128(&mut self) -> u128; + fn read_u64(&mut self) -> u64; + fn read_u32(&mut self) -> u32; + fn read_u16(&mut self) -> u16; + fn read_u8(&mut self) -> u8; + fn read_isize(&mut self) -> isize; + fn read_i128(&mut self) -> i128; + fn read_i64(&mut self) -> i64; + fn read_i32(&mut self) -> i32; + fn read_i16(&mut self) -> i16; + fn read_i8(&mut self) -> i8; + fn read_bool(&mut self) -> bool; + fn read_f64(&mut self) -> f64; + fn read_f32(&mut self) -> f32; + fn read_char(&mut self) -> char; + fn read_str(&mut self) -> Cow<'_, str>; + fn read_raw_bytes_into(&mut self, s: &mut [u8]); // Compound types: #[inline] - fn read_enum<T, F>(&mut self, f: F) -> Result<T, Self::Error> + fn read_enum<T, F>(&mut self, f: F) -> T where - F: FnOnce(&mut Self) -> Result<T, Self::Error>, + F: FnOnce(&mut Self) -> T, { f(self) } #[inline] - fn read_enum_variant<T, F>(&mut self, _names: &[&str], mut f: F) -> Result<T, Self::Error> + fn read_enum_variant<T, F>(&mut self, _names: &[&str], mut f: F) -> T where - F: FnMut(&mut Self, usize) -> Result<T, Self::Error>, + F: FnMut(&mut Self, usize) -> T, { - let disr = self.read_usize()?; + let disr = self.read_usize(); f(self, disr) } #[inline] - fn read_enum_variant_arg<T, F>(&mut self, f: F) -> Result<T, Self::Error> + fn read_enum_variant_arg<T, F>(&mut self, f: F) -> T where - F: FnOnce(&mut Self) -> Result<T, Self::Error>, + F: FnOnce(&mut Self) -> T, { f(self) } #[inline] - fn read_struct<T, F>(&mut self, f: F) -> Result<T, Self::Error> + fn read_struct<T, F>(&mut self, f: F) -> T where - F: FnOnce(&mut Self) -> Result<T, Self::Error>, + F: FnOnce(&mut Self) -> T, { f(self) } #[inline] - fn read_struct_field<T, F>(&mut self, _f_name: &str, f: F) -> Result<T, Self::Error> + fn read_struct_field<T, F>(&mut self, _f_name: &str, f: F) -> T where - F: FnOnce(&mut Self) -> Result<T, Self::Error>, + F: FnOnce(&mut Self) -> T, { f(self) } #[inline] - fn read_tuple<T, F>(&mut self, _len: usize, f: F) -> Result<T, Self::Error> + fn read_tuple<T, F>(&mut self, _len: usize, f: F) -> T where - F: FnOnce(&mut Self) -> Result<T, Self::Error>, + F: FnOnce(&mut Self) -> T, { f(self) } #[inline] - fn read_tuple_arg<T, F>(&mut self, f: F) -> Result<T, Self::Error> + fn read_tuple_arg<T, F>(&mut self, f: F) -> T where - F: FnOnce(&mut Self) -> Result<T, Self::Error>, + F: FnOnce(&mut Self) -> T, { f(self) } // Specialized types: - fn read_option<T, F>(&mut self, mut f: F) -> Result<T, Self::Error> + fn read_option<T, F>(&mut self, mut f: F) -> T where - F: FnMut(&mut Self, bool) -> Result<T, Self::Error>, + F: FnMut(&mut Self, bool) -> T, { self.read_enum(move |this| { this.read_enum_variant(&["None", "Some"], move |this, idx| match idx { 0 => f(this, false), 1 => f(this, true), - _ => Err(this.error("read_option: expected 0 for None or 1 for Some")), + _ => panic!("read_option: expected 0 for None or 1 for Some"), }) }) } - fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error> + fn read_seq<T, F>(&mut self, f: F) -> T where - F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>, + F: FnOnce(&mut Self, usize) -> T, { - let len = self.read_usize()?; + let len = self.read_usize(); f(self, len) } #[inline] - fn read_seq_elt<T, F>(&mut self, f: F) -> Result<T, Self::Error> + fn read_seq_elt<T, F>(&mut self, f: F) -> T where - F: FnOnce(&mut Self) -> Result<T, Self::Error>, + F: FnOnce(&mut Self) -> T, { f(self) } - fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error> + fn read_map<T, F>(&mut self, f: F) -> T where - F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>, + F: FnOnce(&mut Self, usize) -> T, { - let len = self.read_usize()?; + let len = self.read_usize(); f(self, len) } #[inline] - fn read_map_elt_key<T, F>(&mut self, f: F) -> Result<T, Self::Error> + fn read_map_elt_key<T, F>(&mut self, f: F) -> T where - F: FnOnce(&mut Self) -> Result<T, Self::Error>, + F: FnOnce(&mut Self) -> T, { f(self) } #[inline] - fn read_map_elt_val<T, F>(&mut self, f: F) -> Result<T, Self::Error> + fn read_map_elt_val<T, F>(&mut self, f: F) -> T where - F: FnOnce(&mut Self) -> Result<T, Self::Error>, + F: FnOnce(&mut Self) -> T, { f(self) } - - // Failure - fn error(&mut self, err: &str) -> Self::Error; } /// Trait for types that can be serialized @@ -340,7 +341,7 @@ pub trait Encodable<S: Encoder> { /// * `TyDecodable` should be used for types that are only serialized in crate /// metadata or the incremental cache. This is most types in `rustc_middle`. pub trait Decodable<D: Decoder>: Sized { - fn decode(d: &mut D) -> Result<Self, D::Error>; + fn decode(d: &mut D) -> Self; } macro_rules! direct_serialize_impls { @@ -353,7 +354,7 @@ macro_rules! direct_serialize_impls { } impl<D: Decoder> Decodable<D> for $ty { - fn decode(d: &mut D) -> Result<$ty, D::Error> { + fn decode(d: &mut D) -> $ty { d.$read_method() } } @@ -387,7 +388,7 @@ impl<S: Encoder> Encodable<S> for ! { } impl<D: Decoder> Decodable<D> for ! { - fn decode(_d: &mut D) -> Result<!, D::Error> { + fn decode(_d: &mut D) -> ! { unreachable!() } } @@ -399,8 +400,8 @@ impl<S: Encoder> Encodable<S> for ::std::num::NonZeroU32 { } impl<D: Decoder> Decodable<D> for ::std::num::NonZeroU32 { - fn decode(d: &mut D) -> Result<Self, D::Error> { - d.read_u32().map(|d| ::std::num::NonZeroU32::new(d).unwrap()) + fn decode(d: &mut D) -> Self { + ::std::num::NonZeroU32::new(d.read_u32()).unwrap() } } @@ -423,8 +424,8 @@ impl<S: Encoder> Encodable<S> for String { } impl<D: Decoder> Decodable<D> for String { - fn decode(d: &mut D) -> Result<String, D::Error> { - Ok(d.read_str()?.into_owned()) + fn decode(d: &mut D) -> String { + d.read_str().into_owned() } } @@ -435,8 +436,8 @@ impl<S: Encoder> Encodable<S> for () { } impl<D: Decoder> Decodable<D> for () { - fn decode(d: &mut D) -> Result<(), D::Error> { - d.read_nil() + fn decode(d: &mut D) -> () { + d.read_unit() } } @@ -447,16 +448,16 @@ impl<S: Encoder, T> Encodable<S> for PhantomData<T> { } impl<D: Decoder, T> Decodable<D> for PhantomData<T> { - fn decode(d: &mut D) -> Result<PhantomData<T>, D::Error> { - d.read_nil()?; - Ok(PhantomData) + fn decode(d: &mut D) -> PhantomData<T> { + d.read_unit(); + PhantomData } } impl<D: Decoder, T: Decodable<D>> Decodable<D> for Box<[T]> { - fn decode(d: &mut D) -> Result<Box<[T]>, D::Error> { - let v: Vec<T> = Decodable::decode(d)?; - Ok(v.into_boxed_slice()) + fn decode(d: &mut D) -> Box<[T]> { + let v: Vec<T> = Decodable::decode(d); + v.into_boxed_slice() } } @@ -467,8 +468,8 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for Rc<T> { } impl<D: Decoder, T: Decodable<D>> Decodable<D> for Rc<T> { - fn decode(d: &mut D) -> Result<Rc<T>, D::Error> { - Ok(Rc::new(Decodable::decode(d)?)) + fn decode(d: &mut D) -> Rc<T> { + Rc::new(Decodable::decode(d)) } } @@ -491,13 +492,22 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for Vec<T> { } impl<D: Decoder, T: Decodable<D>> Decodable<D> for Vec<T> { - default fn decode(d: &mut D) -> Result<Vec<T>, D::Error> { + default fn decode(d: &mut D) -> Vec<T> { d.read_seq(|d, len| { - let mut v = Vec::with_capacity(len); - for _ in 0..len { - v.push(d.read_seq_elt(|d| Decodable::decode(d))?); + // SAFETY: we set the capacity in advance, only write elements, and + // only set the length at the end once the writing has succeeded. + let mut vec = Vec::with_capacity(len); + unsafe { + let ptr: *mut T = vec.as_mut_ptr(); + for i in 0..len { + std::ptr::write( + ptr.offset(i as isize), + d.read_seq_elt(|d| Decodable::decode(d)), + ); + } + vec.set_len(len); } - Ok(v) + vec }) } } @@ -510,14 +520,14 @@ impl<S: Encoder, T: Encodable<S>, const N: usize> Encodable<S> for [T; N] { } impl<D: Decoder, const N: usize> Decodable<D> for [u8; N] { - fn decode(d: &mut D) -> Result<[u8; N], D::Error> { + fn decode(d: &mut D) -> [u8; N] { d.read_seq(|d, len| { assert!(len == N); let mut v = [0u8; N]; for i in 0..len { - v[i] = d.read_seq_elt(|d| Decodable::decode(d))?; + v[i] = d.read_seq_elt(|d| Decodable::decode(d)); } - Ok(v) + v }) } } @@ -536,9 +546,9 @@ impl<D: Decoder, T: Decodable<D> + ToOwned> Decodable<D> for Cow<'static, [T]> where [T]: ToOwned<Owned = Vec<T>>, { - fn decode(d: &mut D) -> Result<Cow<'static, [T]>, D::Error> { - let v: Vec<T> = Decodable::decode(d)?; - Ok(Cow::Owned(v)) + fn decode(d: &mut D) -> Cow<'static, [T]> { + let v: Vec<T> = Decodable::decode(d); + Cow::Owned(v) } } @@ -552,8 +562,8 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for Option<T> { } impl<D: Decoder, T: Decodable<D>> Decodable<D> for Option<T> { - fn decode(d: &mut D) -> Result<Option<T>, D::Error> { - d.read_option(|d, b| if b { Ok(Some(Decodable::decode(d)?)) } else { Ok(None) }) + fn decode(d: &mut D) -> Option<T> { + d.read_option(|d, b| if b { Some(Decodable::decode(d)) } else { None }) } } @@ -571,17 +581,12 @@ impl<S: Encoder, T1: Encodable<S>, T2: Encodable<S>> Encodable<S> for Result<T1, } impl<D: Decoder, T1: Decodable<D>, T2: Decodable<D>> Decodable<D> for Result<T1, T2> { - fn decode(d: &mut D) -> Result<Result<T1, T2>, D::Error> { + fn decode(d: &mut D) -> Result<T1, T2> { d.read_enum(|d| { d.read_enum_variant(&["Ok", "Err"], |d, disr| match disr { - 0 => Ok(Ok(d.read_enum_variant_arg(|d| T1::decode(d))?)), - 1 => Ok(Err(d.read_enum_variant_arg(|d| T2::decode(d))?)), - _ => { - panic!( - "Encountered invalid discriminant while \ - decoding `Result`." - ); - } + 0 => Ok(d.read_enum_variant_arg(|d| T1::decode(d))), + 1 => Err(d.read_enum_variant_arg(|d| T2::decode(d))), + _ => panic!("Encountered invalid discriminant while decoding `Result`."), }) }) } @@ -609,13 +614,13 @@ macro_rules! tuple { ( $($name:ident,)+ ) => ( impl<D: Decoder, $($name: Decodable<D>),+> Decodable<D> for ($($name,)+) { #[allow(non_snake_case)] - fn decode(d: &mut D) -> Result<($($name,)+), D::Error> { + fn decode(d: &mut D) -> ($($name,)+) { let len: usize = count!($($name)+); d.read_tuple(len, |d| { - let ret = ($(d.read_tuple_arg(|d| -> Result<$name, D::Error> { + let ret = ($(d.read_tuple_arg(|d| -> $name { Decodable::decode(d) - })?,)+); - Ok(ret) + }),)+); + ret }) } } @@ -651,9 +656,9 @@ impl<S: Encoder> Encodable<S> for path::PathBuf { } impl<D: Decoder> Decodable<D> for path::PathBuf { - fn decode(d: &mut D) -> Result<path::PathBuf, D::Error> { - let bytes: String = Decodable::decode(d)?; - Ok(path::PathBuf::from(bytes)) + fn decode(d: &mut D) -> path::PathBuf { + let bytes: String = Decodable::decode(d); + path::PathBuf::from(bytes) } } @@ -664,8 +669,8 @@ impl<S: Encoder, T: Encodable<S> + Copy> Encodable<S> for Cell<T> { } impl<D: Decoder, T: Decodable<D> + Copy> Decodable<D> for Cell<T> { - fn decode(d: &mut D) -> Result<Cell<T>, D::Error> { - Ok(Cell::new(Decodable::decode(d)?)) + fn decode(d: &mut D) -> Cell<T> { + Cell::new(Decodable::decode(d)) } } @@ -681,8 +686,8 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for RefCell<T> { } impl<D: Decoder, T: Decodable<D>> Decodable<D> for RefCell<T> { - fn decode(d: &mut D) -> Result<RefCell<T>, D::Error> { - Ok(RefCell::new(Decodable::decode(d)?)) + fn decode(d: &mut D) -> RefCell<T> { + RefCell::new(Decodable::decode(d)) } } @@ -693,8 +698,8 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for Arc<T> { } impl<D: Decoder, T: Decodable<D>> Decodable<D> for Arc<T> { - fn decode(d: &mut D) -> Result<Arc<T>, D::Error> { - Ok(Arc::new(Decodable::decode(d)?)) + fn decode(d: &mut D) -> Arc<T> { + Arc::new(Decodable::decode(d)) } } @@ -704,7 +709,7 @@ impl<S: Encoder, T: ?Sized + Encodable<S>> Encodable<S> for Box<T> { } } impl<D: Decoder, T: Decodable<D>> Decodable<D> for Box<T> { - fn decode(d: &mut D) -> Result<Box<T>, D::Error> { - Ok(Box::new(Decodable::decode(d)?)) + fn decode(d: &mut D) -> Box<T> { + Box::new(Decodable::decode(d)) } } diff --git a/compiler/rustc_serialize/tests/json.rs b/compiler/rustc_serialize/tests/json.rs index a759fa1bf1a..ede912bdfb6 100644 --- a/compiler/rustc_serialize/tests/json.rs +++ b/compiler/rustc_serialize/tests/json.rs @@ -1,14 +1,10 @@ #![allow(rustc::internal)] -use json::DecoderError::*; use json::ErrorCode::*; use json::Json::*; use json::JsonEvent::*; use json::ParserError::*; -use json::{ - from_str, DecodeResult, Decoder, DecoderError, Encoder, EncoderError, Json, JsonEvent, Parser, - StackElement, -}; +use json::{from_str, Decoder, Encoder, EncoderError, Json, JsonEvent, Parser, StackElement}; use rustc_macros::{Decodable, Encodable}; use rustc_serialize::json; use rustc_serialize::{Decodable, Encodable}; @@ -26,27 +22,27 @@ struct OptionData { #[test] fn test_decode_option_none() { let s = "{}"; - let obj: OptionData = json::decode(s).unwrap(); + let obj: OptionData = json::decode(s); assert_eq!(obj, OptionData { opt: None }); } #[test] fn test_decode_option_some() { let s = "{ \"opt\": 10 }"; - let obj: OptionData = json::decode(s).unwrap(); + let obj: OptionData = json::decode(s); assert_eq!(obj, OptionData { opt: Some(10) }); } #[test] -fn test_decode_option_malformed() { - check_err::<OptionData>( - "{ \"opt\": [] }", - ExpectedError("Number".to_string(), "[]".to_string()), - ); - check_err::<OptionData>( - "{ \"opt\": false }", - ExpectedError("Number".to_string(), "false".to_string()), - ); +#[should_panic(expected = r#"ExpectedError("Number", "[]")"#)] +fn test_decode_option_malformed1() { + check_err::<OptionData>(r#"{ "opt": [] }"#); +} + +#[test] +#[should_panic(expected = r#"ExpectedError("Number", "false")"#)] +fn test_decode_option_malformed2() { + check_err::<OptionData>(r#"{ "opt": false }"#); } #[derive(PartialEq, Encodable, Decodable, Debug)] @@ -329,13 +325,13 @@ fn test_read_identifiers() { #[test] fn test_decode_identifiers() { - let v: () = json::decode("null").unwrap(); + let v: () = json::decode("null"); assert_eq!(v, ()); - let v: bool = json::decode("true").unwrap(); + let v: bool = json::decode("true"); assert_eq!(v, true); - let v: bool = json::decode("false").unwrap(); + let v: bool = json::decode("false"); assert_eq!(v, false); } @@ -368,42 +364,42 @@ fn test_read_number() { } #[test] +#[should_panic(expected = r#"ExpectedError("Integer", "765.25")"#)] fn test_decode_numbers() { - let v: f64 = json::decode("3").unwrap(); + let v: f64 = json::decode("3"); assert_eq!(v, 3.0); - let v: f64 = json::decode("3.1").unwrap(); + let v: f64 = json::decode("3.1"); assert_eq!(v, 3.1); - let v: f64 = json::decode("-1.2").unwrap(); + let v: f64 = json::decode("-1.2"); assert_eq!(v, -1.2); - let v: f64 = json::decode("0.4").unwrap(); + let v: f64 = json::decode("0.4"); assert_eq!(v, 0.4); - let v: f64 = json::decode("0.4e5").unwrap(); + let v: f64 = json::decode("0.4e5"); assert_eq!(v, 0.4e5); - let v: f64 = json::decode("0.4e15").unwrap(); + let v: f64 = json::decode("0.4e15"); assert_eq!(v, 0.4e15); - let v: f64 = json::decode("0.4e-01").unwrap(); + let v: f64 = json::decode("0.4e-01"); assert_eq!(v, 0.4e-01); - let v: u64 = json::decode("0").unwrap(); + let v: u64 = json::decode("0"); assert_eq!(v, 0); - let v: u64 = json::decode("18446744073709551615").unwrap(); + let v: u64 = json::decode("18446744073709551615"); assert_eq!(v, u64::MAX); - let v: i64 = json::decode("-9223372036854775808").unwrap(); + let v: i64 = json::decode("-9223372036854775808"); assert_eq!(v, i64::MIN); - let v: i64 = json::decode("9223372036854775807").unwrap(); + let v: i64 = json::decode("9223372036854775807"); assert_eq!(v, i64::MAX); - let res: DecodeResult<i64> = json::decode("765.25"); - assert_eq!(res, Err(ExpectedError("Integer".to_string(), "765.25".to_string()))); + json::decode::<i64>("765.25"); } #[test] @@ -438,7 +434,7 @@ fn test_decode_str() { ]; for (i, o) in s { - let v: string::String = json::decode(i).unwrap(); + let v: string::String = json::decode(i); assert_eq!(v, o); } } @@ -463,39 +459,41 @@ fn test_read_array() { #[test] fn test_decode_array() { - let v: Vec<()> = json::decode("[]").unwrap(); + let v: Vec<()> = json::decode("[]"); assert_eq!(v, []); - let v: Vec<()> = json::decode("[null]").unwrap(); + let v: Vec<()> = json::decode("[null]"); assert_eq!(v, [()]); - let v: Vec<bool> = json::decode("[true]").unwrap(); + let v: Vec<bool> = json::decode("[true]"); assert_eq!(v, [true]); - let v: Vec<isize> = json::decode("[3, 1]").unwrap(); + let v: Vec<isize> = json::decode("[3, 1]"); assert_eq!(v, [3, 1]); - let v: Vec<Vec<usize>> = json::decode("[[3], [1, 2]]").unwrap(); + let v: Vec<Vec<usize>> = json::decode("[[3], [1, 2]]"); assert_eq!(v, [vec![3], vec![1, 2]]); } #[test] fn test_decode_tuple() { - let t: (usize, usize, usize) = json::decode("[1, 2, 3]").unwrap(); + let t: (usize, usize, usize) = json::decode("[1, 2, 3]"); assert_eq!(t, (1, 2, 3)); - let t: (usize, string::String) = json::decode("[1, \"two\"]").unwrap(); + let t: (usize, string::String) = json::decode("[1, \"two\"]"); assert_eq!(t, (1, "two".to_string())); } #[test] +#[should_panic] fn test_decode_tuple_malformed_types() { - assert!(json::decode::<(usize, string::String)>("[1, 2]").is_err()); + json::decode::<(usize, string::String)>("[1, 2]"); } #[test] +#[should_panic] fn test_decode_tuple_malformed_length() { - assert!(json::decode::<(usize, usize)>("[1, 2, 3]").is_err()); + json::decode::<(usize, usize)>("[1, 2, 3]"); } #[test] @@ -562,7 +560,7 @@ fn test_decode_struct() { ] }"; - let v: Outer = json::decode(s).unwrap(); + let v: Outer = json::decode(s); assert_eq!( v, Outer { inner: vec![Inner { a: (), b: 2, c: vec!["abc".to_string(), "xyz".to_string()] }] } @@ -577,7 +575,7 @@ struct FloatStruct { #[test] fn test_decode_struct_with_nan() { let s = "{\"f\":null,\"a\":[null,123]}"; - let obj: FloatStruct = json::decode(s).unwrap(); + let obj: FloatStruct = json::decode(s); assert!(obj.f.is_nan()); assert!(obj.a[0].is_nan()); assert_eq!(obj.a[1], 123f64); @@ -585,20 +583,20 @@ fn test_decode_struct_with_nan() { #[test] fn test_decode_option() { - let value: Option<string::String> = json::decode("null").unwrap(); + let value: Option<string::String> = json::decode("null"); assert_eq!(value, None); - let value: Option<string::String> = json::decode("\"jodhpurs\"").unwrap(); + let value: Option<string::String> = json::decode("\"jodhpurs\""); assert_eq!(value, Some("jodhpurs".to_string())); } #[test] fn test_decode_enum() { - let value: Animal = json::decode("\"Dog\"").unwrap(); + let value: Animal = json::decode("\"Dog\""); assert_eq!(value, Dog); let s = "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}"; - let value: Animal = json::decode(s).unwrap(); + let value: Animal = json::decode(s); assert_eq!(value, Frog("Henry".to_string(), 349)); } @@ -606,7 +604,7 @@ fn test_decode_enum() { fn test_decode_map() { let s = "{\"a\": \"Dog\", \"b\": {\"variant\":\"Frog\",\ \"fields\":[\"Henry\", 349]}}"; - let mut map: BTreeMap<string::String, Animal> = json::decode(s).unwrap(); + let mut map: BTreeMap<string::String, Animal> = json::decode(s); assert_eq!(map.remove(&"a".to_string()), Some(Dog)); assert_eq!(map.remove(&"b".to_string()), Some(Frog("Henry".to_string(), 349))); @@ -630,59 +628,65 @@ enum DecodeEnum { A(f64), B(string::String), } -fn check_err<T: Decodable<Decoder>>(to_parse: &'static str, expected: DecoderError) { - let res: DecodeResult<T> = match from_str(to_parse) { - Err(e) => Err(ParseError(e)), - Ok(json) => Decodable::decode(&mut Decoder::new(json)), - }; - match res { - Ok(_) => panic!("`{:?}` parsed & decoded ok, expecting error `{:?}`", to_parse, expected), - Err(ParseError(e)) => panic!("`{:?}` is not valid json: {:?}", to_parse, e), - Err(e) => { - assert_eq!(e, expected); - } - } +fn check_err<T: Decodable<Decoder>>(to_parse: &str) { + let json = from_str(to_parse).unwrap(); + let _: T = Decodable::decode(&mut Decoder::new(json)); } #[test] -fn test_decode_errors_struct() { - check_err::<DecodeStruct>("[]", ExpectedError("Object".to_string(), "[]".to_string())); - check_err::<DecodeStruct>( - "{\"x\": true, \"y\": true, \"z\": \"\", \"w\": []}", - ExpectedError("Number".to_string(), "true".to_string()), - ); - check_err::<DecodeStruct>( - "{\"x\": 1, \"y\": [], \"z\": \"\", \"w\": []}", - ExpectedError("Boolean".to_string(), "[]".to_string()), - ); - check_err::<DecodeStruct>( - "{\"x\": 1, \"y\": true, \"z\": {}, \"w\": []}", - ExpectedError("String".to_string(), "{}".to_string()), - ); - check_err::<DecodeStruct>( - "{\"x\": 1, \"y\": true, \"z\": \"\", \"w\": null}", - ExpectedError("Array".to_string(), "null".to_string()), - ); - check_err::<DecodeStruct>( - "{\"x\": 1, \"y\": true, \"z\": \"\"}", - MissingFieldError("w".to_string()), - ); +#[should_panic(expected = r#"ExpectedError("Object", "[]")"#)] +fn test_decode_errors_struct1() { + check_err::<DecodeStruct>("[]"); } #[test] -fn test_decode_errors_enum() { - check_err::<DecodeEnum>("{}", MissingFieldError("variant".to_string())); - check_err::<DecodeEnum>( - "{\"variant\": 1}", - ExpectedError("String".to_string(), "1".to_string()), - ); - check_err::<DecodeEnum>("{\"variant\": \"A\"}", MissingFieldError("fields".to_string())); - check_err::<DecodeEnum>( - "{\"variant\": \"A\", \"fields\": null}", - ExpectedError("Array".to_string(), "null".to_string()), - ); - check_err::<DecodeEnum>( - "{\"variant\": \"C\", \"fields\": []}", - UnknownVariantError("C".to_string()), - ); +#[should_panic(expected = r#"ExpectedError("Number", "true")"#)] +fn test_decode_errors_struct2() { + check_err::<DecodeStruct>(r#"{"x": true, "y": true, "z": "", "w": []}"#); +} +#[test] +#[should_panic(expected = r#"ExpectedError("Boolean", "[]")"#)] +fn test_decode_errors_struct3() { + check_err::<DecodeStruct>(r#"{"x": 1, "y": [], "z": "", "w": []}"#); +} +#[test] +#[should_panic(expected = r#"ExpectedError("String", "{}")"#)] +fn test_decode_errors_struct4() { + check_err::<DecodeStruct>(r#"{"x": 1, "y": true, "z": {}, "w": []}"#); +} +#[test] +#[should_panic(expected = r#"ExpectedError("Array", "null")"#)] +fn test_decode_errors_struct5() { + check_err::<DecodeStruct>(r#"{"x": 1, "y": true, "z": "", "w": null}"#); +} +#[test] +#[should_panic(expected = r#"ExpectedError("Array", "null")"#)] +fn test_decode_errors_struct6() { + check_err::<DecodeStruct>(r#"{"x": 1, "y": true, "z": ""}"#); +} + +#[test] +#[should_panic(expected = r#"MissingFieldError("variant")"#)] +fn test_decode_errors_enum1() { + check_err::<DecodeEnum>(r#"{}"#); +} +#[test] +#[should_panic(expected = r#"ExpectedError("String", "1")"#)] +fn test_decode_errors_enum2() { + check_err::<DecodeEnum>(r#"{"variant": 1}"#); +} +#[test] +#[should_panic(expected = r#"MissingFieldError("fields")"#)] +fn test_decode_errors_enum3() { + check_err::<DecodeEnum>(r#"{"variant": "A"}"#); +} +#[test] +#[should_panic(expected = r#"ExpectedError("Array", "null")"#)] +fn test_decode_errors_enum4() { + check_err::<DecodeEnum>(r#"{"variant": "A", "fields": null}"#); +} +#[test] +#[should_panic(expected = r#"UnknownVariantError("C")"#)] +fn test_decode_errors_enum5() { + check_err::<DecodeEnum>(r#"{"variant": "C", "fields": []}"#); } #[test] @@ -944,7 +948,7 @@ fn test_hashmap_with_enum_key() { map.insert(Enum::Foo, 0); let result = json::encode(&map).unwrap(); assert_eq!(&result[..], r#"{"Foo":0}"#); - let decoded: HashMap<Enum, _> = json::decode(&result).unwrap(); + let decoded: HashMap<Enum, _> = json::decode(&result); assert_eq!(map, decoded); } @@ -957,10 +961,11 @@ fn test_hashmap_with_numeric_key_can_handle_double_quote_delimited_key() { Ok(o) => o, }; let mut decoder = Decoder::new(json_obj); - let _hm: HashMap<usize, bool> = Decodable::decode(&mut decoder).unwrap(); + let _hm: HashMap<usize, bool> = Decodable::decode(&mut decoder); } #[test] +#[should_panic(expected = r#"ExpectedError("Number", "a")"#)] fn test_hashmap_with_numeric_key_will_error_with_string_keys() { use std::collections::HashMap; let json_str = "{\"a\":true}"; @@ -969,8 +974,7 @@ fn test_hashmap_with_numeric_key_will_error_with_string_keys() { Ok(o) => o, }; let mut decoder = Decoder::new(json_obj); - let result: Result<HashMap<usize, bool>, DecoderError> = Decodable::decode(&mut decoder); - assert_eq!(result, Err(ExpectedError("Number".to_string(), "a".to_string()))); + let _: HashMap<usize, bool> = Decodable::decode(&mut decoder); } fn assert_stream_equal(src: &str, expected: Vec<(JsonEvent, Vec<StackElement<'_>>)>) { diff --git a/compiler/rustc_serialize/tests/opaque.rs b/compiler/rustc_serialize/tests/opaque.rs index 13b3676a56c..298eb115111 100644 --- a/compiler/rustc_serialize/tests/opaque.rs +++ b/compiler/rustc_serialize/tests/opaque.rs @@ -41,7 +41,7 @@ fn check_round_trip<T: Encodable<Encoder> + for<'a> Decodable<Decoder<'a>> + Par let mut decoder = Decoder::new(&data[..], 0); for value in values { - let decoded = Decodable::decode(&mut decoder).unwrap(); + let decoded = Decodable::decode(&mut decoder); assert_eq!(value, decoded); } } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 92ad0723f48..a756de4c0fc 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -12,7 +12,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::impl_stable_hash_via_hash; use rustc_target::abi::{Align, TargetDataLayout}; -use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple, TargetWarnings}; +use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings}; use rustc_serialize::json; @@ -2237,6 +2237,16 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { } } + if cg.linker_flavor == Some(LinkerFlavor::L4Bender) + && !nightly_options::is_unstable_enabled(matches) + { + early_error( + error_format, + "`l4-bender` linker flavor is unstable, `-Z unstable-options` \ + flag must also be passed to explicitly use it", + ); + } + let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format); let cg = cg; diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 730e79a5647..9bcdd7f3da6 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -476,10 +476,6 @@ impl Session { &self.parse_sess.span_diagnostic } - pub fn with_disabled_diagnostic<T, F: FnOnce() -> T>(&self, f: F) -> T { - self.parse_sess.span_diagnostic.with_disabled_diagnostic(f) - } - /// Analogous to calling methods on the given `DiagnosticBuilder`, but /// deduplicates on lint ID, span (if any), and message for this `Session` fn diag_once<'a, 'b>( diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 5390eed89fa..147c1f9e043 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -47,8 +47,8 @@ impl<E: Encoder> Encodable<E> for CrateNum { } impl<D: Decoder> Decodable<D> for CrateNum { - default fn decode(d: &mut D) -> Result<CrateNum, D::Error> { - Ok(CrateNum::from_u32(d.read_u32()?)) + default fn decode(d: &mut D) -> CrateNum { + CrateNum::from_u32(d.read_u32()) } } @@ -209,7 +209,7 @@ impl<E: Encoder> Encodable<E> for DefIndex { } impl<D: Decoder> Decodable<D> for DefIndex { - default fn decode(_: &mut D) -> Result<DefIndex, D::Error> { + default fn decode(_: &mut D) -> DefIndex { panic!("cannot decode `DefIndex` with `{}`", std::any::type_name::<D>()); } } @@ -298,12 +298,10 @@ impl<E: Encoder> Encodable<E> for DefId { } impl<D: Decoder> Decodable<D> for DefId { - default fn decode(d: &mut D) -> Result<DefId, D::Error> { - d.read_struct(|d| { - Ok(DefId { - krate: d.read_struct_field("krate", Decodable::decode)?, - index: d.read_struct_field("index", Decodable::decode)?, - }) + default fn decode(d: &mut D) -> DefId { + d.read_struct(|d| DefId { + krate: d.read_struct_field("krate", Decodable::decode), + index: d.read_struct_field("index", Decodable::decode), }) } } @@ -378,8 +376,8 @@ impl<E: Encoder> Encodable<E> for LocalDefId { } impl<D: Decoder> Decodable<D> for LocalDefId { - fn decode(d: &mut D) -> Result<LocalDefId, D::Error> { - DefId::decode(d).map(|d| d.expect_local()) + fn decode(d: &mut D) -> LocalDefId { + DefId::decode(d).expect_local() } } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 7b70c20d307..e0d6bd8cb7b 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1314,19 +1314,16 @@ pub fn decode_expn_id( // to track which `SyntaxContext`s we have already decoded. // The provided closure will be invoked to deserialize a `SyntaxContextData` // if we haven't already seen the id of the `SyntaxContext` we are deserializing. -pub fn decode_syntax_context< - D: Decoder, - F: FnOnce(&mut D, u32) -> Result<SyntaxContextData, D::Error>, ->( +pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContextData>( d: &mut D, context: &HygieneDecodeContext, decode_data: F, -) -> Result<SyntaxContext, D::Error> { - let raw_id: u32 = Decodable::decode(d)?; +) -> SyntaxContext { + let raw_id: u32 = Decodable::decode(d); if raw_id == 0 { debug!("decode_syntax_context: deserialized root"); // The root is special - return Ok(SyntaxContext::root()); + return SyntaxContext::root(); } let outer_ctxts = &context.remapped_ctxts; @@ -1334,7 +1331,7 @@ pub fn decode_syntax_context< // Ensure that the lock() temporary is dropped early { if let Some(ctxt) = outer_ctxts.lock().get(raw_id as usize).copied().flatten() { - return Ok(ctxt); + return ctxt; } } @@ -1364,7 +1361,7 @@ pub fn decode_syntax_context< // Don't try to decode data while holding the lock, since we need to // be able to recursively decode a SyntaxContext - let mut ctxt_data = decode_data(d, raw_id)?; + let mut ctxt_data = decode_data(d, raw_id); // Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names` // We don't care what the encoding crate set this to - we want to resolve it // from the perspective of the current compilation session @@ -1380,7 +1377,7 @@ pub fn decode_syntax_context< assert_eq!(dummy.dollar_crate_name, kw::Empty); }); - Ok(new_ctxt) + new_ctxt } fn for_all_ctxts_in<E, F: FnMut(u32, SyntaxContext, &SyntaxContextData) -> Result<(), E>>( @@ -1422,13 +1419,13 @@ impl<E: Encoder> Encodable<E> for ExpnId { } impl<D: Decoder> Decodable<D> for LocalExpnId { - fn decode(d: &mut D) -> Result<Self, D::Error> { - ExpnId::decode(d).map(ExpnId::expect_local) + fn decode(d: &mut D) -> Self { + ExpnId::expect_local(ExpnId::decode(d)) } } impl<D: Decoder> Decodable<D> for ExpnId { - default fn decode(_: &mut D) -> Result<Self, D::Error> { + default fn decode(_: &mut D) -> Self { panic!("cannot decode `ExpnId` with `{}`", std::any::type_name::<D>()); } } @@ -1451,7 +1448,7 @@ impl<E: Encoder> Encodable<E> for SyntaxContext { } impl<D: Decoder> Decodable<D> for SyntaxContext { - default fn decode(_: &mut D) -> Result<Self, D::Error> { + default fn decode(_: &mut D) -> Self { panic!("cannot decode `SyntaxContext` with `{}`", std::any::type_name::<D>()); } } diff --git a/compiler/rustc_span/src/lev_distance.rs b/compiler/rustc_span/src/lev_distance.rs index aed699e4839..93cf965f105 100644 --- a/compiler/rustc_span/src/lev_distance.rs +++ b/compiler/rustc_span/src/lev_distance.rs @@ -11,16 +11,21 @@ use std::cmp; mod tests; /// Finds the Levenshtein distance between two strings. -pub fn lev_distance(a: &str, b: &str) -> usize { - // cases which don't require further computation - if a.is_empty() { - return b.chars().count(); - } else if b.is_empty() { - return a.chars().count(); +/// +/// Returns None if the distance exceeds the limit. +pub fn lev_distance(a: &str, b: &str, limit: usize) -> Option<usize> { + let n = a.chars().count(); + let m = b.chars().count(); + let min_dist = if n < m { m - n } else { n - m }; + + if min_dist > limit { + return None; + } + if n == 0 || m == 0 { + return (min_dist <= limit).then_some(min_dist); } - let mut dcol: Vec<_> = (0..=b.len()).collect(); - let mut t_last = 0; + let mut dcol: Vec<_> = (0..=m).collect(); for (i, sc) in a.chars().enumerate() { let mut current = i; @@ -35,10 +40,10 @@ pub fn lev_distance(a: &str, b: &str) -> usize { dcol[j + 1] = cmp::min(dcol[j + 1], dcol[j]) + 1; } current = next; - t_last = j; } } - dcol[t_last + 1] + + (dcol[m] <= limit).then_some(dcol[m]) } /// Finds the best match for a given word in the given iterator. @@ -51,39 +56,38 @@ pub fn lev_distance(a: &str, b: &str) -> usize { /// on an edge case with a lower(upper)case letters mismatch. #[cold] pub fn find_best_match_for_name( - name_vec: &[Symbol], + candidates: &[Symbol], lookup: Symbol, dist: Option<usize>, ) -> Option<Symbol> { let lookup = lookup.as_str(); - let max_dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3); + let lookup_uppercase = lookup.to_uppercase(); // Priority of matches: // 1. Exact case insensitive match // 2. Levenshtein distance match // 3. Sorted word match - if let Some(case_insensitive_match) = - name_vec.iter().find(|candidate| candidate.as_str().to_uppercase() == lookup.to_uppercase()) - { - return Some(*case_insensitive_match); + if let Some(c) = candidates.iter().find(|c| c.as_str().to_uppercase() == lookup_uppercase) { + return Some(*c); } - let levenshtein_match = name_vec - .iter() - .filter_map(|&name| { - let dist = lev_distance(lookup, name.as_str()); - if dist <= max_dist { Some((name, dist)) } else { None } - }) - // Here we are collecting the next structure: - // (levenshtein_match, levenshtein_distance) - .fold(None, |result, (candidate, dist)| match result { - None => Some((candidate, dist)), - Some((c, d)) => Some(if dist < d { (candidate, dist) } else { (c, d) }), - }); - if levenshtein_match.is_some() { - levenshtein_match.map(|(candidate, _)| candidate) - } else { - find_match_by_sorted_words(name_vec, lookup) + + let mut dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3); + let mut best = None; + for c in candidates { + match lev_distance(lookup, c.as_str(), dist) { + Some(0) => return Some(*c), + Some(d) => { + dist = d - 1; + best = Some(*c); + } + None => {} + } } + if best.is_some() { + return best; + } + + find_match_by_sorted_words(candidates, lookup) } fn find_match_by_sorted_words(iter_names: &[Symbol], lookup: &str) -> Option<Symbol> { diff --git a/compiler/rustc_span/src/lev_distance/tests.rs b/compiler/rustc_span/src/lev_distance/tests.rs index b32f8d32c13..4e34219248d 100644 --- a/compiler/rustc_span/src/lev_distance/tests.rs +++ b/compiler/rustc_span/src/lev_distance/tests.rs @@ -5,18 +5,26 @@ fn test_lev_distance() { use std::char::{from_u32, MAX}; // Test bytelength agnosticity for c in (0..MAX as u32).filter_map(from_u32).map(|i| i.to_string()) { - assert_eq!(lev_distance(&c[..], &c[..]), 0); + assert_eq!(lev_distance(&c[..], &c[..], usize::MAX), Some(0)); } let a = "\nMäry häd ä little lämb\n\nLittle lämb\n"; let b = "\nMary häd ä little lämb\n\nLittle lämb\n"; let c = "Mary häd ä little lämb\n\nLittle lämb\n"; - assert_eq!(lev_distance(a, b), 1); - assert_eq!(lev_distance(b, a), 1); - assert_eq!(lev_distance(a, c), 2); - assert_eq!(lev_distance(c, a), 2); - assert_eq!(lev_distance(b, c), 1); - assert_eq!(lev_distance(c, b), 1); + assert_eq!(lev_distance(a, b, usize::MAX), Some(1)); + assert_eq!(lev_distance(b, a, usize::MAX), Some(1)); + assert_eq!(lev_distance(a, c, usize::MAX), Some(2)); + assert_eq!(lev_distance(c, a, usize::MAX), Some(2)); + assert_eq!(lev_distance(b, c, usize::MAX), Some(1)); + assert_eq!(lev_distance(c, b, usize::MAX), Some(1)); +} + +#[test] +fn test_lev_distance_limit() { + assert_eq!(lev_distance("abc", "abcd", 1), Some(1)); + assert_eq!(lev_distance("abc", "abcd", 0), None); + assert_eq!(lev_distance("abc", "xyz", 3), Some(3)); + assert_eq!(lev_distance("abc", "xyz", 2), None); } #[test] diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 9602bc5d0b7..2c3db35bb66 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -15,6 +15,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(array_windows)] +#![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(if_let_guard)] #![feature(negative_impls)] @@ -611,7 +612,7 @@ impl Span { #[inline] /// Returns `true` if `hi == lo`. - pub fn is_empty(&self) -> bool { + pub fn is_empty(self) -> bool { let span = self.data_untracked(); span.hi == span.lo } @@ -639,7 +640,7 @@ impl Span { /// /// Use this instead of `==` when either span could be generated code, /// and you only care that they point to the same bytes of source text. - pub fn source_equal(&self, other: &Span) -> bool { + pub fn source_equal(self, other: Span) -> bool { let span = self.data(); let other = other.data(); span.lo == other.lo && span.hi == other.hi @@ -680,17 +681,17 @@ impl Span { } #[inline] - pub fn rust_2015(&self) -> bool { + pub fn rust_2015(self) -> bool { self.edition() == edition::Edition::Edition2015 } #[inline] - pub fn rust_2018(&self) -> bool { + pub fn rust_2018(self) -> bool { self.edition() >= edition::Edition::Edition2018 } #[inline] - pub fn rust_2021(&self) -> bool { + pub fn rust_2021(self) -> bool { self.edition() >= edition::Edition::Edition2021 } @@ -711,7 +712,7 @@ impl Span { /// Checks if a span is "internal" to a macro in which `#[unstable]` /// items can be used (that is, a macro marked with /// `#[allow_internal_unstable]`). - pub fn allows_unstable(&self, feature: Symbol) -> bool { + pub fn allows_unstable(self, feature: Symbol) -> bool { self.ctxt() .outer_expn_data() .allow_internal_unstable @@ -719,7 +720,7 @@ impl Span { } /// Checks if this span arises from a compiler desugaring of kind `kind`. - pub fn is_desugaring(&self, kind: DesugaringKind) -> bool { + pub fn is_desugaring(self, kind: DesugaringKind) -> bool { match self.ctxt().outer_expn_data().kind { ExpnKind::Desugaring(k) => k == kind, _ => false, @@ -728,7 +729,7 @@ impl Span { /// Returns the compiler desugaring that created this span, or `None` /// if this span is not from a desugaring. - pub fn desugaring_kind(&self) -> Option<DesugaringKind> { + pub fn desugaring_kind(self) -> Option<DesugaringKind> { match self.ctxt().outer_expn_data().kind { ExpnKind::Desugaring(k) => Some(k), _ => None, @@ -738,7 +739,7 @@ impl Span { /// Checks if a span is "internal" to a macro in which `unsafe` /// can be used without triggering the `unsafe_code` lint. // (that is, a macro marked with `#[allow_internal_unsafe]`). - pub fn allows_unsafe(&self) -> bool { + pub fn allows_unsafe(self) -> bool { self.ctxt().outer_expn_data().allow_internal_unsafe } @@ -751,7 +752,7 @@ impl Span { return None; } - let is_recursive = expn_data.call_site.source_equal(&prev_span); + let is_recursive = expn_data.call_site.source_equal(prev_span); prev_span = self; self = expn_data.call_site; @@ -865,13 +866,13 @@ impl Span { /// Equivalent of `Span::call_site` from the proc macro API, /// except that the location is taken from the `self` span. - pub fn with_call_site_ctxt(&self, expn_id: ExpnId) -> Span { + pub fn with_call_site_ctxt(self, expn_id: ExpnId) -> Span { self.with_ctxt_from_mark(expn_id, Transparency::Transparent) } /// Equivalent of `Span::mixed_site` from the proc macro API, /// except that the location is taken from the `self` span. - pub fn with_mixed_site_ctxt(&self, expn_id: ExpnId) -> Span { + pub fn with_mixed_site_ctxt(self, expn_id: ExpnId) -> Span { self.with_ctxt_from_mark(expn_id, Transparency::SemiTransparent) } @@ -975,12 +976,12 @@ impl<E: Encoder> Encodable<E> for Span { } } impl<D: Decoder> Decodable<D> for Span { - default fn decode(s: &mut D) -> Result<Span, D::Error> { + default fn decode(s: &mut D) -> Span { s.read_struct(|d| { - let lo = d.read_struct_field("lo", Decodable::decode)?; - let hi = d.read_struct_field("hi", Decodable::decode)?; + let lo = d.read_struct_field("lo", Decodable::decode); + let hi = d.read_struct_field("hi", Decodable::decode); - Ok(Span::new(lo, hi, SyntaxContext::root(), None)) + Span::new(lo, hi, SyntaxContext::root(), None) }) } } @@ -1448,30 +1449,30 @@ impl<S: Encoder> Encodable<S> for SourceFile { } impl<D: Decoder> Decodable<D> for SourceFile { - fn decode(d: &mut D) -> Result<SourceFile, D::Error> { + fn decode(d: &mut D) -> SourceFile { d.read_struct(|d| { - let name: FileName = d.read_struct_field("name", |d| Decodable::decode(d))?; + let name: FileName = d.read_struct_field("name", |d| Decodable::decode(d)); let src_hash: SourceFileHash = - d.read_struct_field("src_hash", |d| Decodable::decode(d))?; - let start_pos: BytePos = d.read_struct_field("start_pos", |d| Decodable::decode(d))?; - let end_pos: BytePos = d.read_struct_field("end_pos", |d| Decodable::decode(d))?; + d.read_struct_field("src_hash", |d| Decodable::decode(d)); + let start_pos: BytePos = d.read_struct_field("start_pos", |d| Decodable::decode(d)); + let end_pos: BytePos = d.read_struct_field("end_pos", |d| Decodable::decode(d)); let lines: Vec<BytePos> = d.read_struct_field("lines", |d| { - let num_lines: u32 = Decodable::decode(d)?; + let num_lines: u32 = Decodable::decode(d); let mut lines = Vec::with_capacity(num_lines as usize); if num_lines > 0 { // Read the number of bytes used per diff. - let bytes_per_diff: u8 = Decodable::decode(d)?; + let bytes_per_diff: u8 = Decodable::decode(d); // Read the first element. - let mut line_start: BytePos = Decodable::decode(d)?; + let mut line_start: BytePos = Decodable::decode(d); lines.push(line_start); for _ in 1..num_lines { let diff = match bytes_per_diff { - 1 => d.read_u8()? as u32, - 2 => d.read_u16()? as u32, - 4 => d.read_u32()?, + 1 => d.read_u8() as u32, + 2 => d.read_u16() as u32, + 4 => d.read_u32(), _ => unreachable!(), }; @@ -1481,17 +1482,17 @@ impl<D: Decoder> Decodable<D> for SourceFile { } } - Ok(lines) - })?; + lines + }); let multibyte_chars: Vec<MultiByteChar> = - d.read_struct_field("multibyte_chars", |d| Decodable::decode(d))?; + d.read_struct_field("multibyte_chars", |d| Decodable::decode(d)); let non_narrow_chars: Vec<NonNarrowChar> = - d.read_struct_field("non_narrow_chars", |d| Decodable::decode(d))?; - let name_hash: u128 = d.read_struct_field("name_hash", |d| Decodable::decode(d))?; + d.read_struct_field("non_narrow_chars", |d| Decodable::decode(d)); + let name_hash: u128 = d.read_struct_field("name_hash", |d| Decodable::decode(d)); let normalized_pos: Vec<NormalizedPos> = - d.read_struct_field("normalized_pos", |d| Decodable::decode(d))?; - let cnum: CrateNum = d.read_struct_field("cnum", |d| Decodable::decode(d))?; - Ok(SourceFile { + d.read_struct_field("normalized_pos", |d| Decodable::decode(d)); + let cnum: CrateNum = d.read_struct_field("cnum", |d| Decodable::decode(d)); + SourceFile { name, start_pos, end_pos, @@ -1506,7 +1507,7 @@ impl<D: Decoder> Decodable<D> for SourceFile { normalized_pos, name_hash, cnum, - }) + } }) } } @@ -1949,8 +1950,8 @@ impl<S: rustc_serialize::Encoder> Encodable<S> for BytePos { } impl<D: rustc_serialize::Decoder> Decodable<D> for BytePos { - fn decode(d: &mut D) -> Result<BytePos, D::Error> { - Ok(BytePos(d.read_u32()?)) + fn decode(d: &mut D) -> BytePos { + BytePos(d.read_u32()) } } diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index e9120b98aab..61e4074a7c8 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -61,6 +61,15 @@ use rustc_data_structures::fx::FxIndexSet; /// using the callback `SPAN_TRACK` to access the query engine. /// #[derive(Clone, Copy, Eq, PartialEq, Hash)] +// FIXME(@lcnr): Enable this attribute once the bootstrap +// compiler knows of `rustc_pass_by_value`. +// +// Right now, this lint would only trigger when compiling the +// stage 2 compiler, which is fairly annoying as there are +// a lot of places using `&Span` right now. After the next bootstrap bump, +// the lint will already trigger when using stage 1, which is a lot less annoying. +// +// #[cfg_attr(not(bootstrap), rustc_pass_by_value)] pub struct Span { base_or_index: u32, len_or_tag: u16, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 702e3594660..757c430e799 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -272,7 +272,6 @@ symbols! { __H, __S, __try_var, - _args, _d, _e, _task_context, @@ -321,8 +320,10 @@ symbols! { and, and_then, any, + append_const_msg, arbitrary_enum_discriminant, arbitrary_self_types, + args, arith_offset, arm, arm_target_feature, @@ -460,6 +461,7 @@ symbols! { const_async_blocks, const_compare_raw_pointers, const_constructor, + const_deallocate, const_eval_limit, const_eval_select, const_eval_select_ct, @@ -990,6 +992,7 @@ symbols! { panic_implementation, panic_info, panic_location, + panic_no_unwind, panic_runtime, panic_str, panic_unwind, @@ -1203,6 +1206,7 @@ symbols! { rustc_trivial_field_reads, rustc_unsafe_specialization_marker, rustc_variance, + rustc_with_negative_coherence, rustdoc, rustdoc_internals, rustfmt, @@ -1755,8 +1759,8 @@ impl<S: Encoder> Encodable<S> for Symbol { impl<D: Decoder> Decodable<D> for Symbol { #[inline] - fn decode(d: &mut D) -> Result<Symbol, D::Error> { - Ok(Symbol::intern(&d.read_str()?)) + fn decode(d: &mut D) -> Symbol { + Symbol::intern(&d.read_str()) } } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 0d51f7779e1..f8e8e15e78c 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -556,7 +556,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { cx = cx.print_def_path(trait_ref.def_id, trait_ref.substs)?; } ty::ExistentialPredicate::Projection(projection) => { - let name = cx.tcx.associated_item(projection.item_def_id).ident; + let name = cx.tcx.associated_item(projection.item_def_id).name; cx.push("p"); cx.push_ident(name.as_str()); cx = match projection.term { diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 6b82bb337e6..a84410d0f3c 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -152,6 +152,7 @@ mod avr; mod bpf; mod hexagon; mod mips; +mod msp430; mod nvptx; mod powerpc; mod riscv; @@ -166,6 +167,7 @@ pub use avr::{AvrInlineAsmReg, AvrInlineAsmRegClass}; pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass}; pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass}; pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass}; +pub use msp430::{Msp430InlineAsmReg, Msp430InlineAsmRegClass}; pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass}; pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass}; pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass}; @@ -194,6 +196,7 @@ pub enum InlineAsmArch { Wasm64, Bpf, Avr, + Msp430, } impl FromStr for InlineAsmArch { @@ -219,6 +222,7 @@ impl FromStr for InlineAsmArch { "wasm64" => Ok(Self::Wasm64), "bpf" => Ok(Self::Bpf), "avr" => Ok(Self::Avr), + "msp430" => Ok(Self::Msp430), _ => Err(()), } } @@ -250,6 +254,7 @@ pub enum InlineAsmReg { Wasm(WasmInlineAsmReg), Bpf(BpfInlineAsmReg), Avr(AvrInlineAsmReg), + Msp430(Msp430InlineAsmReg), // Placeholder for invalid register constraints for the current target Err, } @@ -267,6 +272,7 @@ impl InlineAsmReg { Self::S390x(r) => r.name(), Self::Bpf(r) => r.name(), Self::Avr(r) => r.name(), + Self::Msp430(r) => r.name(), Self::Err => "<reg>", } } @@ -283,6 +289,7 @@ impl InlineAsmReg { Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()), Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()), Self::Avr(r) => InlineAsmRegClass::Avr(r.reg_class()), + Self::Msp430(r) => InlineAsmRegClass::Msp430(r.reg_class()), Self::Err => InlineAsmRegClass::Err, } } @@ -336,6 +343,9 @@ impl InlineAsmReg { InlineAsmArch::Avr => { Self::Avr(AvrInlineAsmReg::parse(arch, target_features, target, name)?) } + InlineAsmArch::Msp430 => { + Self::Msp430(Msp430InlineAsmReg::parse(arch, target_features, target, name)?) + } }) } @@ -358,6 +368,7 @@ impl InlineAsmReg { Self::S390x(r) => r.emit(out, arch, modifier), Self::Bpf(r) => r.emit(out, arch, modifier), Self::Avr(r) => r.emit(out, arch, modifier), + Self::Msp430(r) => r.emit(out, arch, modifier), Self::Err => unreachable!("Use of InlineAsmReg::Err"), } } @@ -374,6 +385,7 @@ impl InlineAsmReg { Self::S390x(_) => cb(self), Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))), Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))), + Self::Msp430(_) => cb(self), Self::Err => unreachable!("Use of InlineAsmReg::Err"), } } @@ -405,6 +417,7 @@ pub enum InlineAsmRegClass { Wasm(WasmInlineAsmRegClass), Bpf(BpfInlineAsmRegClass), Avr(AvrInlineAsmRegClass), + Msp430(Msp430InlineAsmRegClass), // Placeholder for invalid register constraints for the current target Err, } @@ -425,12 +438,13 @@ impl InlineAsmRegClass { Self::Wasm(r) => r.name(), Self::Bpf(r) => r.name(), Self::Avr(r) => r.name(), + Self::Msp430(r) => r.name(), Self::Err => rustc_span::symbol::sym::reg, } } /// Returns a suggested register class to use for this type. This is called - /// after type checking via `supported_types` fails to give a better error + /// when `supported_types` fails to give a better error /// message to the user. pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> { match self { @@ -447,6 +461,7 @@ impl InlineAsmRegClass { Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm), Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf), Self::Avr(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Avr), + Self::Msp430(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Msp430), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), } } @@ -476,6 +491,7 @@ impl InlineAsmRegClass { Self::Wasm(r) => r.suggest_modifier(arch, ty), Self::Bpf(r) => r.suggest_modifier(arch, ty), Self::Avr(r) => r.suggest_modifier(arch, ty), + Self::Msp430(r) => r.suggest_modifier(arch, ty), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), } } @@ -501,6 +517,7 @@ impl InlineAsmRegClass { Self::Wasm(r) => r.default_modifier(arch), Self::Bpf(r) => r.default_modifier(arch), Self::Avr(r) => r.default_modifier(arch), + Self::Msp430(r) => r.default_modifier(arch), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), } } @@ -525,6 +542,7 @@ impl InlineAsmRegClass { Self::Wasm(r) => r.supported_types(arch), Self::Bpf(r) => r.supported_types(arch), Self::Avr(r) => r.supported_types(arch), + Self::Msp430(r) => r.supported_types(arch), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), } } @@ -554,6 +572,7 @@ impl InlineAsmRegClass { } InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?), InlineAsmArch::Avr => Self::Avr(AvrInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmRegClass::parse(arch, name)?), }) } @@ -574,6 +593,7 @@ impl InlineAsmRegClass { Self::Wasm(r) => r.valid_modifiers(arch), Self::Bpf(r) => r.valid_modifiers(arch), Self::Avr(r) => r.valid_modifiers(arch), + Self::Msp430(r) => r.valid_modifiers(arch), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), } } @@ -764,6 +784,11 @@ pub fn allocatable_registers( avr::fill_reg_map(arch, target_features, target, &mut map); map } + InlineAsmArch::Msp430 => { + let mut map = msp430::regclass_map(); + msp430::fill_reg_map(arch, target_features, target, &mut map); + map + } } } diff --git a/compiler/rustc_target/src/asm/msp430.rs b/compiler/rustc_target/src/asm/msp430.rs new file mode 100644 index 00000000000..a27d6390a72 --- /dev/null +++ b/compiler/rustc_target/src/asm/msp430.rs @@ -0,0 +1,81 @@ +use super::{InlineAsmArch, InlineAsmType}; +use rustc_macros::HashStable_Generic; +use rustc_span::Symbol; +use std::fmt; + +def_reg_class! { + Msp430 Msp430InlineAsmRegClass { + reg, + } +} + +impl Msp430InlineAsmRegClass { + pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] { + &[] + } + + pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> { + None + } + + pub fn suggest_modifier( + self, + _arch: InlineAsmArch, + _ty: InlineAsmType, + ) -> Option<(char, &'static str)> { + None + } + + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + None + } + + pub fn supported_types( + self, + arch: InlineAsmArch, + ) -> &'static [(InlineAsmType, Option<Symbol>)] { + match (self, arch) { + (Self::reg, _) => types! { _: I8, I16; }, + } + } +} + +// The reserved registers are taken from: +// https://github.com/llvm/llvm-project/blob/36cb29cbbe1b22dcd298ad65e1fabe899b7d7249/llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp#L73. +def_regs! { + Msp430 Msp430InlineAsmReg Msp430InlineAsmRegClass { + r5: reg = ["r5"], + r6: reg = ["r6"], + r7: reg = ["r7"], + r8: reg = ["r8"], + r9: reg = ["r9"], + r10: reg = ["r10"], + r11: reg = ["r11"], + r12: reg = ["r12"], + r13: reg = ["r13"], + r14: reg = ["r14"], + r15: reg = ["r15"], + + #error = ["r0", "pc"] => + "the program counter cannot be used as an operand for inline asm", + #error = ["r1", "sp"] => + "the stack pointer cannot be used as an operand for inline asm", + #error = ["r2", "sr"] => + "the status register cannot be used as an operand for inline asm", + #error = ["r3", "cg"] => + "the constant generator cannot be used as an operand for inline asm", + #error = ["r4", "fp"] => + "the frame pointer cannot be used as an operand for inline asm", + } +} + +impl Msp430InlineAsmReg { + pub fn emit( + self, + out: &mut dyn fmt::Write, + _arch: InlineAsmArch, + _modifier: Option<char>, + ) -> fmt::Result { + out.write_str(self.name()) + } +} diff --git a/compiler/rustc_target/src/spec/l4re_base.rs b/compiler/rustc_target/src/spec/l4re_base.rs index f6e3102f617..9e7973f63a9 100644 --- a/compiler/rustc_target/src/spec/l4re_base.rs +++ b/compiler/rustc_target/src/spec/l4re_base.rs @@ -1,25 +1,14 @@ use crate::spec::{LinkerFlavor, PanicStrategy, TargetOptions}; -//use std::process::Command; - -// Use GCC to locate code for crt* libraries from the host, not from L4Re. Note -// that a few files also come from L4Re, for these, the function shouldn't be -// used. This uses GCC for the location of the file, but GCC is required for L4Re anyway. -//fn get_path_or(filename: &str) -> String { -// let child = Command::new("gcc") -// .arg(format!("-print-file-name={}", filename)).output() -// .expect("Failed to execute GCC"); -// String::from_utf8(child.stdout) -// .expect("Couldn't read path from GCC").trim().into() -//} +use std::default::Default; pub fn opts() -> TargetOptions { TargetOptions { os: "l4re".to_string(), env: "uclibc".to_string(), - linker_flavor: LinkerFlavor::Ld, + linker_flavor: LinkerFlavor::L4Bender, executables: true, panic_strategy: PanicStrategy::Abort, - linker: Some("ld".to_string()), + linker: Some("l4-bender".to_string()), linker_is_gnu: false, families: vec!["unix".to_string()], ..Default::default() diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 2c149318730..4effb8bacf6 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -90,6 +90,7 @@ mod windows_uwp_msvc_base; pub enum LinkerFlavor { Em, Gcc, + L4Bender, Ld, Msvc, Lld(LldFlavor), @@ -160,6 +161,7 @@ macro_rules! flavor_mappings { flavor_mappings! { ((LinkerFlavor::Em), "em"), ((LinkerFlavor::Gcc), "gcc"), + ((LinkerFlavor::L4Bender), "l4-bender"), ((LinkerFlavor::Ld), "ld"), ((LinkerFlavor::Msvc), "msvc"), ((LinkerFlavor::PtxLinker), "ptx-linker"), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs index 1fbd0bb4cec..64c7c1c5f6f 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs @@ -1,9 +1,12 @@ -use crate::spec::Target; +use crate::spec::{PanicStrategy, Target}; pub fn target() -> Target { let mut base = super::l4re_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); + base.crt_static_allows_dylibs = false; + base.dynamic_linking = false; + base.panic_strategy = PanicStrategy::Abort; Target { llvm_target: "x86_64-unknown-l4re-uclibc".to_string(), diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index 848aba7c912..759bc696981 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -18,7 +18,6 @@ use rustc_middle::ty::{self, TyCtxt}; /// that type check should guarantee to us that all nested /// obligations *could be* resolved if we wanted to. /// -/// Assumes that this is run after the entire crate has been successfully type-checked. /// This also expects that `trait_ref` is fully normalized. pub fn codegen_fulfill_obligation<'tcx>( tcx: TyCtxt<'tcx>, @@ -101,7 +100,7 @@ pub fn codegen_fulfill_obligation<'tcx>( /// Finishes processes any obligations that remain in the /// fulfillment context, and then returns the result with all type /// variables removed and regions erased. Because this is intended -/// for use after type-check has completed, if any errors occur, +/// for use outside of type inference, if any errors occur, /// it will panic. It is used during normalization and other cases /// where processing the obligations in `fulfill_cx` may cause /// type inference variables that appear in `result` to be @@ -124,7 +123,10 @@ where if !errors.is_empty() { infcx.tcx.sess.delay_span_bug( rustc_span::DUMMY_SP, - &format!("Encountered errors `{:?}` resolving bounds after type-checking", errors), + &format!( + "Encountered errors `{:?}` resolving bounds outside of type inference", + errors + ), ); } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index af3540386f9..ab1dc8fcbfe 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -7,10 +7,13 @@ use crate::infer::{CombinedSnapshot, InferOk, TyCtxtInferExt}; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::select::IntercrateAmbiguityCause; +use crate::traits::util::impl_trait_ref_and_oblig; use crate::traits::SkipLeakCheck; use crate::traits::{ - self, Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext, + self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation, + PredicateObligations, SelectionContext, }; +use rustc_ast::Attribute; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences}; use rustc_middle::ty::fold::TypeFoldable; @@ -135,45 +138,89 @@ fn with_fresh_ty_vars<'cx, 'tcx>( header } +/// What kind of overlap check are we doing -- this exists just for testing and feature-gating +/// purposes. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +enum OverlapMode { + /// The 1.0 rules (either types fail to unify, or where clauses are not implemented for crate-local types) + Stable, + /// Feature-gated test: Stable, *or* there is an explicit negative impl that rules out one of the where-clauses. + WithNegative, + /// Just check for negative impls, not for "where clause not implemented": used for testing. + Strict, +} + +impl OverlapMode { + fn use_negative_impl(&self) -> bool { + *self == OverlapMode::Strict || *self == OverlapMode::WithNegative + } + + fn use_implicit_negative(&self) -> bool { + *self == OverlapMode::Stable || *self == OverlapMode::WithNegative + } +} + +fn overlap_mode<'tcx>(tcx: TyCtxt<'tcx>, impl1_def_id: DefId, impl2_def_id: DefId) -> OverlapMode { + // Find the possible coherence mode override opt-in attributes for each `DefId` + let find_coherence_attr = |attr: &Attribute| { + let name = attr.name_or_empty(); + match name { + sym::rustc_with_negative_coherence | sym::rustc_strict_coherence => Some(name), + _ => None, + } + }; + let impl1_coherence_mode = tcx.get_attrs(impl1_def_id).iter().find_map(find_coherence_attr); + let impl2_coherence_mode = tcx.get_attrs(impl2_def_id).iter().find_map(find_coherence_attr); + + // If there are any (that currently happens in tests), they need to match. Otherwise, the + // default 1.0 rules are used. + match (impl1_coherence_mode, impl2_coherence_mode) { + (None, None) => OverlapMode::Stable, + (Some(sym::rustc_with_negative_coherence), Some(sym::rustc_with_negative_coherence)) => { + OverlapMode::WithNegative + } + (Some(sym::rustc_strict_coherence), Some(sym::rustc_strict_coherence)) => { + OverlapMode::Strict + } + (Some(mode), _) | (_, Some(mode)) => { + bug!("Use the same coherence mode on both impls: {}", mode) + } + } +} + /// Can both impl `a` and impl `b` be satisfied by a common type (including /// where-clauses)? If so, returns an `ImplHeader` that unifies the two impls. fn overlap<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, skip_leak_check: SkipLeakCheck, - a_def_id: DefId, - b_def_id: DefId, + impl1_def_id: DefId, + impl2_def_id: DefId, ) -> Option<OverlapResult<'tcx>> { - debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id); + debug!("overlap(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id); selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| { - overlap_within_probe(selcx, skip_leak_check, a_def_id, b_def_id, snapshot) + overlap_within_probe(selcx, skip_leak_check, impl1_def_id, impl2_def_id, snapshot) }) } fn overlap_within_probe<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, skip_leak_check: SkipLeakCheck, - a_def_id: DefId, - b_def_id: DefId, + impl1_def_id: DefId, + impl2_def_id: DefId, snapshot: &CombinedSnapshot<'_, 'tcx>, ) -> Option<OverlapResult<'tcx>> { - fn loose_check<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - o: &PredicateObligation<'tcx>, - ) -> bool { - !selcx.predicate_may_hold_fatal(o) - } + let infcx = selcx.infcx(); + let tcx = infcx.tcx; + + let overlap_mode = overlap_mode(tcx, impl1_def_id, impl2_def_id); - fn strict_check<'cx, 'tcx>( - selcx: &SelectionContext<'cx, 'tcx>, - o: &PredicateObligation<'tcx>, - ) -> bool { - let infcx = selcx.infcx(); - let tcx = infcx.tcx; - o.flip_polarity(tcx) - .as_ref() - .map(|o| selcx.infcx().predicate_must_hold_modulo_regions(o)) - .unwrap_or(false) + if overlap_mode.use_negative_impl() { + if negative_impl(selcx, impl1_def_id, impl2_def_id) + || negative_impl(selcx, impl2_def_id, impl1_def_id) + { + return None; + } } // For the purposes of this check, we don't bring any placeholder @@ -182,26 +229,61 @@ fn overlap_within_probe<'cx, 'tcx>( // empty environment. let param_env = ty::ParamEnv::empty(); - let a_impl_header = with_fresh_ty_vars(selcx, param_env, a_def_id); - let b_impl_header = with_fresh_ty_vars(selcx, param_env, b_def_id); + let impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id); + let impl2_header = with_fresh_ty_vars(selcx, param_env, impl2_def_id); - debug!("overlap: a_impl_header={:?}", a_impl_header); - debug!("overlap: b_impl_header={:?}", b_impl_header); + debug!("overlap: impl1_header={:?}", impl1_header); + debug!("overlap: impl2_header={:?}", impl2_header); - // Do `a` and `b` unify? If not, no overlap. - let obligations = match selcx - .infcx() - .at(&ObligationCause::dummy(), param_env) - .eq_impl_headers(&a_impl_header, &b_impl_header) - { - Ok(InferOk { obligations, value: () }) => obligations, - Err(_) => { + let obligations = equate_impl_headers(selcx, &impl1_header, &impl2_header)?; + debug!("overlap: unification check succeeded"); + + if overlap_mode.use_implicit_negative() { + if implicit_negative(selcx, param_env, &impl1_header, impl2_header, obligations) { return None; } - }; + } - debug!("overlap: unification check succeeded"); + if !skip_leak_check.is_yes() { + if infcx.leak_check(true, snapshot).is_err() { + debug!("overlap: leak check failed"); + return None; + } + } + + let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes(); + debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes); + + let involves_placeholder = + matches!(selcx.infcx().region_constraints_added_in_snapshot(snapshot), Some(true)); + + let impl_header = selcx.infcx().resolve_vars_if_possible(impl1_header); + Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) +} + +fn equate_impl_headers<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + impl1_header: &ty::ImplHeader<'tcx>, + impl2_header: &ty::ImplHeader<'tcx>, +) -> Option<PredicateObligations<'tcx>> { + // Do `a` and `b` unify? If not, no overlap. + selcx + .infcx() + .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) + .eq_impl_headers(impl1_header, impl2_header) + .map(|infer_ok| infer_ok.obligations) + .ok() +} +/// Given impl1 and impl2 check if both impls can be satisfied by a common type (including +/// where-clauses) If so, return false, otherwise return true, they are disjoint. +fn implicit_negative<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + impl1_header: &ty::ImplHeader<'tcx>, + impl2_header: ty::ImplHeader<'tcx>, + obligations: PredicateObligations<'tcx>, +) -> bool { // There's no overlap if obligations are unsatisfiable or if the obligation negated is // satisfied. // @@ -225,11 +307,11 @@ fn overlap_within_probe<'cx, 'tcx>( // at some point an impl for `&'?a str: Error` could be added. let infcx = selcx.infcx(); let tcx = infcx.tcx; - let opt_failing_obligation = a_impl_header + let opt_failing_obligation = impl1_header .predicates .iter() .copied() - .chain(b_impl_header.predicates) + .chain(impl2_header.predicates) .map(|p| infcx.resolve_vars_if_possible(p)) .map(|p| Obligation { cause: ObligationCause::dummy(), @@ -239,15 +321,7 @@ fn overlap_within_probe<'cx, 'tcx>( }) .chain(obligations) .find(|o| { - // if both impl headers are set to strict coherence it means that this will be accepted - // only if it's stated that T: !Trait. So only prove that the negated obligation holds. - if tcx.has_attr(a_def_id, sym::rustc_strict_coherence) - && tcx.has_attr(b_def_id, sym::rustc_strict_coherence) - { - strict_check(selcx, o) - } else { - loose_check(selcx, o) || tcx.features().negative_impls && strict_check(selcx, o) - } + loose_check(selcx, o) || tcx.features().negative_impls && negative_impl_exists(selcx, o) }); // FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported // to the canonical trait query form, `infcx.predicate_may_hold`, once @@ -255,24 +329,97 @@ fn overlap_within_probe<'cx, 'tcx>( if let Some(failing_obligation) = opt_failing_obligation { debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); - return None; + true + } else { + false } +} - if !skip_leak_check.is_yes() { - if infcx.leak_check(true, snapshot).is_err() { - debug!("overlap: leak check failed"); - return None; - } - } +/// Given impl1 and impl2 check if both impls are never satisfied by a common type (including +/// where-clauses) If so, return true, they are disjoint and false otherwise. +fn negative_impl<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + impl1_def_id: DefId, + impl2_def_id: DefId, +) -> bool { + let tcx = selcx.infcx().tcx; - let impl_header = selcx.infcx().resolve_vars_if_possible(a_impl_header); - let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes(); - debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes); + // create a parameter environment corresponding to a (placeholder) instantiation of impl1 + let impl1_env = tcx.param_env(impl1_def_id); + let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap(); - let involves_placeholder = - matches!(selcx.infcx().region_constraints_added_in_snapshot(snapshot), Some(true)); + // Create an infcx, taking the predicates of impl1 as assumptions: + tcx.infer_ctxt().enter(|infcx| { + // Normalize the trait reference. The WF rules ought to ensure + // that this always succeeds. + let impl1_trait_ref = match traits::fully_normalize( + &infcx, + FulfillmentContext::new(), + ObligationCause::dummy(), + impl1_env, + impl1_trait_ref, + ) { + Ok(impl1_trait_ref) => impl1_trait_ref, + Err(err) => { + bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err); + } + }; + + // Attempt to prove that impl2 applies, given all of the above. + let selcx = &mut SelectionContext::new(&infcx); + let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id); + let (impl2_trait_ref, obligations) = + impl_trait_ref_and_oblig(selcx, impl1_env, impl2_def_id, impl2_substs); + + // do the impls unify? If not, not disjoint. + let more_obligations = match infcx + .at(&ObligationCause::dummy(), impl1_env) + .eq(impl1_trait_ref, impl2_trait_ref) + { + Ok(InferOk { obligations, .. }) => obligations, + Err(_) => { + debug!( + "explicit_disjoint: {:?} does not unify with {:?}", + impl1_trait_ref, impl2_trait_ref + ); + return false; + } + }; - Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) + let opt_failing_obligation = obligations + .into_iter() + .chain(more_obligations) + .find(|o| negative_impl_exists(selcx, o)); + + if let Some(failing_obligation) = opt_failing_obligation { + debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); + true + } else { + false + } + }) +} + +fn loose_check<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + o: &PredicateObligation<'tcx>, +) -> bool { + !selcx.predicate_may_hold_fatal(o) +} + +fn negative_impl_exists<'cx, 'tcx>( + selcx: &SelectionContext<'cx, 'tcx>, + o: &PredicateObligation<'tcx>, +) -> bool { + let infcx = selcx.infcx(); + let tcx = infcx.tcx; + o.flip_polarity(tcx) + .as_ref() + .map(|o| { + // FIXME This isn't quite correct, regions should be included + selcx.infcx().predicate_must_hold_modulo_regions(o) + }) + .unwrap_or(false) } pub fn trait_ref_is_knowable<'tcx>( diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 0760f626851..687bd16ba30 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -205,6 +205,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.note_obligation_cause_code( &mut err, &obligation.predicate, + obligation.param_env, obligation.cause.code(), &mut vec![], &mut Default::default(), @@ -288,7 +289,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { match bound_predicate.skip_binder() { ty::PredicateKind::Trait(trait_predicate) => { let trait_predicate = bound_predicate.rebind(trait_predicate); - let trait_predicate = self.resolve_vars_if_possible(trait_predicate); + let mut trait_predicate = self.resolve_vars_if_possible(trait_predicate); + + trait_predicate.remap_constness_diag(obligation.param_env); + let predicate_is_const = ty::BoundConstness::ConstIfConst + == trait_predicate.skip_binder().constness; if self.tcx.sess.has_errors() && trait_predicate.references_error() { return; @@ -305,13 +310,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }) .unwrap_or_default(); - let OnUnimplementedNote { message, label, note, enclosing_scope } = - self.on_unimplemented_note(trait_ref, &obligation); + let OnUnimplementedNote { + message, + label, + note, + enclosing_scope, + append_const_msg, + } = self.on_unimplemented_note(trait_ref, &obligation); let have_alt_message = message.is_some() || label.is_some(); let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id()); let is_unsize = { Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait() }; - let (message, note) = if is_try_conversion { + let (message, note, append_const_msg) = if is_try_conversion { ( Some(format!( "`?` couldn't convert the error to `{}`", @@ -322,9 +332,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { conversion on the error value using the `From` trait" .to_owned(), ), + Some(None), ) } else { - (message, note) + (message, note, append_const_msg) }; let mut err = struct_span_err!( @@ -332,11 +343,27 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { span, E0277, "{}", - message.unwrap_or_else(|| format!( - "the trait bound `{}` is not satisfied{}", - trait_ref.without_const().to_predicate(tcx), - post_message, - )) + message + .and_then(|cannot_do_this| { + match (predicate_is_const, append_const_msg) { + // do nothing if predicate is not const + (false, _) => Some(cannot_do_this), + // suggested using default post message + (true, Some(None)) => { + Some(format!("{cannot_do_this} in const contexts")) + } + // overriden post message + (true, Some(Some(post_message))) => { + Some(format!("{cannot_do_this}{post_message}")) + } + // fallback to generic message + (true, None) => None, + } + }) + .unwrap_or_else(|| format!( + "the trait bound `{}` is not satisfied{}", + trait_predicate, post_message, + )) ); if is_try_conversion { @@ -384,7 +411,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { format!( "{}the trait `{}` is not implemented for `{}`", pre_message, - trait_ref.print_only_trait_path(), + trait_predicate.print_modifiers_and_trait_path(), trait_ref.skip_binder().self_ty(), ) }; @@ -392,7 +419,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if self.suggest_add_reference_to_arg( &obligation, &mut err, - &trait_ref, + trait_predicate, have_alt_message, ) { self.note_obligation_cause(&mut err, &obligation); @@ -412,6 +439,28 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } else { err.span_label(span, explanation); } + + if trait_predicate.is_const_if_const() && obligation.param_env.is_const() { + let non_const_predicate = trait_ref.without_const(); + let non_const_obligation = Obligation { + cause: obligation.cause.clone(), + param_env: obligation.param_env.without_const(), + predicate: non_const_predicate.to_predicate(tcx), + recursion_depth: obligation.recursion_depth, + }; + if self.predicate_may_hold(&non_const_obligation) { + err.span_note( + span, + &format!( + "the trait `{}` is implemented for `{}`, \ + but that implementation is not `const`", + non_const_predicate.print_modifiers_and_trait_path(), + trait_ref.skip_binder().self_ty(), + ), + ); + } + } + if let Some((msg, span)) = type_def { err.span_label(span, &msg); } @@ -435,18 +484,28 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.span_label(enclosing_scope_span, s.as_str()); } - self.suggest_dereferences(&obligation, &mut err, trait_ref); - self.suggest_fn_call(&obligation, &mut err, trait_ref); - self.suggest_remove_reference(&obligation, &mut err, trait_ref); - self.suggest_semicolon_removal(&obligation, &mut err, span, trait_ref); + self.suggest_dereferences(&obligation, &mut err, trait_predicate); + self.suggest_fn_call(&obligation, &mut err, trait_predicate); + self.suggest_remove_reference(&obligation, &mut err, trait_predicate); + self.suggest_semicolon_removal( + &obligation, + &mut err, + span, + trait_predicate, + ); self.note_version_mismatch(&mut err, &trait_ref); self.suggest_remove_await(&obligation, &mut err); if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() { - self.suggest_await_before_try(&mut err, &obligation, trait_ref, span); + self.suggest_await_before_try( + &mut err, + &obligation, + trait_predicate, + span, + ); } - if self.suggest_impl_trait(&mut err, span, &obligation, trait_ref) { + if self.suggest_impl_trait(&mut err, span, &obligation, trait_predicate) { err.emit(); return; } @@ -494,7 +553,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // which is somewhat confusing. self.suggest_restricting_param_bound( &mut err, - trait_ref, + trait_predicate, obligation.cause.body_id, ); } else if !have_alt_message { @@ -506,7 +565,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Changing mutability doesn't make a difference to whether we have // an `Unsize` impl (Fixes ICE in #71036) if !is_unsize { - self.suggest_change_mut(&obligation, &mut err, trait_ref); + self.suggest_change_mut(&obligation, &mut err, trait_predicate); } // If this error is due to `!: Trait` not implemented but `(): Trait` is @@ -1121,7 +1180,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> { fn mk_trait_obligation_with_new_self_ty( &self, param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_ref: ty::PolyTraitPredicate<'tcx>, new_self_ty: Ty<'tcx>, ) -> PredicateObligation<'tcx>; @@ -1353,6 +1412,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { .map(|id| (trait_assoc_item, id)) }) .and_then(|(trait_assoc_item, id)| { + let trait_assoc_ident = trait_assoc_item.ident(self.tcx); self.tcx.find_map_relevant_impl( id, proj.projection_ty.self_ty(), @@ -1360,7 +1420,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { self.tcx .associated_items(did) .in_definition_order() - .filter(|assoc| assoc.ident == trait_assoc_item.ident) + .filter(|assoc| assoc.ident(self.tcx) == trait_assoc_ident) .next() }, ) @@ -1540,7 +1600,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { ) -> Option<(String, Option<Span>)> { match code { ObligationCauseCode::BuiltinDerivedObligation(data) => { - let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref); + let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); match self.get_parent_trait_ref(&data.parent_code) { Some(t) => Some(t), None => { @@ -1593,21 +1653,20 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { fn mk_trait_obligation_with_new_self_ty( &self, param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_ref: ty::PolyTraitPredicate<'tcx>, new_self_ty: Ty<'tcx>, ) -> PredicateObligation<'tcx> { assert!(!new_self_ty.has_escaping_bound_vars()); - let trait_ref = trait_ref.map_bound_ref(|tr| ty::TraitRef { - substs: self.tcx.mk_substs_trait(new_self_ty, &tr.substs[1..]), + let trait_pred = trait_ref.map_bound_ref(|tr| ty::TraitPredicate { + trait_ref: ty::TraitRef { + substs: self.tcx.mk_substs_trait(new_self_ty, &tr.trait_ref.substs[1..]), + ..tr.trait_ref + }, ..*tr }); - Obligation::new( - ObligationCause::dummy(), - param_env, - trait_ref.without_const().to_predicate(self.tcx), - ) + Obligation::new(ObligationCause::dummy(), param_env, trait_pred.to_predicate(self.tcx)) } #[instrument(skip(self), level = "debug")] @@ -2008,6 +2067,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { self.note_obligation_cause_code( err, &obligation.predicate, + obligation.param_env, obligation.cause.code(), &mut vec![], &mut Default::default(), @@ -2155,7 +2215,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { cause_code: &ObligationCauseCode<'tcx>, ) -> bool { if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code { - let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref); + let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); let self_ty = parent_trait_ref.skip_binder().self_ty(); if obligated_types.iter().any(|ot| ot == &self_ty) { return true; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index e94c600bb49..8c0dbe9b064 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -48,7 +48,7 @@ pub trait InferCtxtExt<'tcx> { fn suggest_restricting_param_bound( &self, err: &mut DiagnosticBuilder<'_>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, body_id: hir::HirId, ); @@ -56,7 +56,7 @@ pub trait InferCtxtExt<'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, ); fn get_closure_name( @@ -70,14 +70,14 @@ pub trait InferCtxtExt<'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + trait_pred: ty::PolyTraitPredicate<'tcx>, ); fn suggest_add_reference_to_arg( &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder<'tcx, ty::TraitRef<'tcx>>, + trait_pred: ty::PolyTraitPredicate<'tcx>, has_custom_message: bool, ) -> bool; @@ -85,7 +85,7 @@ pub trait InferCtxtExt<'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + trait_pred: ty::PolyTraitPredicate<'tcx>, ); fn suggest_remove_await( @@ -98,7 +98,7 @@ pub trait InferCtxtExt<'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + trait_pred: ty::PolyTraitPredicate<'tcx>, ); fn suggest_semicolon_removal( @@ -106,7 +106,7 @@ pub trait InferCtxtExt<'tcx> { obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, span: Span, - trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + trait_pred: ty::PolyTraitPredicate<'tcx>, ); fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span>; @@ -116,7 +116,7 @@ pub trait InferCtxtExt<'tcx> { err: &mut DiagnosticBuilder<'_>, span: Span, obligation: &PredicateObligation<'tcx>, - trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool; fn point_at_returns_when_relevant( @@ -154,7 +154,7 @@ pub trait InferCtxtExt<'tcx> { interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>, inner_generator_body: Option<&hir::Body<'tcx>>, outer_generator: Option<DefId>, - trait_ref: ty::TraitRef<'tcx>, + trait_pred: ty::TraitPredicate<'tcx>, target_ty: Ty<'tcx>, typeck_results: Option<&ty::TypeckResults<'tcx>>, obligation: &PredicateObligation<'tcx>, @@ -165,6 +165,7 @@ pub trait InferCtxtExt<'tcx> { &self, err: &mut DiagnosticBuilder<'_>, predicate: &T, + param_env: ty::ParamEnv<'tcx>, cause_code: &ObligationCauseCode<'tcx>, obligated_types: &mut Vec<&ty::TyS<'tcx>>, seen_requirements: &mut FxHashSet<DefId>, @@ -178,7 +179,7 @@ pub trait InferCtxtExt<'tcx> { &self, err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, - trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + trait_pred: ty::PolyTraitPredicate<'tcx>, span: Span, ); } @@ -204,7 +205,7 @@ fn suggest_restriction<'tcx>( err: &mut DiagnosticBuilder<'_>, fn_sig: Option<&hir::FnSig<'_>>, projection: Option<&ty::ProjectionTy<'_>>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>, ) { // When we are dealing with a trait, `super_traits` will be `Some`: @@ -257,9 +258,9 @@ fn suggest_restriction<'tcx>( // The type param `T: Trait` we will suggest to introduce. let type_param = format!("{}: {}", type_param_name, bound_str); - // FIXME: modify the `trait_ref` instead of string shenanigans. + // FIXME: modify the `trait_pred` instead of string shenanigans. // Turn `<impl Trait as Foo>::Bar: Qux` into `<T as Foo>::Bar: Qux`. - let pred = trait_ref.without_const().to_predicate(tcx).to_string(); + let pred = trait_pred.to_predicate(tcx).to_string(); let pred = pred.replace(&impl_trait_str, &type_param_name); let mut sugg = vec![ // Find the last of the generic parameters contained within the span of @@ -301,19 +302,19 @@ fn suggest_restriction<'tcx>( .find(|p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: true, .. })), super_traits, ) { - (_, None) => predicate_constraint( - generics, - trait_ref.without_const().to_predicate(tcx).to_string(), + (_, None) => predicate_constraint(generics, trait_pred.to_predicate(tcx).to_string()), + (None, Some((ident, []))) => ( + ident.span.shrink_to_hi(), + format!(": {}", trait_pred.print_modifiers_and_trait_path()), + ), + (_, Some((_, [.., bounds]))) => ( + bounds.span().shrink_to_hi(), + format!(" + {}", trait_pred.print_modifiers_and_trait_path()), + ), + (Some(_), Some((_, []))) => ( + generics.span.shrink_to_hi(), + format!(": {}", trait_pred.print_modifiers_and_trait_path()), ), - (None, Some((ident, []))) => { - (ident.span.shrink_to_hi(), format!(": {}", trait_ref.print_only_trait_path())) - } - (_, Some((_, [.., bounds]))) => { - (bounds.span().shrink_to_hi(), format!(" + {}", trait_ref.print_only_trait_path())) - } - (Some(_), Some((_, []))) => { - (generics.span.shrink_to_hi(), format!(": {}", trait_ref.print_only_trait_path())) - } }; err.span_suggestion_verbose( @@ -329,10 +330,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn suggest_restricting_param_bound( &self, mut err: &mut DiagnosticBuilder<'_>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, body_id: hir::HirId, ) { - let self_ty = trait_ref.skip_binder().self_ty(); + let self_ty = trait_pred.skip_binder().self_ty(); let (param_ty, projection) = match self_ty.kind() { ty::Param(_) => (true, None), ty::Projection(projection) => (false, Some(projection)), @@ -358,7 +359,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err, None, projection, - trait_ref, + trait_pred, Some((ident, bounds)), ); return; @@ -372,7 +373,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { assert!(param_ty); // Restricting `Self` for a single method. suggest_restriction( - self.tcx, &generics, "`Self`", err, None, projection, trait_ref, None, + self.tcx, &generics, "`Self`", err, None, projection, trait_pred, None, ); return; } @@ -398,7 +399,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err, Some(fn_sig), projection, - trait_ref, + trait_pred, None, ); return; @@ -417,7 +418,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err, None, projection, - trait_ref, + trait_pred, None, ); return; @@ -442,15 +443,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { { // Missing generic type parameter bound. let param_name = self_ty.to_string(); - let constraint = - with_no_trimmed_paths(|| trait_ref.print_only_trait_path().to_string()); + let constraint = with_no_trimmed_paths(|| { + trait_pred.print_modifiers_and_trait_path().to_string() + }); if suggest_constraining_type_param( self.tcx, generics, &mut err, ¶m_name, &constraint, - Some(trait_ref.def_id()), + Some(trait_pred.def_id()), ) { return; } @@ -471,7 +473,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }) if !param_ty => { // Missing generic type parameter bound. let param_name = self_ty.to_string(); - let constraint = trait_ref.print_only_trait_path().to_string(); + let constraint = trait_pred.print_modifiers_and_trait_path().to_string(); if suggest_arbitrary_trait_bound(generics, &mut err, ¶m_name, &constraint) { return; } @@ -492,7 +494,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, ) { // It only make sense when suggesting dereferences for arguments let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } = @@ -505,13 +507,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let param_env = obligation.param_env; let body_id = obligation.cause.body_id; let span = obligation.cause.span; - let real_trait_ref = match &*code { + let real_trait_pred = match &*code { ObligationCauseCode::ImplDerivedObligation(cause) | ObligationCauseCode::DerivedObligation(cause) - | ObligationCauseCode::BuiltinDerivedObligation(cause) => cause.parent_trait_ref, - _ => trait_ref, + | ObligationCauseCode::BuiltinDerivedObligation(cause) => cause.parent_trait_pred, + _ => trait_pred, }; - let real_ty = match real_trait_ref.self_ty().no_bound_vars() { + let real_ty = match real_trait_pred.self_ty().no_bound_vars() { Some(ty) => ty, None => return, }; @@ -522,7 +524,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Re-add the `&` let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl }); let obligation = - self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_ref, ty); + self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred, ty); Some(steps).filter(|_| self.predicate_may_hold(&obligation)) }) { if steps > 0 { @@ -589,9 +591,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + trait_pred: ty::PolyTraitPredicate<'tcx>, ) { - let self_ty = match trait_ref.self_ty().no_bound_vars() { + let self_ty = match trait_pred.self_ty().no_bound_vars() { None => return, Some(ty) => ty, }; @@ -611,7 +613,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; let new_obligation = - self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_ref, output_ty); + self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred, output_ty); match self.evaluate_obligation(&new_obligation) { Ok( @@ -682,7 +684,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - poly_trait_ref: &ty::Binder<'tcx, ty::TraitRef<'tcx>>, + poly_trait_pred: ty::PolyTraitPredicate<'tcx>, has_custom_message: bool, ) -> bool { let span = obligation.cause.span; @@ -715,24 +717,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let param_env = obligation.param_env; // Try to apply the original trait binding obligation by borrowing. - let mut try_borrowing = |old_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>, blacklist: &[DefId]| -> bool { - if blacklist.contains(&old_ref.def_id()) { + if blacklist.contains(&old_pred.def_id()) { return false; } - let orig_ty = old_ref.self_ty().skip_binder(); + let orig_ty = old_pred.self_ty().skip_binder(); let mk_result = |new_ty| { - let new_ref = old_ref.rebind(ty::TraitRef::new( - old_ref.def_id(), - self.tcx.mk_substs_trait(new_ty, &old_ref.skip_binder().substs[1..]), - )); - self.predicate_must_hold_modulo_regions(&Obligation::new( - ObligationCause::dummy(), - param_env, - new_ref.without_const().to_predicate(self.tcx), - )) + let obligation = + self.mk_trait_obligation_with_new_self_ty(param_env, old_pred, new_ty); + self.predicate_must_hold_modulo_regions(&obligation) }; let imm_result = mk_result(self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, orig_ty)); let mut_result = mk_result(self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, orig_ty)); @@ -748,7 +744,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let msg = format!( "the trait bound `{}: {}` is not satisfied", orig_ty, - old_ref.print_only_trait_path(), + old_pred.print_modifiers_and_trait_path(), ); if has_custom_message { err.note(&msg); @@ -764,7 +760,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { span, &format!( "expected an implementor of trait `{}`", - old_ref.print_only_trait_path(), + old_pred.print_modifiers_and_trait_path(), ), ); @@ -806,11 +802,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; if let ObligationCauseCode::ImplDerivedObligation(obligation) = code { - try_borrowing(obligation.parent_trait_ref, &[]) + try_borrowing(obligation.parent_trait_pred, &[]) } else if let ObligationCauseCode::BindingObligation(_, _) | ObligationCauseCode::ItemObligation(_) = code { - try_borrowing(*poly_trait_ref, &never_suggest_borrow) + try_borrowing(poly_trait_pred, &never_suggest_borrow) } else { false } @@ -822,7 +818,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + trait_pred: ty::PolyTraitPredicate<'tcx>, ) { let span = obligation.cause.span; @@ -834,45 +830,44 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { return; } - let mut suggested_ty = match trait_ref.self_ty().no_bound_vars() { + let mut suggested_ty = match trait_pred.self_ty().no_bound_vars() { Some(ty) => ty, None => return, }; for refs_remaining in 0..refs_number { - if let ty::Ref(_, inner_ty, _) = suggested_ty.kind() { - suggested_ty = inner_ty; + let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else { + break; + }; + suggested_ty = inner_ty; - let new_obligation = self.mk_trait_obligation_with_new_self_ty( - obligation.param_env, - trait_ref, - suggested_ty, - ); + let new_obligation = self.mk_trait_obligation_with_new_self_ty( + obligation.param_env, + trait_pred, + suggested_ty, + ); - if self.predicate_may_hold(&new_obligation) { - let sp = self - .tcx - .sess - .source_map() - .span_take_while(span, |c| c.is_whitespace() || *c == '&'); + if self.predicate_may_hold(&new_obligation) { + let sp = self + .tcx + .sess + .source_map() + .span_take_while(span, |c| c.is_whitespace() || *c == '&'); - let remove_refs = refs_remaining + 1; + let remove_refs = refs_remaining + 1; - let msg = if remove_refs == 1 { - "consider removing the leading `&`-reference".to_string() - } else { - format!("consider removing {} leading `&`-references", remove_refs) - }; + let msg = if remove_refs == 1 { + "consider removing the leading `&`-reference".to_string() + } else { + format!("consider removing {} leading `&`-references", remove_refs) + }; - err.span_suggestion_short( - sp, - &msg, - String::new(), - Applicability::MachineApplicable, - ); - break; - } - } else { + err.span_suggestion_short( + sp, + &msg, + String::new(), + Applicability::MachineApplicable, + ); break; } } @@ -942,7 +937,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + trait_pred: ty::PolyTraitPredicate<'tcx>, ) { let points_at_arg = matches!( obligation.cause.code(), @@ -957,14 +952,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Do not suggest removal of borrow from type arguments. return; } - let trait_ref = self.resolve_vars_if_possible(trait_ref); - if trait_ref.has_infer_types_or_consts() { + let trait_pred = self.resolve_vars_if_possible(trait_pred); + if trait_pred.has_infer_types_or_consts() { // Do not ICE while trying to find if a reborrow would succeed on a trait with // unresolved bindings. return; } - if let ty::Ref(region, t_type, mutability) = *trait_ref.skip_binder().self_ty().kind() { + if let ty::Ref(region, t_type, mutability) = *trait_pred.skip_binder().self_ty().kind() + { if region.is_late_bound() || t_type.has_escaping_bound_vars() { // Avoid debug assertion in `mk_obligation_for_def_id`. // @@ -981,7 +977,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let new_obligation = self.mk_trait_obligation_with_new_self_ty( obligation.param_env, - trait_ref, + trait_pred, suggested_ty, ); let suggested_ty_would_satisfy_obligation = self @@ -1003,9 +999,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } else { err.note(&format!( "`{}` is implemented for `{:?}`, but not for `{:?}`", - trait_ref.print_only_trait_path(), + trait_pred.print_modifiers_and_trait_path(), suggested_ty, - trait_ref.skip_binder().self_ty(), + trait_pred.skip_binder().self_ty(), )); } } @@ -1018,7 +1014,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, span: Span, - trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + trait_pred: ty::PolyTraitPredicate<'tcx>, ) { let is_empty_tuple = |ty: ty::Binder<'tcx, Ty<'_>>| *ty.skip_binder().kind() == ty::Tuple(ty::List::empty()); @@ -1034,7 +1030,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let hir::ExprKind::Block(blk, _) = &body.value.kind { if sig.decl.output.span().overlaps(span) && blk.expr.is_none() - && is_empty_tuple(trait_ref.self_ty()) + && is_empty_tuple(trait_pred.self_ty()) { // FIXME(estebank): When encountering a method with a trait // bound not satisfied in the return type with a body that has @@ -1070,7 +1066,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'_>, span: Span, obligation: &PredicateObligation<'tcx>, - trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { match obligation.cause.code().peel_derives() { // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`. @@ -1089,8 +1085,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { return false; }; let body = hir.body(*body_id); - let trait_ref = self.resolve_vars_if_possible(trait_ref); - let ty = trait_ref.skip_binder().self_ty(); + let trait_pred = self.resolve_vars_if_possible(trait_pred); + let ty = trait_pred.skip_binder().self_ty(); let is_object_safe = match ty.kind() { ty::Dynamic(predicates, _) => { // If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`. @@ -1327,9 +1323,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { trait_ref.rebind(sig).to_string() } - let argument_kind = match expected_ref.skip_binder().substs.type_at(0) { - t if t.is_closure() => "closure", - t if t.is_generator() => "generator", + let argument_kind = match expected_ref.skip_binder().self_ty().kind() { + ty::Closure(..) => "closure", + ty::Generator(..) => "generator", _ => "function", }; let mut err = struct_span_err!( @@ -1368,7 +1364,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.span_suggestion( span, "use the fully qualified path to an implementation", - format!("<Type as {}>::{}", self.tcx.def_path_str(trait_ref), assoc_item.ident), + format!("<Type as {}>::{}", self.tcx.def_path_str(trait_ref), assoc_item.name), Applicability::HasPlaceholders, ); } @@ -1456,7 +1452,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // bound was introduced. At least one generator should be present for this diagnostic to be // modified. let (mut trait_ref, mut target_ty) = match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Trait(p) => (Some(p.trait_ref), Some(p.self_ty())), + ty::PredicateKind::Trait(p) => (Some(p), Some(p.self_ty())), _ => (None, None), }; let mut generator = None; @@ -1474,11 +1470,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ObligationCauseCode::DerivedObligation(derived_obligation) | ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) | ObligationCauseCode::ImplDerivedObligation(derived_obligation) => { - let ty = derived_obligation.parent_trait_ref.skip_binder().self_ty(); + let ty = derived_obligation.parent_trait_pred.skip_binder().self_ty(); debug!( "maybe_note_obligation_cause_for_async_await: \ parent_trait_ref={:?} self_ty.kind={:?}", - derived_obligation.parent_trait_ref, + derived_obligation.parent_trait_pred, ty.kind() ); @@ -1496,7 +1492,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { seen_upvar_tys_infer_tuple = true; } _ if generator.is_none() => { - trait_ref = Some(derived_obligation.parent_trait_ref.skip_binder()); + trait_ref = Some(derived_obligation.parent_trait_pred.skip_binder()); target_ty = Some(ty); } _ => {} @@ -1652,7 +1648,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>, inner_generator_body: Option<&hir::Body<'tcx>>, outer_generator: Option<DefId>, - trait_ref: ty::TraitRef<'tcx>, + trait_pred: ty::TraitPredicate<'tcx>, target_ty: Ty<'tcx>, typeck_results: Option<&ty::TypeckResults<'tcx>>, obligation: &PredicateObligation<'tcx>, @@ -1672,7 +1668,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // not implemented. let hir = self.tcx.hir(); let trait_explanation = if let Some(name @ (sym::Send | sym::Sync)) = - self.tcx.get_diagnostic_name(trait_ref.def_id) + self.tcx.get_diagnostic_name(trait_pred.def_id()) { let (trait_name, trait_verb) = if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") }; @@ -1714,7 +1710,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { format!("is not {}", trait_name) } else { - format!("does not implement `{}`", trait_ref.print_only_trait_path()) + format!("does not implement `{}`", trait_pred.print_modifiers_and_trait_path()) }; let mut explain_yield = |interior_span: Span, @@ -1895,6 +1891,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.note_obligation_cause_code( err, &obligation.predicate, + obligation.param_env, next_code.unwrap(), &mut Vec::new(), &mut Default::default(), @@ -1905,6 +1902,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, err: &mut DiagnosticBuilder<'_>, predicate: &T, + param_env: ty::ParamEnv<'tcx>, cause_code: &ObligationCauseCode<'tcx>, obligated_types: &mut Vec<&ty::TyS<'tcx>>, seen_requirements: &mut FxHashSet<DefId>, @@ -2135,7 +2133,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.note("shared static variables must have a type that implements `Sync`"); } ObligationCauseCode::BuiltinDerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref); + let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); let ty = parent_trait_ref.skip_binder().self_ty(); if parent_trait_ref.references_error() { err.cancel(); @@ -2150,7 +2148,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = *data.parent_code { - let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref); + let parent_trait_ref = + self.resolve_vars_if_possible(data.parent_trait_pred); let ty = parent_trait_ref.skip_binder().self_ty(); matches!(ty.kind(), ty::Generator(..)) || matches!(ty.kind(), ty::Closure(..)) @@ -2173,13 +2172,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligated_types.push(ty); - let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx); + let parent_predicate = parent_trait_ref.to_predicate(tcx); if !self.is_recursive_obligation(obligated_types, &data.parent_code) { // #74711: avoid a stack overflow ensure_sufficient_stack(|| { self.note_obligation_cause_code( err, &parent_predicate, + param_env, &data.parent_code, obligated_types, seen_requirements, @@ -2190,6 +2190,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.note_obligation_cause_code( err, &parent_predicate, + param_env, &cause_code.peel_derives(), obligated_types, seen_requirements, @@ -2198,17 +2199,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } ObligationCauseCode::ImplDerivedObligation(ref data) => { - let mut parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref); - let parent_def_id = parent_trait_ref.def_id(); + let mut parent_trait_pred = self.resolve_vars_if_possible(data.parent_trait_pred); + parent_trait_pred.remap_constness_diag(param_env); + let parent_def_id = parent_trait_pred.def_id(); let msg = format!( "required because of the requirements on the impl of `{}` for `{}`", - parent_trait_ref.print_only_trait_path(), - parent_trait_ref.skip_binder().self_ty() + parent_trait_pred.print_modifiers_and_trait_path(), + parent_trait_pred.skip_binder().self_ty() ); let mut candidates = vec![]; self.tcx.for_each_relevant_impl( parent_def_id, - parent_trait_ref.self_ty().skip_binder(), + parent_trait_pred.self_ty().skip_binder(), |impl_def_id| match self.tcx.hir().get_if_local(impl_def_id) { Some(Node::Item(hir::Item { kind: hir::ItemKind::Impl(hir::Impl { .. }), @@ -2237,21 +2239,21 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { _ => err.note(&msg), }; - let mut parent_predicate = parent_trait_ref.without_const().to_predicate(tcx); + let mut parent_predicate = parent_trait_pred.to_predicate(tcx); let mut data = data; let mut count = 0; seen_requirements.insert(parent_def_id); while let ObligationCauseCode::ImplDerivedObligation(child) = &*data.parent_code { // Skip redundant recursive obligation notes. See `ui/issue-20413.rs`. - let child_trait_ref = self.resolve_vars_if_possible(child.parent_trait_ref); - let child_def_id = child_trait_ref.def_id(); + let child_trait_pred = self.resolve_vars_if_possible(child.parent_trait_pred); + let child_def_id = child_trait_pred.def_id(); if seen_requirements.insert(child_def_id) { break; } count += 1; data = child; - parent_predicate = child_trait_ref.without_const().to_predicate(tcx); - parent_trait_ref = child_trait_ref; + parent_predicate = child_trait_pred.to_predicate(tcx); + parent_trait_pred = child_trait_pred; } if count > 0 { err.note(&format!( @@ -2261,8 +2263,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { )); err.note(&format!( "required because of the requirements on the impl of `{}` for `{}`", - parent_trait_ref.print_only_trait_path(), - parent_trait_ref.skip_binder().self_ty() + parent_trait_pred.print_modifiers_and_trait_path(), + parent_trait_pred.skip_binder().self_ty() )); } // #74711: avoid a stack overflow @@ -2270,6 +2272,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.note_obligation_cause_code( err, &parent_predicate, + param_env, &data.parent_code, obligated_types, seen_requirements, @@ -2277,13 +2280,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }); } ObligationCauseCode::DerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref); - let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx); + let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); + let parent_predicate = parent_trait_ref.to_predicate(tcx); // #74711: avoid a stack overflow ensure_sufficient_stack(|| { self.note_obligation_cause_code( err, &parent_predicate, + param_env, &data.parent_code, obligated_types, seen_requirements, @@ -2337,6 +2341,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.note_obligation_cause_code( err, predicate, + param_env, &parent_code, obligated_types, seen_requirements, @@ -2427,15 +2432,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, - trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + trait_pred: ty::PolyTraitPredicate<'tcx>, span: Span, ) { debug!( - "suggest_await_before_try: obligation={:?}, span={:?}, trait_ref={:?}, trait_ref_self_ty={:?}", + "suggest_await_before_try: obligation={:?}, span={:?}, trait_pred={:?}, trait_pred_self_ty={:?}", obligation, span, - trait_ref, - trait_ref.self_ty() + trait_pred, + trait_pred.self_ty() ); let body_hir_id = obligation.cause.body_id; let item_id = self.tcx.hir().get_parent_node(body_hir_id); @@ -2445,7 +2450,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { let future_trait = self.tcx.require_lang_item(LangItem::Future, None); - let self_ty = self.resolve_vars_if_possible(trait_ref.self_ty()); + let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); // Do not check on infer_types to avoid panic in evaluate_obligation. if self_ty.has_infer_types() { @@ -2465,7 +2470,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let projection_ty = ty::ProjectionTy { // `T` substs: self.tcx.mk_substs_trait( - trait_ref.self_ty().skip_binder(), + trait_pred.self_ty().skip_binder(), self.fresh_substs_for_item(span, item_def_id), ), // `Future::Output` @@ -2490,7 +2495,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ); let try_obligation = self.mk_trait_obligation_with_new_self_ty( obligation.param_env, - trait_ref, + trait_pred, normalized_ty, ); debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 23f534858b8..2927e64f705 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -291,7 +291,7 @@ pub fn normalize_param_env_or_error<'tcx>( // // In any case, in practice, typeck constructs all the // parameter environments once for every fn as it goes, - // and errors will get reported then; so after typeck we + // and errors will get reported then; so outside of type inference we // can be sure that no errors should occur. debug!( diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 7bfedecbdc7..7818053218d 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -89,7 +89,7 @@ fn object_safety_violations_for_trait( .filter(|item| item.kind == ty::AssocKind::Fn) .filter_map(|item| { object_safety_violation_for_method(tcx, trait_def_id, &item) - .map(|(code, span)| ObjectSafetyViolation::Method(item.ident.name, code, span)) + .map(|(code, span)| ObjectSafetyViolation::Method(item.name, code, span)) }) .filter(|violation| { if let ObjectSafetyViolation::Method( @@ -125,7 +125,10 @@ fn object_safety_violations_for_trait( tcx.associated_items(trait_def_id) .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Const) - .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)), + .map(|item| { + let ident = item.ident(tcx); + ObjectSafetyViolation::AssocConst(ident.name, ident.span) + }), ); violations.extend( @@ -133,7 +136,10 @@ fn object_safety_violations_for_trait( .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) .filter(|item| !tcx.generics_of(item.def_id).params.is_empty()) - .map(|item| ObjectSafetyViolation::GAT(item.ident.name, item.ident.span)), + .map(|item| { + let ident = item.ident(tcx); + ObjectSafetyViolation::GAT(ident.name, ident.span) + }), ); debug!( @@ -367,15 +373,15 @@ fn object_safety_violation_for_method( (MethodViolationCode::ReferencesSelfInput(arg), Some(node)) => node .fn_decl() .and_then(|decl| decl.inputs.get(arg + 1)) - .map_or(method.ident.span, |arg| arg.span), + .map_or(method.ident(tcx).span, |arg| arg.span), (MethodViolationCode::UndispatchableReceiver, Some(node)) => node .fn_decl() .and_then(|decl| decl.inputs.get(0)) - .map_or(method.ident.span, |arg| arg.span), + .map_or(method.ident(tcx).span, |arg| arg.span), (MethodViolationCode::ReferencesSelfOutput, Some(node)) => { - node.fn_decl().map_or(method.ident.span, |decl| decl.output.span()) + node.fn_decl().map_or(method.ident(tcx).span, |decl| decl.output.span()) } - _ => method.ident.span, + _ => method.ident(tcx).span, }; (v, span) }) @@ -404,10 +410,10 @@ fn virtual_call_violation_for_method<'tcx>( ); // Get the span pointing at where the `self` receiver should be. let sm = tcx.sess.source_map(); - let self_span = method.ident.span.to(tcx + let self_span = method.ident(tcx).span.to(tcx .hir() .span_if_local(method.def_id) - .unwrap_or_else(|| sm.next_point(method.ident.span)) + .unwrap_or_else(|| sm.next_point(method.ident(tcx).span)) .shrink_to_hi()); let self_span = sm.span_through_char(self_span, '(').shrink_to_hi(); return Some(MethodViolationCode::StaticMethod( diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs index 4840995275a..6b20476b955 100644 --- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs @@ -19,6 +19,7 @@ pub struct OnUnimplementedDirective { pub label: Option<OnUnimplementedFormatString>, pub note: Option<OnUnimplementedFormatString>, pub enclosing_scope: Option<OnUnimplementedFormatString>, + pub append_const_msg: Option<Option<Symbol>>, } #[derive(Default)] @@ -27,6 +28,11 @@ pub struct OnUnimplementedNote { pub label: Option<String>, pub note: Option<String>, pub enclosing_scope: Option<String>, + /// Append a message for `~const Trait` errors. `None` means not requested and + /// should fallback to a generic message, `Some(None)` suggests using the default + /// appended message, `Some(Some(s))` suggests use the `s` message instead of the + /// default one.. + pub append_const_msg: Option<Option<Symbol>>, } fn parse_error( @@ -89,6 +95,7 @@ impl<'tcx> OnUnimplementedDirective { let mut note = None; let mut enclosing_scope = None; let mut subcommands = vec![]; + let mut append_const_msg = None; let parse_value = |value_str| { OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some) @@ -131,6 +138,14 @@ impl<'tcx> OnUnimplementedDirective { } continue; } + } else if item.has_name(sym::append_const_msg) && append_const_msg.is_none() { + if let Some(msg) = item.value_str() { + append_const_msg = Some(Some(msg)); + continue; + } else if item.is_word() { + append_const_msg = Some(None); + continue; + } } // nothing found @@ -153,6 +168,7 @@ impl<'tcx> OnUnimplementedDirective { label, note, enclosing_scope, + append_const_msg, }) } } @@ -183,6 +199,7 @@ impl<'tcx> OnUnimplementedDirective { )?), note: None, enclosing_scope: None, + append_const_msg: None, })) } else { return Err(ErrorReported); @@ -201,6 +218,7 @@ impl<'tcx> OnUnimplementedDirective { let mut label = None; let mut note = None; let mut enclosing_scope = None; + let mut append_const_msg = None; info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options); for command in self.subcommands.iter().chain(Some(self)).rev() { @@ -235,6 +253,8 @@ impl<'tcx> OnUnimplementedDirective { if let Some(ref enclosing_scope_) = command.enclosing_scope { enclosing_scope = Some(enclosing_scope_.clone()); } + + append_const_msg = command.append_const_msg.clone(); } let options: FxHashMap<Symbol, String> = @@ -244,6 +264,7 @@ impl<'tcx> OnUnimplementedDirective { message: message.map(|m| m.format(tcx, trait_ref, &options)), note: note.map(|n| n.format(tcx, trait_ref, &options)), enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options)), + append_const_msg, } } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index f49f53351aa..087fc6034d9 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -391,7 +391,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { // severe performance implications for large opaque types with // late-bound regions. See `issue-88862` benchmark. ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { - // Only normalize `impl Trait` after type-checking, usually in codegen. + // Only normalize `impl Trait` outside of type inference, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty.super_fold_with(self), @@ -1600,7 +1600,7 @@ fn confirm_generator_candidate<'cx, 'tcx>( gen_sig, ) .map_bound(|(trait_ref, yield_ty, return_ty)| { - let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name; + let name = tcx.associated_item(obligation.predicate.item_def_id).name; let ty = if name == sym::Return { return_ty } else if name == sym::Yield { @@ -1842,7 +1842,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( // just return Error. debug!( "confirm_impl_candidate: no associated type {:?} for {:?}", - assoc_ty.item.ident, obligation.predicate + assoc_ty.item.name, obligation.predicate ); return Progress { ty: tcx.ty_error(), obligations: nested }; } diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 81ee22c1de4..3c9e1bbcef2 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -200,7 +200,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { // severe performance implications for large opaque types with // late-bound regions. See `issue-88862` benchmark. ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { - // Only normalize `impl Trait` after type-checking, usually in codegen. + // Only normalize `impl Trait` outside of type inference, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty.try_super_fold_with(self), diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index b573c4b4390..db86041f618 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -305,15 +305,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } else if lang_items.unsize_trait() == Some(def_id) { self.assemble_candidates_for_unsizing(obligation, &mut candidates); } else if lang_items.drop_trait() == Some(def_id) - && obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst + && obligation.predicate.is_const_if_const() { - if obligation.param_env.constness() == hir::Constness::Const { - self.assemble_const_drop_candidates(obligation, stack, &mut candidates)?; - } else { - debug!("passing ~const Drop bound; in non-const context"); - // `~const Drop` when we are not in a const context has no effect. - candidates.vec.push(ConstDropCandidate) - } + self.assemble_const_drop_candidates(obligation, &mut candidates); } else { if lang_items.clone_trait() == Some(def_id) { // Same builtin conditions as `Copy`, i.e., every type which has builtin support @@ -918,139 +912,77 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - fn assemble_const_drop_candidates<'a>( + fn assemble_const_drop_candidates( &mut self, obligation: &TraitObligation<'tcx>, - obligation_stack: &TraitObligationStack<'a, 'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - let mut stack: Vec<(Ty<'tcx>, usize)> = vec![(obligation.self_ty().skip_binder(), 0)]; - - while let Some((ty, depth)) = stack.pop() { - let mut noreturn = false; - - self.check_recursion_depth(depth, obligation)?; - let mut new_candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false }; - let mut copy_obligation = - obligation.with(obligation.predicate.rebind(ty::TraitPredicate { - trait_ref: ty::TraitRef { - def_id: self.tcx().require_lang_item(hir::LangItem::Copy, None), - substs: self.tcx().mk_substs_trait(ty, &[]), - }, - constness: ty::BoundConstness::NotConst, - polarity: ty::ImplPolarity::Positive, - })); - copy_obligation.recursion_depth = depth + 1; - self.assemble_candidates_from_impls(©_obligation, &mut new_candidates); - let copy_conditions = self.copy_clone_conditions(©_obligation); - self.assemble_builtin_bound_candidates(copy_conditions, &mut new_candidates); - let copy_stack = self.push_stack(obligation_stack.list(), ©_obligation); - self.assemble_candidates_from_caller_bounds(©_stack, &mut new_candidates)?; - - let const_drop_obligation = - obligation.with(obligation.predicate.rebind(ty::TraitPredicate { - trait_ref: ty::TraitRef { - def_id: self.tcx().require_lang_item(hir::LangItem::Drop, None), - substs: self.tcx().mk_substs_trait(ty, &[]), - }, - constness: ty::BoundConstness::ConstIfConst, - polarity: ty::ImplPolarity::Positive, - })); - - let const_drop_stack = self.push_stack(obligation_stack.list(), &const_drop_obligation); - self.assemble_candidates_from_caller_bounds(&const_drop_stack, &mut new_candidates)?; - - if !new_candidates.vec.is_empty() { - noreturn = true; - } - debug!(?new_candidates.vec, "assemble_const_drop_candidates"); - - match ty.kind() { - ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Infer(ty::IntVar(_)) - | ty::Infer(ty::FloatVar(_)) - | ty::FnPtr(_) - | ty::Never - | ty::Ref(..) - | ty::FnDef(..) - | ty::RawPtr(_) - | ty::Bool - | ty::Char - | ty::Str - | ty::Foreign(_) => {} // Do nothing. These types satisfy `const Drop`. - - ty::Adt(def, subst) => { - let mut set = SelectionCandidateSet { vec: Vec::new(), ambiguous: false }; - self.assemble_candidates_from_impls( - &obligation.with(obligation.predicate.map_bound(|mut pred| { - pred.trait_ref.substs = self.tcx().mk_substs_trait(ty, &[]); - pred - })), - &mut set, - ); - stack.extend(def.all_fields().map(|f| (f.ty(self.tcx(), subst), depth + 1))); - - debug!(?set.vec, "assemble_const_drop_candidates - ty::Adt"); - if set.vec.into_iter().any(|candidate| { - if let SelectionCandidate::ImplCandidate(did) = candidate { - matches!(self.tcx().impl_constness(did), hir::Constness::NotConst) - } else { - false - } - }) { - if !noreturn { - // has non-const Drop - return Ok(()); - } - debug!("not returning"); - } - } - - ty::Array(ty, _) => stack.push((ty, depth + 1)), - - ty::Tuple(_) => stack.extend(ty.tuple_fields().map(|t| (t, depth + 1))), + ) { + // If the predicate is `~const Drop` in a non-const environment, we don't actually need + // to check anything. We'll short-circuit checking any obligations in confirmation, too. + if obligation.param_env.constness() == hir::Constness::NotConst { + candidates.vec.push(ConstDropCandidate(None)); + return; + } - ty::Closure(_, substs) => { - let substs = substs.as_closure(); - let ty = self.infcx.shallow_resolve(substs.tupled_upvars_ty()); - stack.push((ty, depth + 1)); - } + let self_ty = self.infcx().shallow_resolve(obligation.self_ty()); + match self_ty.skip_binder().kind() { + ty::Opaque(..) + | ty::Dynamic(..) + | ty::Error(_) + | ty::Bound(..) + | ty::Param(_) + | ty::Placeholder(_) + | ty::Projection(_) => { + // We don't know if these are `~const Drop`, at least + // not structurally... so don't push a candidate. + } - ty::Generator(_, substs, _) => { - let substs = substs.as_generator(); - let ty = self.infcx.shallow_resolve(substs.tupled_upvars_ty()); + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Infer(ty::IntVar(_)) + | ty::Infer(ty::FloatVar(_)) + | ty::Str + | ty::RawPtr(_) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Never + | ty::Foreign(_) + | ty::Array(..) + | ty::Slice(_) + | ty::Closure(..) + | ty::Generator(..) + | ty::Tuple(_) + | ty::GeneratorWitness(_) => { + // These are built-in, and cannot have a custom `impl const Drop`. + candidates.vec.push(ConstDropCandidate(None)); + } - stack.push((ty, depth + 1)); - stack.push((substs.witness(), depth + 1)); - } + ty::Adt(..) => { + // Find a custom `impl Drop` impl, if it exists + let relevant_impl = self.tcx().find_map_relevant_impl( + obligation.predicate.def_id(), + obligation.predicate.skip_binder().trait_ref.self_ty(), + Some, + ); - ty::GeneratorWitness(tys) => stack.extend( - self.tcx().erase_late_bound_regions(*tys).iter().map(|t| (t, depth + 1)), - ), - - ty::Slice(ty) => stack.push((ty, depth + 1)), - - ty::Opaque(..) - | ty::Dynamic(..) - | ty::Error(_) - | ty::Bound(..) - | ty::Infer(_) - | ty::Placeholder(_) - | ty::Projection(..) - | ty::Param(..) => { - if !noreturn { - return Ok(()); + if let Some(impl_def_id) = relevant_impl { + // Check that `impl Drop` is actually const, if there is a custom impl + if self.tcx().impl_constness(impl_def_id) == hir::Constness::Const { + candidates.vec.push(ConstDropCandidate(Some(impl_def_id))); } - debug!("not returning"); + } else { + // Otherwise check the ADT like a built-in type (structurally) + candidates.vec.push(ConstDropCandidate(None)); } } - debug!(?stack, "assemble_const_drop_candidates - in loop"); - } - // all types have passed. - candidates.vec.push(ConstDropCandidate); - Ok(()) + ty::Infer(_) => { + candidates.ambiguous = true; + } + } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 669b6023397..639884844b2 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -72,15 +72,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // CheckPredicate(&A: Super) // CheckPredicate(A: ~const Super) // <- still const env, failure // ``` - if obligation.param_env.constness() == Constness::Const - && obligation.predicate.skip_binder().constness == ty::BoundConstness::NotConst - { + if obligation.param_env.is_const() && !obligation.predicate.is_const_if_const() { new_obligation = TraitObligation { cause: obligation.cause.clone(), param_env: obligation.param_env.without_const(), ..*obligation }; - obligation = &new_obligation; } @@ -159,7 +156,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(ImplSource::TraitUpcasting(data)) } - ConstDropCandidate => Ok(ImplSource::ConstDrop(ImplSourceConstDropData)), + ConstDropCandidate(def_id) => { + let data = self.confirm_const_drop_candidate(obligation, def_id)?; + Ok(ImplSource::ConstDrop(data)) + } } } @@ -657,7 +657,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => bug!("closure candidate for non-closure {:?}", obligation), }; - let obligation_predicate = obligation.predicate.to_poly_trait_ref(); + let obligation_predicate = obligation.predicate; let Normalized { value: obligation_predicate, mut obligations } = ensure_sufficient_stack(|| { normalize_with_depth( @@ -687,7 +687,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligations.extend(self.confirm_poly_trait_refs( obligation.cause.clone(), obligation.param_env, - obligation_predicate, + obligation_predicate.to_poly_trait_ref(), trait_ref, )?); @@ -1087,4 +1087,128 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(ImplSourceBuiltinData { nested }) } + + fn confirm_const_drop_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + impl_def_id: Option<DefId>, + ) -> Result<ImplSourceConstDropData<PredicateObligation<'tcx>>, SelectionError<'tcx>> { + // `~const Drop` in a non-const environment is always trivially true, since our type is `Drop` + if obligation.param_env.constness() == Constness::NotConst { + return Ok(ImplSourceConstDropData { nested: vec![] }); + } + + let tcx = self.tcx(); + let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); + + let mut nested = vec![]; + let cause = obligation.derived_cause(BuiltinDerivedObligation); + + // If we have a custom `impl const Drop`, then + // first check it like a regular impl candidate + if let Some(impl_def_id) = impl_def_id { + nested.extend(self.confirm_impl_candidate(obligation, impl_def_id).nested); + } + + // We want to confirm the ADT's fields if we have an ADT + let mut stack = match *self_ty.skip_binder().kind() { + ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(tcx, substs)).collect(), + _ => vec![self_ty.skip_binder()], + }; + + while let Some(nested_ty) = stack.pop() { + match *nested_ty.kind() { + // We know these types are trivially drop + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Infer(ty::IntVar(_)) + | ty::Infer(ty::FloatVar(_)) + | ty::Str + | ty::RawPtr(_) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Never + | ty::Foreign(_) => {} + + // These types are built-in, so we can fast-track by registering + // nested predicates for their constituient type(s) + ty::Array(ty, _) | ty::Slice(ty) => { + stack.push(ty); + } + ty::Tuple(tys) => { + stack.extend(tys.iter().map(|ty| ty.expect_ty())); + } + ty::Closure(_, substs) => { + stack.push(substs.as_closure().tupled_upvars_ty()); + } + ty::Generator(_, substs, _) => { + let generator = substs.as_generator(); + stack.extend([generator.tupled_upvars_ty(), generator.witness()]); + } + ty::GeneratorWitness(tys) => { + stack.extend(tcx.erase_late_bound_regions(tys).to_vec()); + } + + // If we have a projection type, make sure to normalize it so we replace it + // with a fresh infer variable + ty::Projection(..) => { + self.infcx.commit_unconditionally(|_| { + let predicate = normalize_with_depth_to( + self, + obligation.param_env, + cause.clone(), + obligation.recursion_depth + 1, + self_ty + .rebind(ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: self.tcx().require_lang_item(LangItem::Drop, None), + substs: self.tcx().mk_substs_trait(nested_ty, &[]), + }, + constness: ty::BoundConstness::ConstIfConst, + polarity: ty::ImplPolarity::Positive, + }) + .to_predicate(tcx), + &mut nested, + ); + + nested.push(Obligation::with_depth( + cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + predicate, + )); + }); + } + + // If we have any other type (e.g. an ADT), just register a nested obligation + // since it's either not `const Drop` (and we raise an error during selection), + // or it's an ADT (and we need to check for a custom impl during selection) + _ => { + let predicate = self_ty + .rebind(ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: self.tcx().require_lang_item(LangItem::Drop, None), + substs: self.tcx().mk_substs_trait(nested_ty, &[]), + }, + constness: ty::BoundConstness::ConstIfConst, + polarity: ty::ImplPolarity::Positive, + }) + .to_predicate(tcx); + + nested.push(Obligation::with_depth( + cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + predicate, + )); + } + } + } + + Ok(ImplSourceConstDropData { nested }) + } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 1414c742635..47427395b93 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -765,14 +765,38 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?result, "CACHE MISS"); self.insert_evaluation_cache(param_env, fresh_trait_pred, dep_node, result); - stack.cache().on_completion(stack.dfn, |fresh_trait_pred, provisional_result| { - self.insert_evaluation_cache( - param_env, - fresh_trait_pred, - dep_node, - provisional_result.max(result), - ); - }); + stack.cache().on_completion( + stack.dfn, + |fresh_trait_pred, provisional_result, provisional_dep_node| { + // Create a new `DepNode` that has dependencies on: + // * The `DepNode` for the original evaluation that resulted in a provisional cache + // entry being crated + // * The `DepNode` for the *current* evaluation, which resulted in us completing + // provisional caches entries and inserting them into the evaluation cache + // + // This ensures that when a query reads this entry from the evaluation cache, + // it will end up (transitively) dependening on all of the incr-comp dependencies + // created during the evaluation of this trait. For example, evaluating a trait + // will usually require us to invoke `type_of(field_def_id)` to determine the + // constituent types, and we want any queries reading from this evaluation + // cache entry to end up with a transitive `type_of(field_def_id`)` dependency. + // + // By using `in_task`, we're also creating an edge from the *current* query + // to the newly-created `combined_dep_node`. This is probably redundant, + // but it's better to add too many dep graph edges than to add too few + // dep graph edges. + let ((), combined_dep_node) = self.in_task(|this| { + this.tcx().dep_graph.read_index(provisional_dep_node); + this.tcx().dep_graph.read_index(dep_node); + }); + self.insert_evaluation_cache( + param_env, + fresh_trait_pred, + combined_dep_node, + provisional_result.max(result), + ); + }, + ); } else { debug!(?result, "PROVISIONAL"); debug!( @@ -781,7 +805,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fresh_trait_pred, stack.depth, reached_depth, ); - stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_pred, result); + stack.cache().insert_provisional( + stack.dfn, + reached_depth, + fresh_trait_pred, + result, + dep_node, + ); } Ok(result) @@ -1143,9 +1173,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplCandidate(def_id) if tcx.impl_constness(def_id) == hir::Constness::Const => {} // const param - ParamCandidate(trait_pred) - if trait_pred.skip_binder().constness - == ty::BoundConstness::ConstIfConst => {} + ParamCandidate(trait_pred) if trait_pred.is_const_if_const() => {} // auto trait impl AutoImplCandidate(..) => {} // generator, this will raise error in other places @@ -1153,7 +1181,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { GeneratorCandidate => {} // FnDef where the function is const FnPointerCandidate { is_const: true } => {} - ConstDropCandidate => {} + ConstDropCandidate(_) => {} _ => { // reject all other types of candidates continue; @@ -1537,7 +1565,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`, - // and `DiscriminantKindCandidate` to anything else. + // `DiscriminantKindCandidate`, and `ConstDropCandidate` to anything else. // // This is a fix for #53123 and prevents winnowing from accidentally extending the // lifetime of a variable. @@ -1554,7 +1582,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate | PointeeCandidate - | ConstDropCandidate, + | ConstDropCandidate(_), _, ) => true, ( @@ -1562,7 +1590,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate | PointeeCandidate - | ConstDropCandidate, + | ConstDropCandidate(_), ) => false, (ParamCandidate(other), ParamCandidate(victim)) => { @@ -2383,7 +2411,7 @@ impl<'tcx> TraitObligationExt<'tcx> for TraitObligation<'tcx> { // chain. Ideally, we should have a way to configure this either // by using -Z verbose or just a CLI argument. let derived_cause = DerivedObligationCause { - parent_trait_ref: obligation.predicate.to_poly_trait_ref(), + parent_trait_pred: obligation.predicate, parent_code: obligation.cause.clone_code(), }; let derived_code = variant(derived_cause); @@ -2506,6 +2534,11 @@ struct ProvisionalEvaluation { from_dfn: usize, reached_depth: usize, result: EvaluationResult, + /// The `DepNodeIndex` created for the `evaluate_stack` call for this provisional + /// evaluation. When we create an entry in the evaluation cache using this provisional + /// cache entry (see `on_completion`), we use this `dep_node` to ensure that future reads from + /// the cache will have all of the necessary incr comp dependencies tracked. + dep_node: DepNodeIndex, } impl<'tcx> Default for ProvisionalEvaluationCache<'tcx> { @@ -2548,6 +2581,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { reached_depth: usize, fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, result: EvaluationResult, + dep_node: DepNodeIndex, ) { debug!(?from_dfn, ?fresh_trait_pred, ?result, "insert_provisional"); @@ -2573,7 +2607,10 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { } } - map.insert(fresh_trait_pred, ProvisionalEvaluation { from_dfn, reached_depth, result }); + map.insert( + fresh_trait_pred, + ProvisionalEvaluation { from_dfn, reached_depth, result, dep_node }, + ); } /// Invoked when the node with dfn `dfn` does not get a successful @@ -2624,7 +2661,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { fn on_completion( &self, dfn: usize, - mut op: impl FnMut(ty::PolyTraitPredicate<'tcx>, EvaluationResult), + mut op: impl FnMut(ty::PolyTraitPredicate<'tcx>, EvaluationResult, DepNodeIndex), ) { debug!(?dfn, "on_completion"); @@ -2633,7 +2670,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { { debug!(?fresh_trait_pred, ?eval, "on_completion"); - op(fresh_trait_pred, eval.result); + op(fresh_trait_pred, eval.result, eval.dep_node); } } } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 195a4a4a653..2c5e7e40cc8 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -506,12 +506,21 @@ crate fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<St let mut pretty_predicates = Vec::with_capacity(predicates.len() + types_without_default_bounds.len()); - for (p, _) in predicates { + for (mut p, _) in predicates { if let Some(poly_trait_ref) = p.to_opt_poly_trait_pred() { if Some(poly_trait_ref.def_id()) == sized_trait { types_without_default_bounds.remove(poly_trait_ref.self_ty().skip_binder()); continue; } + + if ty::BoundConstness::ConstIfConst == poly_trait_ref.skip_binder().constness { + let new_trait_pred = poly_trait_ref.map_bound(|mut trait_pred| { + trait_pred.constness = ty::BoundConstness::NotConst; + trait_pred + }); + + p = tcx.mk_predicate(new_trait_pred.map_bound(ty::PredicateKind::Trait)) + } } pretty_predicates.push(p.to_string()); } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 6a355b567e0..493cb199f11 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -306,10 +306,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let extend = |obligation: traits::PredicateObligation<'tcx>| { let mut cause = cause.clone(); - if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_pred() { + if let Some(parent_trait_pred) = obligation.predicate.to_opt_poly_trait_pred() { let derived_cause = traits::DerivedObligationCause { - // FIXME(fee1-dead): when improving error messages, change this to PolyTraitPredicate - parent_trait_ref: parent_trait_ref.map_bound(|t| t.trait_ref), + parent_trait_pred, parent_code: obligation.cause.clone_code(), }; *cause.make_mut_code() = diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 781a639b09e..4142c999ca7 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -100,7 +100,7 @@ fn associated_item_from_trait_item_ref( }; ty::AssocItem { - ident: trait_item_ref.ident, + name: trait_item_ref.ident.name, kind, vis: tcx.visibility(def_id), defaultness: trait_item_ref.defaultness, @@ -124,7 +124,7 @@ fn associated_item_from_impl_item_ref( }; ty::AssocItem { - ident: impl_item_ref.ident, + name: impl_item_ref.ident.name, kind, vis: tcx.visibility(def_id), defaultness: impl_item_ref.defaultness, diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index fef83190468..b882a940d40 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -149,7 +149,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { // kind of an "idempotent" action, but I'm not sure where would be // a better place. In practice, we construct environments for // every fn once during type checking, and we'll abort if there - // are any errors at that point, so after type checking you can be + // are any errors at that point, so outside of type inference you can be // sure that this will succeed without errors anyway. if tcx.sess.opts.debugging_opts.chalk { diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs index b532c41642c..a49d6e24f26 100644 --- a/compiler/rustc_typeck/src/astconv/errors.rs +++ b/compiler/rustc_typeck/src/astconv/errors.rs @@ -214,7 +214,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .map(|r| self.tcx().associated_items(r.def_id()).in_definition_order()) .flatten() .filter_map( - |item| if item.kind == ty::AssocKind::Type { Some(item.ident.name) } else { None }, + |item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None }, ) .collect(); @@ -270,7 +270,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let trait_def_id = assoc_item.container.id(); names.push(format!( "`{}` (from trait `{}`)", - assoc_item.ident, + assoc_item.name, tcx.def_path_str(trait_def_id), )); } @@ -327,11 +327,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut names: FxHashMap<_, usize> = FxHashMap::default(); for item in assoc_items { types_count += 1; - *names.entry(item.ident.name).or_insert(0) += 1; + *names.entry(item.name).or_insert(0) += 1; } let mut dupes = false; for item in assoc_items { - let prefix = if names[&item.ident.name] > 1 { + let prefix = if names[&item.name] > 1 { let trait_def_id = item.container.id(); dupes = true; format!("{}::", tcx.def_path_str(trait_def_id)) @@ -339,7 +339,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { String::new() }; if let Some(sp) = tcx.hir().span_if_local(item.def_id) { - err.span_label(sp, format!("`{}{}` defined here", prefix, item.ident)); + err.span_label(sp, format!("`{}{}` defined here", prefix, item.name)); } } if potential_assoc_types.len() == assoc_items.len() { @@ -350,14 +350,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // `Iterator<Item = isize>`. for (potential, item) in iter::zip(&potential_assoc_types, assoc_items) { if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*potential) { - suggestions.push((*potential, format!("{} = {}", item.ident, snippet))); + suggestions.push((*potential, format!("{} = {}", item.name, snippet))); } } } else if let (Ok(snippet), false) = (tcx.sess.source_map().span_to_snippet(*span), dupes) { let types: Vec<_> = - assoc_items.iter().map(|item| format!("{} = Type", item.ident)).collect(); + assoc_items.iter().map(|item| format!("{} = Type", item.name)).collect(); let code = if snippet.ends_with('>') { // The user wrote `Trait<'a>` or similar and we don't have a type we can // suggest, but at least we can clue them to the correct syntax @@ -388,17 +388,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut names: FxHashMap<_, usize> = FxHashMap::default(); for item in assoc_items { types_count += 1; - *names.entry(item.ident.name).or_insert(0) += 1; + *names.entry(item.name).or_insert(0) += 1; } let mut label = vec![]; for item in assoc_items { - let postfix = if names[&item.ident.name] > 1 { + let postfix = if names[&item.name] > 1 { let trait_def_id = item.container.id(); format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id)) } else { String::new() }; - label.push(format!("`{}`{}", item.ident, postfix)); + label.push(format!("`{}`{}", item.name, postfix)); } if !label.is_empty() { err.span_label( diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 956696546da..05ff7f818c7 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -445,7 +445,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let named_type_param_count = param_counts.types - has_self as usize - synth_type_param_count; let infer_lifetimes = - gen_pos != GenericArgPosition::Type && !gen_args.has_lifetime_params(); + (gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params(); if gen_pos != GenericArgPosition::Type && !gen_args.bindings.is_empty() { Self::prohibit_assoc_ty_binding(tcx, gen_args.bindings[0].span); diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index d9b3f51b5bd..16fc9a01a27 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -482,7 +482,20 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) -> subst::GenericArg<'tcx> { let tcx = self.astconv.tcx(); match param.kind { - GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(), + GenericParamDefKind::Lifetime => self + .astconv + .re_infer(Some(param), self.span) + .unwrap_or_else(|| { + debug!(?param, "unelided lifetime in signature"); + + // This indicates an illegal lifetime in a non-assoc-trait position + tcx.sess.delay_span_bug(self.span, "unelided lifetime in signature"); + + // Supply some dummy value. We don't have an + // `re_error`, annoyingly, so use `'static`. + tcx.lifetimes.re_static + }) + .into(), GenericParamDefKind::Type { has_default, .. } => { if !infer_args && has_default { // No type parameter provided, but a default exists. @@ -1137,7 +1150,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .filter_by_name_unhygienic(assoc_ident.name) .find(|i| { (i.kind == ty::AssocKind::Type || i.kind == ty::AssocKind::Const) - && i.ident.normalize_to_macros_2_0() == assoc_ident + && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident }) .expect("missing associated type"); // FIXME(associated_const_equality): need to handle assoc_consts here as well. @@ -1176,7 +1189,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Include substitutions for generic parameters of associated types let projection_ty = candidate.map_bound(|trait_ref| { - let ident = Ident::new(assoc_ty.ident.name, binding.item_name.span); + let ident = Ident::new(assoc_ty.name, binding.item_name.span); let item_segment = hir::PathSegment { ident, hir_id: Some(binding.hir_id), @@ -1868,7 +1881,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .in_definition_order() .find(|i| { i.kind.namespace() == Namespace::TypeNS - && i.ident.normalize_to_macros_2_0() == assoc_ident + && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident }) .expect("missing associated type"); diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index eea8f40635d..0fea0afb572 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -307,6 +307,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Give appropriate suggestion when encountering `[("a", 0) ("b", 1)]`, where the + /// likely intention is to create an array containing tuples. + fn maybe_suggest_bad_array_definition( + &self, + err: &mut DiagnosticBuilder<'a>, + call_expr: &'tcx hir::Expr<'tcx>, + callee_expr: &'tcx hir::Expr<'tcx>, + ) -> bool { + let hir_id = self.tcx.hir().get_parent_node(call_expr.hir_id); + let parent_node = self.tcx.hir().get(hir_id); + if let ( + hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Array(_), .. }), + hir::ExprKind::Tup(exp), + hir::ExprKind::Call(_, args), + ) = (parent_node, &callee_expr.kind, &call_expr.kind) + { + if args.len() == exp.len() { + let start = callee_expr.span.shrink_to_hi(); + err.span_suggestion( + start, + "consider separating array elements with a comma", + ",".to_string(), + Applicability::MaybeIncorrect, + ); + return true; + } + } + false + } + fn confirm_builtin_call( &self, call_expr: &'tcx hir::Expr<'tcx>, @@ -422,7 +452,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => Res::Err, }; - err.span_label(call_expr.span, "call expression requires function"); + if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) { + err.span_label(call_expr.span, "call expression requires function"); + } if let Some(span) = self.tcx.hir().res_span(def) { let callee_ty = callee_ty.to_string(); diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index eb49cc0233d..18a0a8767d4 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -999,7 +999,7 @@ fn check_impl_items_against_trait<'tcx>( if is_implemented_here { let trait_item = tcx.associated_item(trait_item_id); - if required_items.contains(&trait_item.ident) { + if required_items.contains(&trait_item.ident(tcx)) { must_implement_one_of = None; } } diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 94648d5702c..74910234b7e 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -300,7 +300,7 @@ fn compare_predicate_entailment<'tcx>( cause.span(tcx), E0053, "method `{}` has an incompatible type for trait", - trait_m.ident + trait_m.name ); match &terr { TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0) @@ -452,7 +452,7 @@ fn check_region_bounds_on_impl_item<'tcx>( tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait { span, item_kind, - ident: impl_m.ident, + ident: impl_m.ident(tcx), generics_span, }); return Err(ErrorReported); @@ -540,14 +540,14 @@ fn compare_self_type<'tcx>( impl_m_span, E0185, "method `{}` has a `{}` declaration in the impl, but not in the trait", - trait_m.ident, + trait_m.name, self_descr ); err.span_label(impl_m_span, format!("`{}` used in impl", self_descr)); if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) { err.span_label(span, format!("trait method declared without `{}`", self_descr)); } else { - err.note_trait_signature(trait_m.ident.to_string(), trait_m.signature(tcx)); + err.note_trait_signature(trait_m.name.to_string(), trait_m.signature(tcx)); } err.emit(); return Err(ErrorReported); @@ -560,14 +560,14 @@ fn compare_self_type<'tcx>( impl_m_span, E0186, "method `{}` has a `{}` declaration in the trait, but not in the impl", - trait_m.ident, + trait_m.name, self_descr ); err.span_label(impl_m_span, format!("expected `{}` in impl", self_descr)); if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) { err.span_label(span, format!("`{}` used in trait", self_descr)); } else { - err.note_trait_signature(trait_m.ident.to_string(), trait_m.signature(tcx)); + err.note_trait_signature(trait_m.name.to_string(), trait_m.signature(tcx)); } err.emit(); return Err(ErrorReported); @@ -640,7 +640,7 @@ fn compare_number_of_generics<'tcx>( "{} `{}` has {} {kind} parameter{} but its trait \ declaration has {} {kind} parameter{}", item_kind, - trait_.ident, + trait_.name, impl_count, pluralize!(impl_count), trait_count, @@ -747,7 +747,7 @@ fn compare_number_of_method_arguments<'tcx>( impl_span, E0050, "method `{}` has {} but the declaration in trait `{}` has {}", - trait_m.ident, + trait_m.name, potentially_plural_count(impl_number_args, "parameter"), tcx.def_path_str(trait_m.def_id), trait_number_args @@ -761,7 +761,7 @@ fn compare_number_of_method_arguments<'tcx>( ), ); } else { - err.note_trait_signature(trait_m.ident.to_string(), trait_m.signature(tcx)); + err.note_trait_signature(trait_m.name.to_string(), trait_m.signature(tcx)); } err.span_label( impl_span, @@ -811,7 +811,7 @@ fn compare_synthetic_generics<'tcx>( impl_span, E0643, "method `{}` has incompatible signature for trait", - trait_m.ident + trait_m.name ); err.span_label(trait_span, "declaration in trait here"); match (impl_synthetic, trait_synthetic) { @@ -965,7 +965,7 @@ fn compare_const_param_types<'tcx>( *impl_span, E0053, "method `{}` has an incompatible const parameter type for trait", - trait_m.ident + trait_m.name ); err.span_note( trait_span.map_or_else(|| trait_item_span.unwrap_or(*impl_span), |span| *span), @@ -1053,7 +1053,7 @@ crate fn compare_const_impl<'tcx>( cause.span, E0326, "implemented const `{}` has an incompatible type for trait", - trait_c.ident + trait_c.name ); let trait_c_span = trait_c.def_id.as_local().map(|trait_c_def_id| { diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs index c8986aa7f53..89866c20b61 100644 --- a/compiler/rustc_typeck/src/check/dropck.rs +++ b/compiler/rustc_typeck/src/check/dropck.rs @@ -229,7 +229,13 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( let p = p.kind(); match (predicate.skip_binder(), p.skip_binder()) { (ty::PredicateKind::Trait(a), ty::PredicateKind::Trait(b)) => { - relator.relate(predicate.rebind(a), p.rebind(b)).is_ok() + // Since struct predicates cannot have ~const, project the impl predicate + // onto one that ignores the constness. This is equivalent to saying that + // we match a `Trait` bound on the struct with a `Trait` or `~const Trait` + // in the impl. + let non_const_a = + ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..a }; + relator.relate(predicate.rebind(non_const_a), p.rebind(b)).is_ok() } (ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => { relator.relate(predicate.rebind(a), p.rebind(b)).is_ok() diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 2cad8aab29e..0e1dbc53806 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -31,7 +31,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; -use rustc_hir::{ExprKind, QPath}; +use rustc_hir::{ExprKind, HirId, QPath}; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::InferOk; @@ -1970,7 +1970,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, expr_ty={:?}", field, base, expr, expr_t ); - let mut err = self.no_such_field_err(field, expr_t); + let mut err = self.no_such_field_err(field, expr_t, base.hir_id); match *expr_t.peel_refs().kind() { ty::Array(_, len) => { @@ -2209,6 +2209,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, field: Ident, expr_t: &'tcx ty::TyS<'tcx>, + id: HirId, ) -> DiagnosticBuilder<'_> { let span = field.span; debug!("no_such_field_err(span: {:?}, field: {:?}, expr_t: {:?})", span, field, expr_t); @@ -2226,9 +2227,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // try to add a suggestion in case the field is a nested field of a field of the Adt if let Some((fields, substs)) = self.get_field_candidates(span, &expr_t) { for candidate_field in fields.iter() { - if let Some(field_path) = - self.check_for_nested_field(span, field, candidate_field, substs, vec![]) - { + if let Some(field_path) = self.check_for_nested_field( + span, + field, + candidate_field, + substs, + vec![], + self.tcx.parent_module(id).to_def_id(), + ) { let field_path_str = field_path .iter() .map(|id| id.name.to_ident_string()) @@ -2280,6 +2286,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { candidate_field: &ty::FieldDef, subst: SubstsRef<'tcx>, mut field_path: Vec<Ident>, + id: DefId, ) -> Option<Vec<Ident>> { debug!( "check_for_nested_field(span: {:?}, candidate_field: {:?}, field_path: {:?}", @@ -2299,10 +2306,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let field_ty = candidate_field.ty(self.tcx, subst); if let Some((nested_fields, subst)) = self.get_field_candidates(span, &field_ty) { for field in nested_fields.iter() { - let ident = field.ident(self.tcx).normalize_to_macros_2_0(); - if ident == target_field { - return Some(field_path); - } else { + let accessible = field.vis.is_accessible_from(id, self.tcx); + if accessible { + let ident = field.ident(self.tcx).normalize_to_macros_2_0(); + if ident == target_field { + return Some(field_path); + } let field_path = field_path.clone(); if let Some(path) = self.check_for_nested_field( span, @@ -2310,6 +2319,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field, subst, field_path, + id, ) { return Some(path); } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index e42d94a6f40..1b93017c5aa 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -28,6 +28,11 @@ use crate::structured_errors::StructuredDiagnostic; use std::iter; use std::slice; +struct FnArgsAsTuple<'hir> { + first: &'hir hir::Expr<'hir>, + last: &'hir hir::Expr<'hir>, +} + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn check_casts(&self) { let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); @@ -127,136 +132,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expected_arg_count = formal_input_tys.len(); - let param_count_error = |expected_count: usize, - arg_count: usize, - error_code: &str, - c_variadic: bool, - sugg_unit: bool| { - let (span, start_span, args, ctor_of) = match &call_expr.kind { - hir::ExprKind::Call( - hir::Expr { - span, - kind: - hir::ExprKind::Path(hir::QPath::Resolved( - _, - hir::Path { res: Res::Def(DefKind::Ctor(of, _), _), .. }, - )), - .. - }, - args, - ) => (*span, *span, &args[..], Some(of)), - hir::ExprKind::Call(hir::Expr { span, .. }, args) => { - (*span, *span, &args[..], None) - } - hir::ExprKind::MethodCall(path_segment, args, _) => ( - path_segment.ident.span, - // `sp` doesn't point at the whole `foo.bar()`, only at `bar`. - path_segment - .args - .and_then(|args| args.args.iter().last()) - // Account for `foo.bar::<T>()`. - .map(|arg| { - // Skip the closing `>`. - tcx.sess - .source_map() - .next_point(tcx.sess.source_map().next_point(arg.span())) - }) - .unwrap_or(path_segment.ident.span), - &args[1..], // Skip the receiver. - None, // methods are never ctors - ), - k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k), - }; - let arg_spans = if provided_args.is_empty() { - // foo() - // ^^^-- supplied 0 arguments - // | - // expected 2 arguments - vec![tcx.sess.source_map().next_point(start_span).with_hi(call_span.hi())] - } else { - // foo(1, 2, 3) - // ^^^ - - - supplied 3 arguments - // | - // expected 2 arguments - args.iter().map(|arg| arg.span).collect::<Vec<Span>>() - }; - - let mut err = tcx.sess.struct_span_err_with_code( - span, - &format!( - "this {} takes {}{} but {} {} supplied", - match ctor_of { - Some(CtorOf::Struct) => "struct", - Some(CtorOf::Variant) => "enum variant", - None => "function", - }, - if c_variadic { "at least " } else { "" }, - potentially_plural_count(expected_count, "argument"), - potentially_plural_count(arg_count, "argument"), - if arg_count == 1 { "was" } else { "were" } - ), - DiagnosticId::Error(error_code.to_owned()), - ); - let label = format!("supplied {}", potentially_plural_count(arg_count, "argument")); - for (i, span) in arg_spans.into_iter().enumerate() { - err.span_label( - span, - if arg_count == 0 || i + 1 == arg_count { &label } else { "" }, - ); - } - - if let Some(def_id) = fn_def_id { - if let Some(def_span) = tcx.def_ident_span(def_id) { - let mut spans: MultiSpan = def_span.into(); - - let params = tcx - .hir() - .get_if_local(def_id) - .and_then(|node| node.body_id()) - .into_iter() - .map(|id| tcx.hir().body(id).params) - .flatten(); - - for param in params { - spans.push_span_label(param.span, String::new()); - } - - let def_kind = tcx.def_kind(def_id); - err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); - } - } - - if sugg_unit { - let sugg_span = tcx.sess.source_map().end_point(call_expr.span); - // remove closing `)` from the span - let sugg_span = sugg_span.shrink_to_lo(); - err.span_suggestion( - sugg_span, - "expected the unit value `()`; create it with empty parentheses", - String::from("()"), - Applicability::MachineApplicable, - ); - } else { - err.span_label( - span, - format!( - "expected {}{}", - if c_variadic { "at least " } else { "" }, - potentially_plural_count(expected_count, "argument") - ), - ); - } - err.emit(); - }; + // expected_count, arg_count, error_code, sugg_unit, sugg_tuple_wrap_args + let mut error: Option<(usize, usize, &str, bool, Option<FnArgsAsTuple<'_>>)> = None; + // If the arguments should be wrapped in a tuple (ex: closures), unwrap them here let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments { let tuple_type = self.structurally_resolved_type(call_span, formal_input_tys[0]); match tuple_type.kind() { - ty::Tuple(arg_types) if arg_types.len() != provided_args.len() => { - param_count_error(arg_types.len(), provided_args.len(), "E0057", false, false); - (self.err_args(provided_args.len()), vec![]) - } + // We expected a tuple and got a tuple ty::Tuple(arg_types) => { + // Argument length differs + if arg_types.len() != provided_args.len() { + error = Some((arg_types.len(), provided_args.len(), "E0057", false, None)); + } let expected_input_tys = match expected_input_tys.get(0) { Some(&ty) => match ty.kind() { ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(), @@ -267,6 +155,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (arg_types.iter().map(|k| k.expect_ty()).collect(), expected_input_tys) } _ => { + // Otherwise, there's a mismatch, so clear out what we're expecting, and set + // our input typs to err_args so we don't blow up the error messages struct_span_err!( tcx.sess, call_span, @@ -284,7 +174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if supplied_arg_count >= expected_arg_count { (formal_input_tys.to_vec(), expected_input_tys) } else { - param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false); + error = Some((expected_arg_count, supplied_arg_count, "E0060", false, None)); (self.err_args(supplied_arg_count), vec![]) } } else { @@ -296,8 +186,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { false }; - param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit); + // are we passing elements of a tuple without the tuple parentheses? + let expected_input_tys = if expected_input_tys.is_empty() { + // In most cases we can use expected_input_tys, but some callers won't have the type + // information, in which case we fall back to the types from the input expressions. + formal_input_tys + } else { + &*expected_input_tys + }; + + let sugg_tuple_wrap_args = self.suggested_tuple_wrap(expected_input_tys, provided_args); + + error = Some(( + expected_arg_count, + supplied_arg_count, + "E0061", + sugg_unit, + sugg_tuple_wrap_args, + )); (self.err_args(supplied_arg_count), vec![]) }; @@ -315,13 +222,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { assert_eq!(expected_input_tys.len(), formal_input_tys.len()); + let provided_arg_count: usize = provided_args.len(); + // Keep track of the fully coerced argument types - let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![]; + let mut final_arg_types: Vec<Option<(Ty<'_>, Ty<'_>)>> = vec![None; provided_arg_count]; // We introduce a helper function to demand that a given argument satisfy a given input // This is more complicated than just checking type equality, as arguments could be coerced // This version writes those types back so further type checking uses the narrowed types - let demand_compatible = |idx, final_arg_types: &mut Vec<(usize, Ty<'tcx>, Ty<'tcx>)>| { + let demand_compatible = |idx, final_arg_types: &mut Vec<Option<(Ty<'tcx>, Ty<'tcx>)>>| { let formal_input_ty: Ty<'tcx> = formal_input_tys[idx]; let expected_input_ty: Ty<'tcx> = expected_input_tys[idx]; let provided_arg = &provided_args[idx]; @@ -340,13 +249,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty); // Keep track of these for below - final_arg_types.push((idx, checked_ty, coerced_ty)); + final_arg_types[idx] = Some((checked_ty, coerced_ty)); // Cause selection errors caused by resolving a single argument to point at the // argument and not the call. This is otherwise redundant with the `demand_coerce` // call immediately after, but it lets us customize the span pointed to in the // fulfillment error to be more accurate. - let _ = + let coerced_ty = self.resolve_vars_with_obligations_and_mutate_fulfillment(coerced_ty, |errors| { self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr); self.point_at_arg_instead_of_call_if_possible( @@ -358,6 +267,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); }); + final_arg_types[idx] = Some((checked_ty, coerced_ty)); + // We're processing function arguments so we definitely want to use // two-phase borrows. self.demand_coerce(&provided_arg, checked_ty, coerced_ty, None, AllowTwoPhase::Yes); @@ -416,6 +327,133 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + // If there was an error in parameter count, emit that here + if let Some((expected_count, arg_count, err_code, sugg_unit, sugg_tuple_wrap_args)) = error + { + let (span, start_span, args, ctor_of) = match &call_expr.kind { + hir::ExprKind::Call( + hir::Expr { + span, + kind: + hir::ExprKind::Path(hir::QPath::Resolved( + _, + hir::Path { res: Res::Def(DefKind::Ctor(of, _), _), .. }, + )), + .. + }, + args, + ) => (*span, *span, &args[..], Some(of)), + hir::ExprKind::Call(hir::Expr { span, .. }, args) => { + (*span, *span, &args[..], None) + } + hir::ExprKind::MethodCall(path_segment, args, _) => ( + path_segment.ident.span, + // `sp` doesn't point at the whole `foo.bar()`, only at `bar`. + path_segment + .args + .and_then(|args| args.args.iter().last()) + // Account for `foo.bar::<T>()`. + .map(|arg| { + // Skip the closing `>`. + tcx.sess + .source_map() + .next_point(tcx.sess.source_map().next_point(arg.span())) + }) + .unwrap_or(path_segment.ident.span), + &args[1..], // Skip the receiver. + None, // methods are never ctors + ), + k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k), + }; + let arg_spans = if provided_args.is_empty() { + // foo() + // ^^^-- supplied 0 arguments + // | + // expected 2 arguments + vec![tcx.sess.source_map().next_point(start_span).with_hi(call_span.hi())] + } else { + // foo(1, 2, 3) + // ^^^ - - - supplied 3 arguments + // | + // expected 2 arguments + args.iter().map(|arg| arg.span).collect::<Vec<Span>>() + }; + let call_name = match ctor_of { + Some(CtorOf::Struct) => "struct", + Some(CtorOf::Variant) => "enum variant", + None => "function", + }; + let mut err = tcx.sess.struct_span_err_with_code( + span, + &format!( + "this {} takes {}{} but {} {} supplied", + call_name, + if c_variadic { "at least " } else { "" }, + potentially_plural_count(expected_count, "argument"), + potentially_plural_count(arg_count, "argument"), + if arg_count == 1 { "was" } else { "were" } + ), + DiagnosticId::Error(err_code.to_owned()), + ); + let label = format!("supplied {}", potentially_plural_count(arg_count, "argument")); + for (i, span) in arg_spans.into_iter().enumerate() { + err.span_label( + span, + if arg_count == 0 || i + 1 == arg_count { &label } else { "" }, + ); + } + if let Some(def_id) = fn_def_id { + if let Some(def_span) = tcx.def_ident_span(def_id) { + let mut spans: MultiSpan = def_span.into(); + + let params = tcx + .hir() + .get_if_local(def_id) + .and_then(|node| node.body_id()) + .into_iter() + .map(|id| tcx.hir().body(id).params) + .flatten(); + + for param in params { + spans.push_span_label(param.span, String::new()); + } + + let def_kind = tcx.def_kind(def_id); + err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); + } + } + if sugg_unit { + let sugg_span = tcx.sess.source_map().end_point(call_expr.span); + // remove closing `)` from the span + let sugg_span = sugg_span.shrink_to_lo(); + err.span_suggestion( + sugg_span, + "expected the unit value `()`; create it with empty parentheses", + String::from("()"), + Applicability::MachineApplicable, + ); + } else if let Some(FnArgsAsTuple { first, last }) = sugg_tuple_wrap_args { + err.multipart_suggestion( + "use parentheses to construct a tuple", + vec![ + (first.span.shrink_to_lo(), '('.to_string()), + (last.span.shrink_to_hi(), ')'.to_string()), + ], + Applicability::MachineApplicable, + ); + } else { + err.span_label( + span, + format!( + "expected {}{}", + if c_variadic { "at least " } else { "" }, + potentially_plural_count(expected_count, "argument") + ), + ); + } + err.emit(); + } + // We also need to make sure we at least write the ty of the other // arguments which we skipped above. if c_variadic { @@ -452,6 +490,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn suggested_tuple_wrap( + &self, + expected_input_tys: &[Ty<'tcx>], + provided_args: &'tcx [hir::Expr<'tcx>], + ) -> Option<FnArgsAsTuple<'_>> { + let [expected_arg_type] = &expected_input_tys[..] else { return None }; + + let ty::Tuple(expected_elems) = self.resolve_vars_if_possible(*expected_arg_type).kind() + else { return None }; + + let expected_types: Vec<_> = expected_elems.iter().map(|k| k.expect_ty()).collect(); + let supplied_types: Vec<_> = provided_args.iter().map(|arg| self.check_expr(arg)).collect(); + + let all_match = iter::zip(expected_types, supplied_types) + .all(|(expected, supplied)| self.can_eq(self.param_env, expected, supplied).is_ok()); + + if all_match { + match provided_args { + [] => None, + [_] => unreachable!( + "shouldn't reach here - need count mismatch between 1-tuple and 1-argument" + ), + [first, .., last] => Some(FnArgsAsTuple { first, last }), + } + } else { + None + } + } + // AST fragment checking pub(in super::super) fn check_lit( &self, @@ -975,7 +1042,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn point_at_arg_instead_of_call_if_possible( &self, errors: &mut Vec<traits::FulfillmentError<'tcx>>, - final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)], + final_arg_types: &[Option<(Ty<'tcx>, Ty<'tcx>)>], expr: &'tcx hir::Expr<'tcx>, call_sp: Span, args: &'tcx [hir::Expr<'tcx>], @@ -1016,7 +1083,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ObligationCauseCode::BuiltinDerivedObligation(code) | ObligationCauseCode::ImplDerivedObligation(code) | ObligationCauseCode::DerivedObligation(code) => { - code.parent_trait_ref.self_ty().skip_binder().into() + code.parent_trait_pred.self_ty().skip_binder().into() } _ if let ty::PredicateKind::Trait(predicate) = error.obligation.predicate.kind().skip_binder() => { @@ -1030,8 +1097,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `FulfillmentError`. let mut referenced_in = final_arg_types .iter() - .map(|&(i, checked_ty, _)| (i, checked_ty)) - .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty))) + .enumerate() + .filter_map(|(i, arg)| match arg { + Some((checked_ty, coerce_ty)) => Some([(i, *checked_ty), (i, *coerce_ty)]), + _ => None, + }) + .flatten() .flat_map(|(i, ty)| { let ty = self.resolve_vars_if_possible(ty); // We walk the argument type because the argument's type could have diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index be4c9ec99b9..86cf850d723 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -237,7 +237,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) { let mut suggestions = iter::zip(iter::repeat(&expr_text), &methods) .filter_map(|(receiver, method)| { - let method_call = format!(".{}()", method.ident); + let method_call = format!(".{}()", method.name); if receiver.ends_with(&method_call) { None // do not suggest code that is already there (#53348) } else { diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 56b6dd9a284..c6b92db88ae 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -22,6 +22,11 @@ use tracing::debug; mod drop_ranges; +// FIXME(eholk): This flag is here to give a quick way to disable drop tracking in case we find +// unexpected breakages while it's still new. It should be removed before too long. For example, +// see #93161. +const ENABLE_DROP_TRACKING: bool = false; + struct InteriorVisitor<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, types: FxIndexSet<ty::GeneratorInteriorTypeCause<'tcx>>, @@ -77,7 +82,10 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { yield_data.expr_and_pat_count, self.expr_count, source_span ); - if self.drop_ranges.is_dropped_at(hir_id, yield_data.expr_and_pat_count) + if ENABLE_DROP_TRACKING + && self + .drop_ranges + .is_dropped_at(hir_id, yield_data.expr_and_pat_count) { debug!("value is dropped at yield point; not recording"); return false; diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index 4c612ed5be5..74f6f50d412 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -297,6 +297,11 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::const_allocate => { (0, vec![tcx.types.usize, tcx.types.usize], tcx.mk_mut_ptr(tcx.types.u8)) } + sym::const_deallocate => ( + 0, + vec![tcx.mk_mut_ptr(tcx.types.u8), tcx.types.usize, tcx.types.usize], + tcx.mk_unit(), + ), sym::ptr_offset_from => { (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize) diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 86f3568d2e3..3815fd1992b 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -1033,7 +1033,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { true } }) - .map(|candidate| candidate.item.ident) + .map(|candidate| candidate.item.ident(self.tcx)) .filter(|&name| set.insert(name)) .collect(); @@ -1438,7 +1438,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { "<{} as {}>::{}", stable_pick.self_ty, self.tcx.def_path_str(def_id), - stable_pick.item.ident + stable_pick.item.name ), Applicability::MachineApplicable, ); @@ -1748,14 +1748,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let best_name = { let names = applicable_close_candidates .iter() - .map(|cand| cand.ident.name) + .map(|cand| cand.name) .collect::<Vec<Symbol>>(); find_best_match_for_name(&names, self.method_name.unwrap().name, None) } .unwrap(); - Ok(applicable_close_candidates - .into_iter() - .find(|method| method.ident.name == best_name)) + Ok(applicable_close_candidates.into_iter().find(|method| method.name == best_name)) } }) } @@ -1906,8 +1904,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { .associated_items(def_id) .in_definition_order() .filter(|x| { - let dist = lev_distance(name.as_str(), x.ident.as_str()); - x.kind.namespace() == Namespace::ValueNS && dist > 0 && dist <= max_dist + if x.kind.namespace() != Namespace::ValueNS { + return false; + } + match lev_distance(name.as_str(), x.name.as_str(), max_dist) { + Some(d) => d > 0, + None => false, + } }) .copied() .collect() diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 96ab800afaf..58ea197d3e9 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -823,9 +823,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => None, }) { - let parent_trait_ref = data.parent_trait_ref; + let parent_trait_ref = data.parent_trait_pred; let parent_def_id = parent_trait_ref.def_id(); - let path = parent_trait_ref.print_only_trait_path(); + let path = parent_trait_ref.print_modifiers_and_trait_path(); let tr_self_ty = parent_trait_ref.skip_binder().self_ty(); let mut candidates = vec![]; self.tcx.for_each_relevant_impl( @@ -1025,7 +1025,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { def_kind.article(), def_kind.descr(lev_candidate.def_id), ), - lev_candidate.ident.to_string(), + lev_candidate.name.to_string(), Applicability::MaybeIncorrect, ); } @@ -1480,7 +1480,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let skip = skippable.contains(&did); if pick.autoderefs == 0 && !skip { err.span_label( - pick.item.ident.span, + pick.item.ident(self.tcx).span, &format!("the method is available for `{}` here", rcvr_ty), ); } @@ -1514,7 +1514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // an autoderef to `&self` if pick.autoderefs == 0 && !skip { err.span_label( - pick.item.ident.span, + pick.item.ident(self.tcx).span, &format!("the method is available for `{}` here", new_rcvr_t), ); err.multipart_suggestion( diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 34caabe44d6..6e0b902a00b 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -599,7 +599,7 @@ fn missing_items_err( ) { let missing_items_msg = missing_items .iter() - .map(|trait_item| trait_item.ident.to_string()) + .map(|trait_item| trait_item.name.to_string()) .collect::<Vec<_>>() .join("`, `"); @@ -628,7 +628,7 @@ fn missing_items_err( let msg = format!("implement the missing item: `{}`", snippet); let appl = Applicability::HasPlaceholders; if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) { - err.span_label(span, format!("`{}` from trait", trait_item.ident)); + err.span_label(span, format!("`{}` from trait", trait_item.name)); err.tool_only_span_suggestion(sugg_sp, &msg, code, appl); } else { err.span_suggestion_hidden(sugg_sp, &msg, code, appl); @@ -805,16 +805,16 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String { fn_sig_suggestion( tcx, tcx.fn_sig(assoc.def_id).skip_binder(), - assoc.ident, + assoc.ident(tcx), tcx.predicates_of(assoc.def_id), assoc, ) } - ty::AssocKind::Type => format!("type {} = Type;", assoc.ident), + ty::AssocKind::Type => format!("type {} = Type;", assoc.name), ty::AssocKind::Const => { let ty = tcx.type_of(assoc.def_id); let val = expr::ty_kind_suggestion(ty).unwrap_or("value"); - format!("const {}: {} = {};", assoc.ident, ty, val) + format!("const {}: {} = {};", assoc.name, ty, val) } } } diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index c20c457de85..74516acbfcf 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -549,16 +549,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { is_assign: IsAssign, op: hir::BinOp, ) -> bool { - let source_map = self.tcx.sess.source_map(); - let remove_borrow_msg = "String concatenation appends the string on the right to the \ - string on the left and may require reallocation. This \ - requires ownership of the string on the left"; - - let msg = "`to_owned()` can be used to create an owned `String` \ - from a string reference. String concatenation \ - appends the string on the right to the string \ - on the left and may require reallocation. This \ - requires ownership of the string on the left"; + let str_concat_note = "string concatenation requires an owned `String` on the left"; + let rm_borrow_msg = "remove the borrow to obtain an owned `String`"; + let to_owned_msg = "create an owned `String` from a string reference"; let string_type = self.tcx.get_diagnostic_item(sym::String); let is_std_string = |ty: Ty<'tcx>| match ty.ty_adt_def() { @@ -574,31 +567,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) => { if let IsAssign::No = is_assign { // Do not supply this message if `&str += &str` - err.span_label( - op.span, - "`+` cannot be used to concatenate two `&str` strings", - ); - match source_map.span_to_snippet(lhs_expr.span) { - Ok(lstring) => { - err.span_suggestion( - lhs_expr.span, - if lstring.starts_with('&') { - remove_borrow_msg - } else { - msg - }, - if let Some(stripped) = lstring.strip_prefix('&') { - // let a = String::new(); - // let _ = &a + "bar"; - stripped.to_string() - } else { - format!("{}.to_owned()", lstring) - }, - Applicability::MachineApplicable, - ) - } - _ => err.help(msg), - }; + err.span_label(op.span, "`+` cannot be used to concatenate two `&str` strings"); + err.note(str_concat_note); + if let hir::ExprKind::AddrOf(_, _, lhs_inner_expr) = lhs_expr.kind { + err.span_suggestion_verbose( + lhs_expr.span.until(lhs_inner_expr.span), + rm_borrow_msg, + "".to_owned(), + Applicability::MachineApplicable + ); + } else { + err.span_suggestion_verbose( + lhs_expr.span.shrink_to_hi(), + to_owned_msg, + ".to_owned()".to_owned(), + Applicability::MachineApplicable + ); + } } true } @@ -609,32 +594,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { op.span, "`+` cannot be used to concatenate a `&str` with a `String`", ); - match ( - source_map.span_to_snippet(lhs_expr.span), - source_map.span_to_snippet(rhs_expr.span), - is_assign, - ) { - (Ok(l), Ok(r), IsAssign::No) => { - let to_string = if let Some(stripped) = l.strip_prefix('&') { - // let a = String::new(); let b = String::new(); - // let _ = &a + b; - stripped.to_string() + match is_assign { + IsAssign::No => { + let sugg_msg; + let lhs_sugg = if let hir::ExprKind::AddrOf(_, _, lhs_inner_expr) = lhs_expr.kind { + sugg_msg = "remove the borrow on the left and add one on the right"; + (lhs_expr.span.until(lhs_inner_expr.span), "".to_owned()) } else { - format!("{}.to_owned()", l) + sugg_msg = "create an owned `String` on the left and add a borrow on the right"; + (lhs_expr.span.shrink_to_hi(), ".to_owned()".to_owned()) }; - err.multipart_suggestion( - msg, - vec![ - (lhs_expr.span, to_string), - (rhs_expr.span, format!("&{}", r)), - ], + let suggestions = vec![ + lhs_sugg, + (rhs_expr.span.shrink_to_lo(), "&".to_owned()), + ]; + err.multipart_suggestion_verbose( + sugg_msg, + suggestions, Applicability::MachineApplicable, ); } - _ => { - err.help(msg); + IsAssign::Yes => { + err.note(str_concat_note); } - }; + } true } _ => false, diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 606a2d6a24e..71f45320e49 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -312,7 +312,7 @@ fn check_gat_where_clauses( // of the function signature. In our example, the GAT in the return // type is `<Self as LendingIterator>::Item<'a>`, so 'a and Self are arguments. let (regions, types) = - GATSubstCollector::visit(trait_item.def_id.to_def_id(), sig.output()); + GATSubstCollector::visit(tcx, trait_item.def_id.to_def_id(), sig.output()); // If both regions and types are empty, then this GAT isn't in the // return type, and we shouldn't try to do clause analysis @@ -602,6 +602,7 @@ fn resolve_regions_with_wf_tys<'tcx>( /// the two vectors, `regions` and `types` (depending on their kind). For each /// parameter `Pi` also track the index `i`. struct GATSubstCollector<'tcx> { + tcx: TyCtxt<'tcx>, gat: DefId, // Which region appears and which parameter index its subsituted for regions: FxHashSet<(ty::Region<'tcx>, usize)>, @@ -611,11 +612,16 @@ struct GATSubstCollector<'tcx> { impl<'tcx> GATSubstCollector<'tcx> { fn visit<T: TypeFoldable<'tcx>>( + tcx: TyCtxt<'tcx>, gat: DefId, t: T, ) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) { - let mut visitor = - GATSubstCollector { gat, regions: FxHashSet::default(), types: FxHashSet::default() }; + let mut visitor = GATSubstCollector { + tcx, + gat, + regions: FxHashSet::default(), + types: FxHashSet::default(), + }; t.visit_with(&mut visitor); (visitor.regions, visitor.types) } @@ -624,6 +630,13 @@ impl<'tcx> GATSubstCollector<'tcx> { impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> { type BreakTy = !; + fn visit_binder<T: TypeFoldable<'tcx>>( + &mut self, + t: &ty::Binder<'tcx, T>, + ) -> ControlFlow<Self::BreakTy> { + self.tcx.liberate_late_bound_regions(self.gat, t.clone()).visit_with(self) + } + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { match t.kind() { ty::Projection(p) if p.item_def_id == self.gat => { @@ -851,7 +864,7 @@ fn check_associated_item( let hir_sig = sig_if_method.expect("bad signature for method"); check_fn_or_method( fcx, - item.ident.span, + item.ident(fcx.tcx).span, sig, hir_sig.decl, item.def_id, diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs index 59f211bd2c3..a409201372b 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs @@ -36,7 +36,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { for item1 in impl_items1.in_definition_order() { let collision = impl_items2 - .filter_by_name_unhygienic(item1.ident.name) + .filter_by_name_unhygienic(item1.name) .any(|item2| self.compare_hygienically(item1, item2)); if collision { @@ -50,7 +50,8 @@ impl<'tcx> InherentOverlapChecker<'tcx> { fn compare_hygienically(&self, item1: &ty::AssocItem, item2: &ty::AssocItem) -> bool { // Symbols and namespace match, compare hygienically. item1.kind.namespace() == item2.kind.namespace() - && item1.ident.normalize_to_macros_2_0() == item2.ident.normalize_to_macros_2_0() + && item1.ident(self.tcx).normalize_to_macros_2_0() + == item2.ident(self.tcx).normalize_to_macros_2_0() } fn check_for_common_items_in_impls( @@ -64,11 +65,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> { for item1 in impl_items1.in_definition_order() { let collision = impl_items2 - .filter_by_name_unhygienic(item1.ident.name) + .filter_by_name_unhygienic(item1.name) .find(|item2| self.compare_hygienically(item1, item2)); if let Some(item2) = collision { - let name = item1.ident.normalize_to_macros_2_0(); + let name = item1.ident(self.tcx).normalize_to_macros_2_0(); let mut err = struct_span_err!( self.tcx.sess, self.tcx.span_of_impl(item1.def_id).unwrap(), @@ -181,11 +182,11 @@ impl<'tcx> ItemLikeVisitor<'_> for InherentOverlapChecker<'tcx> { let mut ids = impl_items .in_definition_order() .filter_map(|item| { - let entry = connected_region_ids.entry(item.ident.name); + let entry = connected_region_ids.entry(item.name); if let Entry::Occupied(e) = &entry { Some(*e.get()) } else { - idents_to_add.push(item.ident.name); + idents_to_add.push(item.name); None } }) diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 6fc6002d551..56a47001811 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -433,7 +433,7 @@ impl<T: Ord> BinaryHeap<T> { /// /// ``` /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::from(vec![1, 3]); + /// let mut heap = BinaryHeap::from([1, 3]); /// /// assert_eq!(heap.pop(), Some(3)); /// assert_eq!(heap.pop(), Some(1)); @@ -506,7 +506,7 @@ impl<T: Ord> BinaryHeap<T> { /// ``` /// use std::collections::BinaryHeap; /// - /// let mut heap = BinaryHeap::from(vec![1, 2, 4, 5, 7]); + /// let mut heap = BinaryHeap::from([1, 2, 4, 5, 7]); /// heap.push(6); /// heap.push(3); /// @@ -725,11 +725,8 @@ impl<T: Ord> BinaryHeap<T> { /// ``` /// use std::collections::BinaryHeap; /// - /// let v = vec![-10, 1, 2, 3, 3]; - /// let mut a = BinaryHeap::from(v); - /// - /// let v = vec![-20, 5, 43]; - /// let mut b = BinaryHeap::from(v); + /// let mut a = BinaryHeap::from([-10, 1, 2, 3, 3]); + /// let mut b = BinaryHeap::from([-20, 5, 43]); /// /// a.append(&mut b); /// @@ -765,7 +762,7 @@ impl<T: Ord> BinaryHeap<T> { /// #![feature(binary_heap_drain_sorted)] /// use std::collections::BinaryHeap; /// - /// let mut heap = BinaryHeap::from(vec![1, 2, 3, 4, 5]); + /// let mut heap = BinaryHeap::from([1, 2, 3, 4, 5]); /// assert_eq!(heap.len(), 5); /// /// drop(heap.drain_sorted()); // removes all elements in heap order @@ -790,7 +787,7 @@ impl<T: Ord> BinaryHeap<T> { /// #![feature(binary_heap_retain)] /// use std::collections::BinaryHeap; /// - /// let mut heap = BinaryHeap::from(vec![-10, -5, 1, 2, 4, 13]); + /// let mut heap = BinaryHeap::from([-10, -5, 1, 2, 4, 13]); /// /// heap.retain(|x| x % 2 == 0); // only keep even numbers /// @@ -826,7 +823,7 @@ impl<T> BinaryHeap<T> { /// /// ``` /// use std::collections::BinaryHeap; - /// let heap = BinaryHeap::from(vec![1, 2, 3, 4]); + /// let heap = BinaryHeap::from([1, 2, 3, 4]); /// /// // Print 1, 2, 3, 4 in arbitrary order /// for x in heap.iter() { @@ -848,9 +845,9 @@ impl<T> BinaryHeap<T> { /// ``` /// #![feature(binary_heap_into_iter_sorted)] /// use std::collections::BinaryHeap; - /// let heap = BinaryHeap::from(vec![1, 2, 3, 4, 5]); + /// let heap = BinaryHeap::from([1, 2, 3, 4, 5]); /// - /// assert_eq!(heap.into_iter_sorted().take(2).collect::<Vec<_>>(), vec![5, 4]); + /// assert_eq!(heap.into_iter_sorted().take(2).collect::<Vec<_>>(), [5, 4]); /// ``` #[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")] pub fn into_iter_sorted(self) -> IntoIterSorted<T> { @@ -1086,7 +1083,7 @@ impl<T> BinaryHeap<T> { /// use std::collections::BinaryHeap; /// use std::io::{self, Write}; /// - /// let heap = BinaryHeap::from(vec![1, 2, 3, 4, 5, 6, 7]); + /// let heap = BinaryHeap::from([1, 2, 3, 4, 5, 6, 7]); /// /// io::sink().write(heap.as_slice()).unwrap(); /// ``` @@ -1105,7 +1102,7 @@ impl<T> BinaryHeap<T> { /// /// ``` /// use std::collections::BinaryHeap; - /// let heap = BinaryHeap::from(vec![1, 2, 3, 4, 5, 6, 7]); + /// let heap = BinaryHeap::from([1, 2, 3, 4, 5, 6, 7]); /// let vec = heap.into_vec(); /// /// // Will print in some order @@ -1127,7 +1124,7 @@ impl<T> BinaryHeap<T> { /// /// ``` /// use std::collections::BinaryHeap; - /// let heap = BinaryHeap::from(vec![1, 3]); + /// let heap = BinaryHeap::from([1, 3]); /// /// assert_eq!(heap.len(), 2); /// ``` @@ -1171,7 +1168,7 @@ impl<T> BinaryHeap<T> { /// /// ``` /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::from(vec![1, 3]); + /// let mut heap = BinaryHeap::from([1, 3]); /// /// assert!(!heap.is_empty()); /// @@ -1195,7 +1192,7 @@ impl<T> BinaryHeap<T> { /// /// ``` /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::from(vec![1, 3]); + /// let mut heap = BinaryHeap::from([1, 3]); /// /// assert!(!heap.is_empty()); /// @@ -1616,7 +1613,7 @@ impl<T> IntoIterator for BinaryHeap<T> { /// /// ``` /// use std::collections::BinaryHeap; - /// let heap = BinaryHeap::from(vec![1, 2, 3, 4]); + /// let heap = BinaryHeap::from([1, 2, 3, 4]); /// /// // Print 1, 2, 3, 4 in arbitrary order /// for x in heap.into_iter() { diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 794b9356e7c..cdb961d4cfb 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1098,10 +1098,8 @@ impl<K, V> BTreeMap<K, V> { /// ``` /// use std::collections::BTreeMap; /// - /// let mut map: BTreeMap<&str, i32> = ["Alice", "Bob", "Carol", "Cheryl"] - /// .iter() - /// .map(|&s| (s, 0)) - /// .collect(); + /// let mut map: BTreeMap<&str, i32> = + /// [("Alice", 0), ("Bob", 0), ("Carol", 0), ("Cheryl", 0)].into(); /// for (_, balance) in map.range_mut("B".."Cheryl") { /// *balance += 100; /// } @@ -1135,7 +1133,7 @@ impl<K, V> BTreeMap<K, V> { /// let mut count: BTreeMap<&str, usize> = BTreeMap::new(); /// /// // count the number of occurrences of letters in the vec - /// for x in vec!["a", "b", "a", "c", "a", "b"] { + /// for x in ["a", "b", "a", "c", "a", "b"] { /// *count.entry(x).or_insert(0) += 1; /// } /// @@ -1235,8 +1233,8 @@ impl<K, V> BTreeMap<K, V> { /// let mut map: BTreeMap<i32, i32> = (0..8).map(|x| (x, x)).collect(); /// let evens: BTreeMap<_, _> = map.drain_filter(|k, _v| k % 2 == 0).collect(); /// let odds = map; - /// assert_eq!(evens.keys().copied().collect::<Vec<_>>(), vec![0, 2, 4, 6]); - /// assert_eq!(odds.keys().copied().collect::<Vec<_>>(), vec![1, 3, 5, 7]); + /// assert_eq!(evens.keys().copied().collect::<Vec<_>>(), [0, 2, 4, 6]); + /// assert_eq!(odds.keys().copied().collect::<Vec<_>>(), [1, 3, 5, 7]); /// ``` #[unstable(feature = "btree_drain_filter", issue = "70530")] pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F> diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 1259c53bfab..a8a18d65585 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -669,7 +669,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// ``` /// use std::collections::VecDeque; /// - /// let mut buf: VecDeque<i32> = [1].into_iter().collect(); + /// let mut buf: VecDeque<i32> = [1].into(); /// buf.reserve_exact(10); /// assert!(buf.capacity() >= 11); /// ``` @@ -692,7 +692,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// ``` /// use std::collections::VecDeque; /// - /// let mut buf: VecDeque<i32> = [1].into_iter().collect(); + /// let mut buf: VecDeque<i32> = [1].into(); /// buf.reserve(10); /// assert!(buf.capacity() >= 11); /// ``` @@ -1153,7 +1153,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// ``` /// use std::collections::VecDeque; /// - /// let v: VecDeque<_> = [1, 2, 3].into_iter().collect(); + /// let v: VecDeque<_> = [1, 2, 3].into(); /// let range = v.range(2..).copied().collect::<VecDeque<_>>(); /// assert_eq!(range, [3]); /// @@ -1188,17 +1188,17 @@ impl<T, A: Allocator> VecDeque<T, A> { /// ``` /// use std::collections::VecDeque; /// - /// let mut v: VecDeque<_> = [1, 2, 3].into_iter().collect(); + /// let mut v: VecDeque<_> = [1, 2, 3].into(); /// for v in v.range_mut(2..) { /// *v *= 2; /// } - /// assert_eq!(v, vec![1, 2, 6]); + /// assert_eq!(v, [1, 2, 6]); /// /// // A full range covers all contents /// for v in v.range_mut(..) { /// *v *= 2; /// } - /// assert_eq!(v, vec![2, 4, 12]); + /// assert_eq!(v, [2, 4, 12]); /// ``` #[inline] #[stable(feature = "deque_range", since = "1.51.0")] @@ -1235,7 +1235,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// ``` /// use std::collections::VecDeque; /// - /// let mut v: VecDeque<_> = [1, 2, 3].into_iter().collect(); + /// let mut v: VecDeque<_> = [1, 2, 3].into(); /// let drained = v.drain(2..).collect::<VecDeque<_>>(); /// assert_eq!(drained, [3]); /// assert_eq!(v, [1, 2]); @@ -2025,7 +2025,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// ``` /// use std::collections::VecDeque; /// - /// let mut buf: VecDeque<_> = [1, 2, 3].into_iter().collect(); + /// let mut buf: VecDeque<_> = [1, 2, 3].into(); /// let buf2 = buf.split_off(1); /// assert_eq!(buf, [1]); /// assert_eq!(buf2, [2, 3]); @@ -2091,8 +2091,8 @@ impl<T, A: Allocator> VecDeque<T, A> { /// ``` /// use std::collections::VecDeque; /// - /// let mut buf: VecDeque<_> = [1, 2].into_iter().collect(); - /// let mut buf2: VecDeque<_> = [3, 4].into_iter().collect(); + /// let mut buf: VecDeque<_> = [1, 2].into(); + /// let mut buf2: VecDeque<_> = [3, 4].into(); /// buf.append(&mut buf2); /// assert_eq!(buf, [1, 2, 3, 4]); /// assert_eq!(buf2, []); @@ -2547,7 +2547,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// ``` /// use std::collections::VecDeque; /// - /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); + /// let deque: VecDeque<_> = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); /// /// assert_eq!(deque.binary_search(&13), Ok(9)); /// assert_eq!(deque.binary_search(&4), Err(7)); @@ -2562,7 +2562,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// ``` /// use std::collections::VecDeque; /// - /// let mut deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); + /// let mut deque: VecDeque<_> = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); /// let num = 42; /// let idx = deque.binary_search(&num).unwrap_or_else(|x| x); /// deque.insert(idx, num); @@ -2605,7 +2605,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// ``` /// use std::collections::VecDeque; /// - /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); + /// let deque: VecDeque<_> = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); /// /// assert_eq!(deque.binary_search_by(|x| x.cmp(&13)), Ok(9)); /// assert_eq!(deque.binary_search_by(|x| x.cmp(&4)), Err(7)); @@ -2658,7 +2658,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// ``` /// use std::collections::VecDeque; /// - /// let deque: VecDeque<_> = vec![(0, 0), (2, 1), (4, 1), (5, 1), + /// let deque: VecDeque<_> = [(0, 0), (2, 1), (4, 1), (5, 1), /// (3, 1), (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), /// (1, 21), (2, 34), (4, 55)].into(); /// @@ -2701,7 +2701,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// ``` /// use std::collections::VecDeque; /// - /// let deque: VecDeque<_> = vec![1, 2, 3, 3, 5, 6, 7].into(); + /// let deque: VecDeque<_> = [1, 2, 3, 3, 5, 6, 7].into(); /// let i = deque.partition_point(|&x| x < 5); /// /// assert_eq!(i, 4); diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 1cbc2b65f4d..dfd3771c1d0 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -67,17 +67,14 @@ issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(allow(unused_variables), deny(warnings))) )] -#![cfg_attr( - not(bootstrap), - doc(cfg_hide( - not(test), - not(any(test, bootstrap)), - any(not(feature = "miri-test-libstd"), test, doctest), - no_global_oom_handling, - not(no_global_oom_handling), - target_has_atomic = "ptr" - )) -)] +#![doc(cfg_hide( + not(test), + not(any(test, bootstrap)), + any(not(feature = "miri-test-libstd"), test, doctest), + no_global_oom_handling, + not(no_global_oom_handling), + target_has_atomic = "ptr" +))] #![no_std] #![needs_allocator] // @@ -151,7 +148,6 @@ #![feature(const_precise_live_drops)] #![feature(const_trait_impl)] #![feature(const_try)] -#![cfg_attr(bootstrap, feature(destructuring_assignment))] #![feature(dropck_eyepatch)] #![feature(exclusive_range_pattern)] #![feature(fundamental)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 33bee4324fd..78bf28c843c 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -374,33 +374,51 @@ impl<T> Rc<T> { } } - /// Constructs a new `Rc<T>` using a weak reference to itself. Attempting - /// to upgrade the weak reference before this function returns will result - /// in a `None` value. However, the weak reference may be cloned freely and - /// stored for use at a later time. + /// Constructs a new `Rc<T>` using a closure `data_fn` that has access to a + /// weak reference to the constructing `Rc<T>`. + /// + /// Generally, a structure circularly referencing itself, either directly or + /// indirectly, should not hold a strong reference to prevent a memory leak. + /// In `data_fn`, initialization of `T` can make use of the weak reference + /// by cloning and storing it inside `T` for use at a later time. + /// + /// Since the new `Rc<T>` is not fully-constructed until `Rc<T>::new_cyclic` + /// returns, calling [`upgrade`] on the weak reference inside `data_fn` will + /// fail and result in a `None` value. + /// + /// # Panics + /// If `data_fn` panics, the panic is propagated to the caller, and the + /// temporary [`Weak<T>`] is dropped normally. /// /// # Examples /// /// ``` - /// #![feature(arc_new_cyclic)] /// #![allow(dead_code)] /// use std::rc::{Rc, Weak}; /// /// struct Gadget { - /// self_weak: Weak<Self>, - /// // ... more fields + /// me: Weak<Gadget>, /// } + /// /// impl Gadget { - /// pub fn new() -> Rc<Self> { - /// Rc::new_cyclic(|self_weak| { - /// Gadget { self_weak: self_weak.clone(), /* ... */ } - /// }) + /// /// Construct a reference counted Gadget. + /// fn new() -> Rc<Self> { + /// Rc::new_cyclic(|me| Gadget { me: me.clone() }) + /// } + /// + /// /// Return a reference counted pointer to Self. + /// fn me(&self) -> Rc<Self> { + /// self.me.upgrade().unwrap() /// } /// } /// ``` + /// [`upgrade`]: Weak::upgrade #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "arc_new_cyclic", issue = "75861")] - pub fn new_cyclic(data_fn: impl FnOnce(&Weak<T>) -> T) -> Rc<T> { + #[stable(feature = "arc_new_cyclic", since = "1.60.0")] + pub fn new_cyclic<F>(data_fn: F) -> Rc<T> + where + F: FnOnce(&Weak<T>) -> T, + { // Construct the inner in the "uninitialized" state with a single // weak reference. let uninit_ptr: NonNull<_> = Box::leak(box RcBox { @@ -451,12 +469,10 @@ impl<T> Rc<T> { /// /// let mut five = Rc::<u32>::new_uninit(); /// - /// let five = unsafe { - /// // Deferred initialization: - /// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); + /// // Deferred initialization: + /// Rc::get_mut(&mut five).unwrap().write(5); /// - /// five.assume_init() - /// }; + /// let five = unsafe { five.assume_init() }; /// /// assert_eq!(*five, 5) /// ``` @@ -543,12 +559,10 @@ impl<T> Rc<T> { /// /// let mut five = Rc::<u32>::try_new_uninit()?; /// - /// let five = unsafe { - /// // Deferred initialization: - /// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); + /// // Deferred initialization: + /// Rc::get_mut(&mut five).unwrap().write(5); /// - /// five.assume_init() - /// }; + /// let five = unsafe { five.assume_init() }; /// /// assert_eq!(*five, 5); /// # Ok::<(), std::alloc::AllocError>(()) @@ -660,14 +674,13 @@ impl<T> Rc<[T]> { /// /// let mut values = Rc::<[u32]>::new_uninit_slice(3); /// - /// let values = unsafe { - /// // Deferred initialization: - /// Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1); - /// Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2); - /// Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3); + /// // Deferred initialization: + /// let data = Rc::get_mut(&mut values).unwrap(); + /// data[0].write(1); + /// data[1].write(2); + /// data[2].write(3); /// - /// values.assume_init() - /// }; + /// let values = unsafe { values.assume_init() }; /// /// assert_eq!(*values, [1, 2, 3]) /// ``` @@ -738,12 +751,10 @@ impl<T> Rc<mem::MaybeUninit<T>> { /// /// let mut five = Rc::<u32>::new_uninit(); /// - /// let five = unsafe { - /// // Deferred initialization: - /// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); + /// // Deferred initialization: + /// Rc::get_mut(&mut five).unwrap().write(5); /// - /// five.assume_init() - /// }; + /// let five = unsafe { five.assume_init() }; /// /// assert_eq!(*five, 5) /// ``` @@ -777,14 +788,13 @@ impl<T> Rc<[mem::MaybeUninit<T>]> { /// /// let mut values = Rc::<[u32]>::new_uninit_slice(3); /// - /// let values = unsafe { - /// // Deferred initialization: - /// Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1); - /// Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2); - /// Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3); + /// // Deferred initialization: + /// let data = Rc::get_mut(&mut values).unwrap(); + /// data[0].write(1); + /// data[1].write(2); + /// data[2].write(3); /// - /// values.assume_init() - /// }; + /// let values = unsafe { values.assume_init() }; /// /// assert_eq!(*values, [1, 2, 3]) /// ``` diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 7c065f37d1f..64f21d087da 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -351,30 +351,51 @@ impl<T> Arc<T> { unsafe { Self::from_inner(Box::leak(x).into()) } } - /// Constructs a new `Arc<T>` using a weak reference to itself. Attempting - /// to upgrade the weak reference before this function returns will result - /// in a `None` value. However, the weak reference may be cloned freely and - /// stored for use at a later time. + /// Constructs a new `Arc<T>` using a closure `data_fn` that has access to + /// a weak reference to the constructing `Arc<T>`. /// - /// # Examples + /// Generally, a structure circularly referencing itself, either directly or + /// indirectly, should not hold a strong reference to prevent a memory leak. + /// In `data_fn`, initialization of `T` can make use of the weak reference + /// by cloning and storing it inside `T` for use at a later time. + /// + /// Since the new `Arc<T>` is not fully-constructed until + /// `Arc<T>::new_cyclic` returns, calling [`upgrade`] on the weak + /// reference inside `data_fn` will fail and result in a `None` value. + /// + /// # Panics + /// If `data_fn` panics, the panic is propagated to the caller, and the + /// temporary [`Weak<T>`] is dropped normally. + /// + /// # Example /// ``` - /// #![feature(arc_new_cyclic)] /// #![allow(dead_code)] - /// /// use std::sync::{Arc, Weak}; /// - /// struct Foo { - /// me: Weak<Foo>, + /// struct Gadget { + /// me: Weak<Gadget>, /// } /// - /// let foo = Arc::new_cyclic(|me| Foo { - /// me: me.clone(), - /// }); + /// impl Gadget { + /// /// Construct a reference counted Gadget. + /// fn new() -> Arc<Self> { + /// Arc::new_cyclic(|me| Gadget { me: me.clone() }) + /// } + /// + /// /// Return a reference counted pointer to Self. + /// fn me(&self) -> Arc<Self> { + /// self.me.upgrade().unwrap() + /// } + /// } /// ``` + /// [`upgrade`]: Weak::upgrade #[cfg(not(no_global_oom_handling))] #[inline] - #[unstable(feature = "arc_new_cyclic", issue = "75861")] - pub fn new_cyclic(data_fn: impl FnOnce(&Weak<T>) -> T) -> Arc<T> { + #[stable(feature = "arc_new_cyclic", since = "1.60.0")] + pub fn new_cyclic<F>(data_fn: F) -> Arc<T> + where + F: FnOnce(&Weak<T>) -> T, + { // Construct the inner in the "uninitialized" state with a single // weak reference. let uninit_ptr: NonNull<_> = Box::leak(box ArcInner { @@ -437,12 +458,10 @@ impl<T> Arc<T> { /// /// let mut five = Arc::<u32>::new_uninit(); /// - /// let five = unsafe { - /// // Deferred initialization: - /// Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); + /// // Deferred initialization: + /// Arc::get_mut(&mut five).unwrap().write(5); /// - /// five.assume_init() - /// }; + /// let five = unsafe { five.assume_init() }; /// /// assert_eq!(*five, 5) /// ``` @@ -545,12 +564,10 @@ impl<T> Arc<T> { /// /// let mut five = Arc::<u32>::try_new_uninit()?; /// - /// let five = unsafe { - /// // Deferred initialization: - /// Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); + /// // Deferred initialization: + /// Arc::get_mut(&mut five).unwrap().write(5); /// - /// five.assume_init() - /// }; + /// let five = unsafe { five.assume_init() }; /// /// assert_eq!(*five, 5); /// # Ok::<(), std::alloc::AllocError>(()) @@ -652,14 +669,13 @@ impl<T> Arc<[T]> { /// /// let mut values = Arc::<[u32]>::new_uninit_slice(3); /// - /// let values = unsafe { - /// // Deferred initialization: - /// Arc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1); - /// Arc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2); - /// Arc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3); + /// // Deferred initialization: + /// let data = Arc::get_mut(&mut values).unwrap(); + /// data[0].write(1); + /// data[1].write(2); + /// data[2].write(3); /// - /// values.assume_init() - /// }; + /// let values = unsafe { values.assume_init() }; /// /// assert_eq!(*values, [1, 2, 3]) /// ``` @@ -730,12 +746,10 @@ impl<T> Arc<mem::MaybeUninit<T>> { /// /// let mut five = Arc::<u32>::new_uninit(); /// - /// let five = unsafe { - /// // Deferred initialization: - /// Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); + /// // Deferred initialization: + /// Arc::get_mut(&mut five).unwrap().write(5); /// - /// five.assume_init() - /// }; + /// let five = unsafe { five.assume_init() }; /// /// assert_eq!(*five, 5) /// ``` @@ -770,14 +784,13 @@ impl<T> Arc<[mem::MaybeUninit<T>]> { /// /// let mut values = Arc::<[u32]>::new_uninit_slice(3); /// - /// let values = unsafe { - /// // Deferred initialization: - /// Arc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1); - /// Arc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2); - /// Arc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3); + /// // Deferred initialization: + /// let data = Arc::get_mut(&mut values).unwrap(); + /// data[0].write(1); + /// data[1].write(2); + /// data[2].write(3); /// - /// values.assume_init() - /// }; + /// let values = unsafe { values.assume_init() }; /// /// assert_eq!(*values, [1, 2, 3]) /// ``` diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index bc3f7167fac..5fd60b75928 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1310,11 +1310,7 @@ impl Clone for BorrowRef<'_> { /// /// See the [module-level documentation](self) for more. #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr( - not(bootstrap), - must_not_suspend = "holding a Ref across suspend \ - points can cause BorrowErrors" -)] +#[must_not_suspend = "holding a Ref across suspend points can cause BorrowErrors"] pub struct Ref<'b, T: ?Sized + 'b> { value: &'b T, borrow: BorrowRef<'b>, @@ -1692,11 +1688,7 @@ impl<'b> BorrowRefMut<'b> { /// /// See the [module-level documentation](self) for more. #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr( - not(bootstrap), - must_not_suspend = "holding a RefMut across suspend \ - points can cause BorrowErrors" -)] +#[must_not_suspend = "holding a RefMut across suspend points can cause BorrowErrors"] pub struct RefMut<'b, T: ?Sized + 'b> { value: &'b mut T, borrow: BorrowRefMut<'b>, diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index f89cf812e97..a3e77479911 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -199,9 +199,20 @@ use self::Ordering::*; #[stable(feature = "rust1", since = "1.0.0")] #[doc(alias = "==")] #[doc(alias = "!=")] -#[rustc_on_unimplemented( - message = "can't compare `{Self}` with `{Rhs}`", - label = "no implementation for `{Self} == {Rhs}`" +#[cfg_attr( + bootstrap, + rustc_on_unimplemented( + message = "can't compare `{Self}` with `{Rhs}`", + label = "no implementation for `{Self} == {Rhs}`" + ) +)] +#[cfg_attr( + not(bootstrap), + rustc_on_unimplemented( + message = "can't compare `{Self}` with `{Rhs}`", + label = "no implementation for `{Self} == {Rhs}`", + append_const_msg, + ) )] #[rustc_diagnostic_item = "PartialEq"] pub trait PartialEq<Rhs: ?Sized = Self> { @@ -869,7 +880,7 @@ impl PartialOrd for Ordering { } } -/// Trait for values that can be compared for a sort-order. +/// Trait for types that form a [partial order](https://en.wikipedia.org/wiki/Partial_order). /// /// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using /// the `<`, `<=`, `>`, and `>=` operators, respectively. @@ -1031,9 +1042,20 @@ impl PartialOrd for Ordering { #[doc(alias = "<")] #[doc(alias = "<=")] #[doc(alias = ">=")] -#[rustc_on_unimplemented( - message = "can't compare `{Self}` with `{Rhs}`", - label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" +#[cfg_attr( + bootstrap, + rustc_on_unimplemented( + message = "can't compare `{Self}` with `{Rhs}`", + label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`", + ) +)] +#[cfg_attr( + not(bootstrap), + rustc_on_unimplemented( + message = "can't compare `{Self}` with `{Rhs}`", + label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`", + append_const_msg, + ) )] #[rustc_diagnostic_item = "PartialOrd"] pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 8a2a64f8dc9..e1ea9881303 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -308,9 +308,21 @@ static USIZE_MARKER: fn(&usize, &mut Formatter<'_>) -> Result = |ptr, _| { loop {} }; +macro_rules! arg_new { + ($f: ident, $t: ident) => { + #[doc(hidden)] + #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] + #[inline] + pub fn $f<'b, T: $t>(x: &'b T) -> ArgumentV1<'_> { + Self::new(x, $t::fmt) + } + }; +} + impl<'a> ArgumentV1<'a> { #[doc(hidden)] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] + #[inline] pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> ArgumentV1<'b> { // SAFETY: `mem::transmute(x)` is safe because // 1. `&'b T` keeps the lifetime it originated with `'b` @@ -323,6 +335,16 @@ impl<'a> ArgumentV1<'a> { unsafe { ArgumentV1 { formatter: mem::transmute(f), value: mem::transmute(x) } } } + arg_new!(new_display, Display); + arg_new!(new_debug, Debug); + arg_new!(new_octal, Octal); + arg_new!(new_lower_hex, LowerHex); + arg_new!(new_upper_hex, UpperHex); + arg_new!(new_pointer, Pointer); + arg_new!(new_binary, Binary); + arg_new!(new_lower_exp, LowerExp); + arg_new!(new_upper_exp, UpperExp); + #[doc(hidden)] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] pub fn from_usize(x: &usize) -> ArgumentV1<'_> { diff --git a/library/core/src/future/into_future.rs b/library/core/src/future/into_future.rs index cac1866188e..0912f8675fa 100644 --- a/library/core/src/future/into_future.rs +++ b/library/core/src/future/into_future.rs @@ -13,7 +13,7 @@ pub trait IntoFuture { /// Creates a future from a value. #[unstable(feature = "into_future", issue = "67644")] - #[cfg_attr(not(bootstrap), lang = "into_future")] + #[lang = "into_future"] fn into_future(self) -> Self::Future; } diff --git a/library/core/src/future/join.rs b/library/core/src/future/join.rs index a6ffbe07d91..fa4eb0d2f33 100644 --- a/library/core/src/future/join.rs +++ b/library/core/src/future/join.rs @@ -9,7 +9,7 @@ use crate::task::{Context, Poll}; /// Polls multiple futures simultaneously, returning a tuple /// of all results once complete. /// -/// While `join!(a, b)` is similar to `(a.await, b.await)`, +/// While `join!(a, b).await` is similar to `(a.await, b.await)`, /// `join!` polls both futures concurrently and is therefore more efficient. /// /// # Examples diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 9781dc320ed..b5228397f0a 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1914,10 +1914,31 @@ extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool; - /// Allocate at compile time. Should not be called at runtime. + /// Allocates a block of memory at compile time. + /// At runtime, just returns a null pointer. + /// + /// # Safety + /// + /// - The `align` argument must be a power of two. + /// - At compile time, a compile error occurs if this constraint is violated. + /// - At runtime, it is not checked. #[rustc_const_unstable(feature = "const_heap", issue = "79597")] pub fn const_allocate(size: usize, align: usize) -> *mut u8; + /// Deallocates a memory which allocated by `intrinsics::const_allocate` at compile time. + /// At runtime, does nothing. + /// + /// # Safety + /// + /// - The `align` argument must be a power of two. + /// - At compile time, a compile error occurs if this constraint is violated. + /// - At runtime, it is not checked. + /// - If the `ptr` is created in an another const, this intrinsic doesn't deallocate it. + /// - If the `ptr` is pointing to a local variable, this intrinsic doesn't deallocate it. + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + #[cfg(not(bootstrap))] + pub fn const_deallocate(ptr: *mut u8, size: usize, align: usize); + /// Determines whether the raw bytes of the two values are equal. /// /// This is particularly handy for arrays, since it allows things like just diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 1d947297463..a8fe5f59bae 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -515,8 +515,44 @@ pub trait Iterator { /// assert_eq!((2, 'o'), zipper[2]); /// ``` /// + /// If both iterators have roughly equivalent syntax, it may be more readable to use [`zip`]: + /// + /// ``` + /// use std::iter::zip; + /// + /// let a = [1, 2, 3]; + /// let b = [2, 3, 4]; + /// + /// let mut zipped = zip( + /// a.into_iter().map(|x| x * 2).skip(1), + /// b.into_iter().map(|x| x * 2).skip(1), + /// ); + /// + /// assert_eq!(zipped.next(), Some((4, 6))); + /// assert_eq!(zipped.next(), Some((6, 8))); + /// assert_eq!(zipped.next(), None); + /// ``` + /// + /// compared to: + /// + /// ``` + /// # let a = [1, 2, 3]; + /// # let b = [2, 3, 4]; + /// # + /// let mut zipped = a + /// .into_iter() + /// .map(|x| x * 2) + /// .skip(1) + /// .zip(b.into_iter().map(|x| x * 2).skip(1)); + /// # + /// # assert_eq!(zipped.next(), Some((4, 6))); + /// # assert_eq!(zipped.next(), Some((6, 8))); + /// # assert_eq!(zipped.next(), None); + /// ``` + /// /// [`enumerate`]: Iterator::enumerate /// [`next`]: Iterator::next + /// [`zip`]: crate::iter::zip #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn zip<U>(self, other: U) -> Zip<Self, U::IntoIter> diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index d8ac816fb15..e52d52e954c 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -60,32 +60,29 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] -#![cfg_attr( - not(bootstrap), - doc(cfg_hide( - not(test), - any(not(feature = "miri-test-libstd"), test, doctest), - no_fp_fmt_parse, - target_pointer_width = "16", - target_pointer_width = "32", - target_pointer_width = "64", - target_has_atomic = "8", - target_has_atomic = "16", - target_has_atomic = "32", - target_has_atomic = "64", - target_has_atomic = "ptr", - target_has_atomic_equal_alignment = "8", - target_has_atomic_equal_alignment = "16", - target_has_atomic_equal_alignment = "32", - target_has_atomic_equal_alignment = "64", - target_has_atomic_equal_alignment = "ptr", - target_has_atomic_load_store = "8", - target_has_atomic_load_store = "16", - target_has_atomic_load_store = "32", - target_has_atomic_load_store = "64", - target_has_atomic_load_store = "ptr", - )) -)] +#![doc(cfg_hide( + not(test), + any(not(feature = "miri-test-libstd"), test, doctest), + no_fp_fmt_parse, + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64", + target_has_atomic = "8", + target_has_atomic = "16", + target_has_atomic = "32", + target_has_atomic = "64", + target_has_atomic = "ptr", + target_has_atomic_equal_alignment = "8", + target_has_atomic_equal_alignment = "16", + target_has_atomic_equal_alignment = "32", + target_has_atomic_equal_alignment = "64", + target_has_atomic_equal_alignment = "ptr", + target_has_atomic_load_store = "8", + target_has_atomic_load_store = "16", + target_has_atomic_load_store = "32", + target_has_atomic_load_store = "64", + target_has_atomic_load_store = "ptr", +))] #![no_core] // // Lints: @@ -374,6 +371,12 @@ pub mod arch { pub use crate::core_arch::arch::*; /// Inline assembly. + /// + /// Refer to [rust by example] for a usage guide and the [reference] for + /// detailed information about the syntax and available options. + /// + /// [rust by example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html + /// [reference]: https://doc.rust-lang.org/nightly/reference/inline-assembly.html #[stable(feature = "asm", since = "1.59.0")] #[rustc_builtin_macro] pub macro asm("assembly template", $(operands,)* $(options($(option),*))?) { @@ -381,6 +384,12 @@ pub mod arch { } /// Module-level inline assembly. + /// + /// Refer to [rust by example] for a usage guide and the [reference] for + /// detailed information about the syntax and available options. + /// + /// [rust by example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html + /// [reference]: https://doc.rust-lang.org/nightly/reference/inline-assembly.html #[stable(feature = "global_asm", since = "1.59.0")] #[rustc_builtin_macro] pub macro global_asm("assembly template", $(operands,)* $(options($(option),*))?) { diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 488bb875c35..0cc428d6962 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1003,7 +1003,6 @@ pub(crate) mod builtin { /// assert_eq!(s, b"ABCDEF"); /// # } /// ``` - #[cfg(not(bootstrap))] #[unstable(feature = "concat_bytes", issue = "87555")] #[rustc_builtin_macro] #[macro_export] diff --git a/library/core/src/num/saturating.rs b/library/core/src/num/saturating.rs index 31755503475..8982473b2dc 100644 --- a/library/core/src/num/saturating.rs +++ b/library/core/src/num/saturating.rs @@ -217,18 +217,6 @@ macro_rules! saturating_impl { forward_ref_binop! { impl Add, add for Saturating<$t>, Saturating<$t>, #[unstable(feature = "saturating_int_impl", issue = "87920")] } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] - impl Add<$t> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn add(self, other: $t) -> Saturating<$t> { - Saturating(self.0.saturating_add(other)) - } - } - forward_ref_binop! { impl Add, add for Saturating<$t>, $t, - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] impl AddAssign for Saturating<$t> { #[inline] @@ -242,7 +230,7 @@ macro_rules! saturating_impl { impl AddAssign<$t> for Saturating<$t> { #[inline] fn add_assign(&mut self, other: $t) { - *self = *self + other; + *self = *self + Saturating(other); } } forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, $t } @@ -259,18 +247,6 @@ macro_rules! saturating_impl { forward_ref_binop! { impl Sub, sub for Saturating<$t>, Saturating<$t>, #[unstable(feature = "saturating_int_impl", issue = "87920")] } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] - impl Sub<$t> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn sub(self, other: $t) -> Saturating<$t> { - Saturating(self.0.saturating_sub(other)) - } - } - forward_ref_binop! { impl Sub, sub for Saturating<$t>, $t, - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] impl SubAssign for Saturating<$t> { #[inline] @@ -284,7 +260,7 @@ macro_rules! saturating_impl { impl SubAssign<$t> for Saturating<$t> { #[inline] fn sub_assign(&mut self, other: $t) { - *self = *self - other; + *self = *self - Saturating(other); } } forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, $t } @@ -301,18 +277,6 @@ macro_rules! saturating_impl { forward_ref_binop! { impl Mul, mul for Saturating<$t>, Saturating<$t>, #[unstable(feature = "saturating_int_impl", issue = "87920")] } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] - impl Mul<$t> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn mul(self, other: $t) -> Saturating<$t> { - Saturating(self.0.saturating_mul(other)) - } - } - forward_ref_binop! { impl Mul, mul for Saturating<$t>, $t, - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] impl MulAssign for Saturating<$t> { #[inline] @@ -326,7 +290,7 @@ macro_rules! saturating_impl { impl MulAssign<$t> for Saturating<$t> { #[inline] fn mul_assign(&mut self, other: $t) { - *self = *self * other; + *self = *self * Saturating(other); } } forward_ref_op_assign! { impl MulAssign, mul_assign for Saturating<$t>, $t } @@ -362,36 +326,6 @@ macro_rules! saturating_impl { forward_ref_binop! { impl Div, div for Saturating<$t>, Saturating<$t>, #[unstable(feature = "saturating_int_impl", issue = "87920")] } - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(saturating_int_impl, saturating_int_assign_impl)] - /// use std::num::Saturating; - /// - #[doc = concat!("assert_eq!(Saturating(2", stringify!($t), "), Saturating(5", stringify!($t), ") / 2);")] - #[doc = concat!("assert_eq!(Saturating(", stringify!($t), "::MAX), Saturating(", stringify!($t), "::MAX) / 1);")] - #[doc = concat!("assert_eq!(Saturating(", stringify!($t), "::MIN), Saturating(", stringify!($t), "::MIN) / 1);")] - /// ``` - /// - /// ```should_panic - /// #![feature(saturating_int_impl, saturating_int_assign_impl)] - /// use std::num::Saturating; - /// - #[doc = concat!("let _ = Saturating(0", stringify!($t), ") / 0;")] - /// ``` - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] - impl Div<$t> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn div(self, other: $t) -> Saturating<$t> { - Saturating(self.0.saturating_div(other)) - } - } - forward_ref_binop! { impl Div, div for Saturating<$t>, $t, - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] } #[unstable(feature = "saturating_int_impl", issue = "87920")] impl DivAssign for Saturating<$t> { @@ -406,7 +340,7 @@ macro_rules! saturating_impl { impl DivAssign<$t> for Saturating<$t> { #[inline] fn div_assign(&mut self, other: $t) { - *self = *self / other; + *self = *self / Saturating(other); } } forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, $t } @@ -423,18 +357,6 @@ macro_rules! saturating_impl { forward_ref_binop! { impl Rem, rem for Saturating<$t>, Saturating<$t>, #[unstable(feature = "saturating_int_impl", issue = "87920")] } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] - impl Rem<$t> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn rem(self, other: $t) -> Saturating<$t> { - Saturating(self.0.rem(other)) - } - } - forward_ref_binop! { impl Rem, rem for Saturating<$t>, $t, - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] impl RemAssign for Saturating<$t> { #[inline] @@ -448,7 +370,7 @@ macro_rules! saturating_impl { impl RemAssign<$t> for Saturating<$t> { #[inline] fn rem_assign(&mut self, other: $t) { - *self = *self % other; + *self = *self % Saturating(other); } } forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, $t } @@ -477,18 +399,6 @@ macro_rules! saturating_impl { forward_ref_binop! { impl BitXor, bitxor for Saturating<$t>, Saturating<$t>, #[unstable(feature = "saturating_int_impl", issue = "87920")] } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] - impl BitXor<$t> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn bitxor(self, other: $t) -> Saturating<$t> { - Saturating(self.0 ^ other) - } - } - forward_ref_binop! { impl BitXor, bitxor for Saturating<$t>, $t, - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] impl BitXorAssign for Saturating<$t> { #[inline] @@ -502,7 +412,7 @@ macro_rules! saturating_impl { impl BitXorAssign<$t> for Saturating<$t> { #[inline] fn bitxor_assign(&mut self, other: $t) { - *self = *self ^ other; + *self = *self ^ Saturating(other); } } forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, $t } @@ -519,18 +429,6 @@ macro_rules! saturating_impl { forward_ref_binop! { impl BitOr, bitor for Saturating<$t>, Saturating<$t>, #[unstable(feature = "saturating_int_impl", issue = "87920")] } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] - impl BitOr<$t> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn bitor(self, other: $t) -> Saturating<$t> { - Saturating(self.0 | other) - } - } - forward_ref_binop! { impl BitOr, bitor for Saturating<$t>, $t, - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] impl BitOrAssign for Saturating<$t> { #[inline] @@ -544,7 +442,7 @@ macro_rules! saturating_impl { impl BitOrAssign<$t> for Saturating<$t> { #[inline] fn bitor_assign(&mut self, other: $t) { - *self = *self | other; + *self = *self | Saturating(other); } } forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, $t } @@ -561,18 +459,6 @@ macro_rules! saturating_impl { forward_ref_binop! { impl BitAnd, bitand for Saturating<$t>, Saturating<$t>, #[unstable(feature = "saturating_int_impl", issue = "87920")] } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] - impl BitAnd<$t> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn bitand(self, other: $t) -> Saturating<$t> { - Saturating(self.0 & other) - } - } - forward_ref_binop! { impl BitAnd, bitand for Saturating<$t>, $t, - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] impl BitAndAssign for Saturating<$t> { #[inline] @@ -586,7 +472,7 @@ macro_rules! saturating_impl { impl BitAndAssign<$t> for Saturating<$t> { #[inline] fn bitand_assign(&mut self, other: $t) { - *self = *self & other; + *self = *self & Saturating(other); } } forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Saturating<$t>, $t } diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index e9547429389..e367be8c167 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -65,11 +65,36 @@ /// ``` #[lang = "add"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented( - on(all(_Self = "{integer}", Rhs = "{float}"), message = "cannot add a float to an integer",), - on(all(_Self = "{float}", Rhs = "{integer}"), message = "cannot add an integer to a float",), - message = "cannot add `{Rhs}` to `{Self}`", - label = "no implementation for `{Self} + {Rhs}`" +#[cfg_attr( + bootstrap, + rustc_on_unimplemented( + on( + all(_Self = "{integer}", Rhs = "{float}"), + message = "cannot add a float to an integer", + ), + on( + all(_Self = "{float}", Rhs = "{integer}"), + message = "cannot add an integer to a float", + ), + message = "cannot add `{Rhs}` to `{Self}`", + label = "no implementation for `{Self} + {Rhs}`" + ) +)] +#[cfg_attr( + not(bootstrap), + rustc_on_unimplemented( + on( + all(_Self = "{integer}", Rhs = "{float}"), + message = "cannot add a float to an integer", + ), + on( + all(_Self = "{float}", Rhs = "{integer}"), + message = "cannot add an integer to a float", + ), + message = "cannot add `{Rhs}` to `{Self}`", + label = "no implementation for `{Self} + {Rhs}`", + append_const_msg, + ) )] #[doc(alias = "+")] pub trait Add<Rhs = Self> { diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs index 255f6cb7933..7c664226fc2 100644 --- a/library/core/src/ops/bit.rs +++ b/library/core/src/ops/bit.rs @@ -68,6 +68,17 @@ macro_rules! not_impl { not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } +#[stable(feature = "not_never", since = "1.60.0")] +#[rustc_const_unstable(feature = "const_ops", issue = "90080")] +impl const Not for ! { + type Output = !; + + #[inline] + fn not(self) -> ! { + match self {} + } +} + /// The bitwise AND operator `&`. /// /// Note that `Rhs` is `Self` by default, but this is not mandatory. diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs index d8e421df5de..405224f8fb0 100644 --- a/library/core/src/panic/panic_info.rs +++ b/library/core/src/panic/panic_info.rs @@ -31,6 +31,7 @@ pub struct PanicInfo<'a> { payload: &'a (dyn Any + Send), message: Option<&'a fmt::Arguments<'a>>, location: &'a Location<'a>, + can_unwind: bool, } impl<'a> PanicInfo<'a> { @@ -44,9 +45,10 @@ impl<'a> PanicInfo<'a> { pub fn internal_constructor( message: Option<&'a fmt::Arguments<'a>>, location: &'a Location<'a>, + can_unwind: bool, ) -> Self { struct NoPayload; - PanicInfo { location, message, payload: &NoPayload } + PanicInfo { location, message, payload: &NoPayload, can_unwind } } #[unstable( @@ -127,6 +129,18 @@ impl<'a> PanicInfo<'a> { // deal with that case in std::panicking::default_hook and core::panicking::panic_fmt. Some(&self.location) } + + /// Returns whether the panic handler is allowed to unwind the stack from + /// the point where the panic occurred. + /// + /// This is true for most kinds of panics with the exception of panics + /// caused by trying to unwind out of a `Drop` implementation or a function + /// whose ABI does not support unwinding. + #[must_use] + #[unstable(feature = "panic_can_unwind", issue = "92988")] + pub fn can_unwind(&self) -> bool { + self.can_unwind + } } #[stable(feature = "panic_hook_display", since = "1.26.0")] diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index ccb82cda54e..5078eea07a1 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -77,6 +77,31 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { panic!("index out of bounds: the len is {} but the index is {}", len, index) } +#[cfg(not(bootstrap))] +#[cold] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[track_caller] +#[lang = "panic_no_unwind"] // needed by codegen for panic in nounwind function +fn panic_no_unwind() -> ! { + if cfg!(feature = "panic_immediate_abort") { + super::intrinsics::abort() + } + + // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call + // that gets resolved to the `#[panic_handler]` function. + extern "Rust" { + #[lang = "panic_impl"] + fn panic_impl(pi: &PanicInfo<'_>) -> !; + } + + // PanicInfo with the `can_unwind` flag set to false forces an abort. + let fmt = format_args!("panic in a function that cannot unwind"); + let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false); + + // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. + unsafe { panic_impl(&pi) } +} + /// The entry point for panicking with a formatted message. /// /// This is designed to reduce the amount of code required at the call @@ -104,7 +129,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { fn panic_impl(pi: &PanicInfo<'_>) -> !; } - let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller()); + let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), true); // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. unsafe { panic_impl(&pi) } diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index d91289fad20..b566e211cd8 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -65,7 +65,6 @@ pub use crate::{ issue = "87555", reason = "`concat_bytes` is not stable enough for use and is subject to change" )] -#[cfg(not(bootstrap))] #[doc(no_inline)] pub use crate::concat_bytes; diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 3a7e99faccf..3f5d3f62c96 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -211,8 +211,9 @@ impl<T: ?Sized> NonNull<T> { /// } /// ``` #[stable(feature = "nonnull", since = "1.25.0")] + #[rustc_const_unstable(feature = "const_nonnull_new", issue = "93235")] #[inline] - pub fn new(ptr: *mut T) -> Option<Self> { + pub const fn new(ptr: *mut T) -> Option<Self> { if !ptr.is_null() { // SAFETY: The pointer is already checked and is not null Some(unsafe { Self::new_unchecked(ptr) }) diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 746d1cacfd0..243c044b5d9 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -711,14 +711,28 @@ impl Duration { /// as `f64`. /// /// # Panics - /// This constructor will panic if `secs` is not finite, negative or overflows `Duration`. + /// This constructor will panic if `secs` is negative, overflows `Duration` or not finite. /// /// # Examples /// ``` /// use std::time::Duration; /// - /// let dur = Duration::from_secs_f64(2.7); - /// assert_eq!(dur, Duration::new(2, 700_000_000)); + /// let res = Duration::from_secs_f64(0.0); + /// assert_eq!(res, Duration::new(0, 0)); + /// let res = Duration::from_secs_f64(1e-20); + /// assert_eq!(res, Duration::new(0, 0)); + /// let res = Duration::from_secs_f64(4.2e-7); + /// assert_eq!(res, Duration::new(0, 420)); + /// let res = Duration::from_secs_f64(2.7); + /// assert_eq!(res, Duration::new(2, 700_000_000)); + /// let res = Duration::from_secs_f64(3e10); + /// assert_eq!(res, Duration::new(30_000_000_000, 0)); + /// // subnormal float + /// let res = Duration::from_secs_f64(f64::from_bits(1)); + /// assert_eq!(res, Duration::new(0, 0)); + /// // conversion uses truncation, not rounding + /// let res = Duration::from_secs_f64(0.999e-9); + /// assert_eq!(res, Duration::new(0, 0)); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[must_use] @@ -731,55 +745,32 @@ impl Duration { } } - /// The checked version of [`from_secs_f64`]. - /// - /// [`from_secs_f64`]: Duration::from_secs_f64 - /// - /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`. - /// - /// # Examples - /// ``` - /// #![feature(duration_checked_float)] - /// use std::time::Duration; - /// - /// let dur = Duration::try_from_secs_f64(2.7); - /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000))); - /// - /// let negative = Duration::try_from_secs_f64(-5.0); - /// assert!(negative.is_err()); - /// ``` - #[unstable(feature = "duration_checked_float", issue = "83400")] - #[inline] - pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, FromSecsError> { - const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64; - let nanos = secs * (NANOS_PER_SEC as f64); - if !nanos.is_finite() { - Err(FromSecsError { kind: FromSecsErrorKind::NonFinite }) - } else if nanos >= MAX_NANOS_F64 { - Err(FromSecsError { kind: FromSecsErrorKind::Overflow }) - } else if nanos < 0.0 { - Err(FromSecsError { kind: FromSecsErrorKind::Negative }) - } else { - let nanos = nanos as u128; - Ok(Duration { - secs: (nanos / (NANOS_PER_SEC as u128)) as u64, - nanos: (nanos % (NANOS_PER_SEC as u128)) as u32, - }) - } - } - /// Creates a new `Duration` from the specified number of seconds represented /// as `f32`. /// /// # Panics - /// This constructor will panic if `secs` is not finite, negative or overflows `Duration`. + /// This constructor will panic if `secs` is negative, overflows `Duration` or not finite. /// /// # Examples /// ``` /// use std::time::Duration; /// - /// let dur = Duration::from_secs_f32(2.7); - /// assert_eq!(dur, Duration::new(2, 700_000_000)); + /// let res = Duration::from_secs_f32(0.0); + /// assert_eq!(res, Duration::new(0, 0)); + /// let res = Duration::from_secs_f32(1e-20); + /// assert_eq!(res, Duration::new(0, 0)); + /// let res = Duration::from_secs_f32(4.2e-7); + /// assert_eq!(res, Duration::new(0, 419)); + /// let res = Duration::from_secs_f32(2.7); + /// assert_eq!(res, Duration::new(2, 700_000_047)); + /// let res = Duration::from_secs_f32(3e10); + /// assert_eq!(res, Duration::new(30_000_001_024, 0)); + /// // subnormal float + /// let res = Duration::from_secs_f32(f32::from_bits(1)); + /// assert_eq!(res, Duration::new(0, 0)); + /// // conversion uses truncation, not rounding + /// let res = Duration::from_secs_f32(0.999e-9); + /// assert_eq!(res, Duration::new(0, 0)); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[must_use] @@ -792,47 +783,10 @@ impl Duration { } } - /// The checked version of [`from_secs_f32`]. - /// - /// [`from_secs_f32`]: Duration::from_secs_f32 - /// - /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`. - /// - /// # Examples - /// ``` - /// #![feature(duration_checked_float)] - /// use std::time::Duration; - /// - /// let dur = Duration::try_from_secs_f32(2.7); - /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000))); - /// - /// let negative = Duration::try_from_secs_f32(-5.0); - /// assert!(negative.is_err()); - /// ``` - #[unstable(feature = "duration_checked_float", issue = "83400")] - #[inline] - pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, FromSecsError> { - const MAX_NANOS_F32: f32 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f32; - let nanos = secs * (NANOS_PER_SEC as f32); - if !nanos.is_finite() { - Err(FromSecsError { kind: FromSecsErrorKind::NonFinite }) - } else if nanos >= MAX_NANOS_F32 { - Err(FromSecsError { kind: FromSecsErrorKind::Overflow }) - } else if nanos < 0.0 { - Err(FromSecsError { kind: FromSecsErrorKind::Negative }) - } else { - let nanos = nanos as u128; - Ok(Duration { - secs: (nanos / (NANOS_PER_SEC as u128)) as u64, - nanos: (nanos % (NANOS_PER_SEC as u128)) as u32, - }) - } - } - /// Multiplies `Duration` by `f64`. /// /// # Panics - /// This method will panic if result is not finite, negative or overflows `Duration`. + /// This method will panic if result is negative, overflows `Duration` or not finite. /// /// # Examples /// ``` @@ -854,17 +808,15 @@ impl Duration { /// Multiplies `Duration` by `f32`. /// /// # Panics - /// This method will panic if result is not finite, negative or overflows `Duration`. + /// This method will panic if result is negative, overflows `Duration` or not finite. /// /// # Examples /// ``` /// use std::time::Duration; /// /// let dur = Duration::new(2, 700_000_000); - /// // note that due to rounding errors result is slightly different - /// // from 8.478 and 847800.0 /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_640)); - /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847799, 969_120_256)); + /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847800, 0)); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ @@ -878,7 +830,7 @@ impl Duration { /// Divide `Duration` by `f64`. /// /// # Panics - /// This method will panic if result is not finite, negative or overflows `Duration`. + /// This method will panic if result is negative, overflows `Duration` or not finite. /// /// # Examples /// ``` @@ -901,7 +853,7 @@ impl Duration { /// Divide `Duration` by `f32`. /// /// # Panics - /// This method will panic if result is not finite, negative or overflows `Duration`. + /// This method will panic if result is negative, overflows `Duration` or not finite. /// /// # Examples /// ``` @@ -910,7 +862,7 @@ impl Duration { /// let dur = Duration::new(2, 700_000_000); /// // note that due to rounding errors result is slightly /// // different from 0.859_872_611 - /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_576)); + /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_579)); /// // note that truncation is used, not rounding /// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_598)); /// ``` @@ -1267,33 +1219,180 @@ impl fmt::Debug for Duration { /// ``` #[derive(Debug, Clone, PartialEq, Eq)] #[unstable(feature = "duration_checked_float", issue = "83400")] -pub struct FromSecsError { - kind: FromSecsErrorKind, +pub struct FromFloatSecsError { + kind: FromFloatSecsErrorKind, } -impl FromSecsError { +impl FromFloatSecsError { const fn description(&self) -> &'static str { match self.kind { - FromSecsErrorKind::NonFinite => "non-finite value when converting float to duration", - FromSecsErrorKind::Overflow => "overflow when converting float to duration", - FromSecsErrorKind::Negative => "negative value when converting float to duration", + FromFloatSecsErrorKind::Negative => { + "can not convert float seconds to Duration: value is negative" + } + FromFloatSecsErrorKind::OverflowOrNan => { + "can not convert float seconds to Duration: value is either too big or NaN" + } } } } #[unstable(feature = "duration_checked_float", issue = "83400")] -impl fmt::Display for FromSecsError { +impl fmt::Display for FromFloatSecsError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self.description(), f) + self.description().fmt(f) } } #[derive(Debug, Clone, PartialEq, Eq)] -enum FromSecsErrorKind { - // Value is not a finite value (either + or - infinity or NaN). - NonFinite, - // Value is too large to store in a `Duration`. - Overflow, +enum FromFloatSecsErrorKind { // Value is negative. Negative, + // Value is either too big to be represented as `Duration` or `NaN`. + OverflowOrNan, +} + +macro_rules! try_from_secs { + ( + secs = $secs: expr, + mantissa_bits = $mant_bits: literal, + exponent_bits = $exp_bits: literal, + offset = $offset: literal, + bits_ty = $bits_ty:ty, + double_ty = $double_ty:ty, + ) => {{ + const MIN_EXP: i16 = 1 - (1i16 << $exp_bits) / 2; + const MANT_MASK: $bits_ty = (1 << $mant_bits) - 1; + const EXP_MASK: $bits_ty = (1 << $exp_bits) - 1; + + if $secs.is_sign_negative() { + return Err(FromFloatSecsError { kind: FromFloatSecsErrorKind::Negative }); + } + + let bits = $secs.to_bits(); + let mant = (bits & MANT_MASK) | (MANT_MASK + 1); + let exp = ((bits >> $mant_bits) & EXP_MASK) as i16 + MIN_EXP; + + let (secs, nanos) = if exp < -30 { + // the input represents less than 1ns. + (0u64, 0u32) + } else if exp < 0 { + // the input is less than 1 second + let t = <$double_ty>::from(mant) << ($offset + exp); + let nanos = (u128::from(NANOS_PER_SEC) * u128::from(t)) >> ($mant_bits + $offset); + (0, nanos as u32) + } else if exp < $mant_bits { + let secs = mant >> ($mant_bits - exp); + let t = <$double_ty>::from((mant << exp) & MANT_MASK); + let nanos = (<$double_ty>::from(NANOS_PER_SEC) * t) >> $mant_bits; + (u64::from(secs), nanos as u32) + } else if exp < 64 { + // the input has no fractional part + let secs = u64::from(mant) << (exp - $mant_bits); + (secs, 0) + } else { + return Err(FromFloatSecsError { kind: FromFloatSecsErrorKind::OverflowOrNan }); + }; + + Ok(Duration { secs, nanos }) + }}; +} + +impl Duration { + /// The checked version of [`from_secs_f32`]. + /// + /// [`from_secs_f32`]: Duration::from_secs_f32 + /// + /// This constructor will return an `Err` if `secs` is negative, overflows `Duration` or not finite. + /// + /// # Examples + /// ``` + /// #![feature(duration_checked_float)] + /// + /// use std::time::Duration; + /// + /// let res = Duration::try_from_secs_f32(0.0); + /// assert_eq!(res, Ok(Duration::new(0, 0))); + /// let res = Duration::try_from_secs_f32(1e-20); + /// assert_eq!(res, Ok(Duration::new(0, 0))); + /// let res = Duration::try_from_secs_f32(4.2e-7); + /// assert_eq!(res, Ok(Duration::new(0, 419))); + /// let res = Duration::try_from_secs_f32(2.7); + /// assert_eq!(res, Ok(Duration::new(2, 700_000_047))); + /// let res = Duration::try_from_secs_f32(3e10); + /// assert_eq!(res, Ok(Duration::new(30_000_001_024, 0))); + /// // subnormal float: + /// let res = Duration::try_from_secs_f32(f32::from_bits(1)); + /// assert_eq!(res, Ok(Duration::new(0, 0))); + /// // conversion uses truncation, not rounding + /// let res = Duration::try_from_secs_f32(0.999e-9); + /// assert_eq!(res, Ok(Duration::new(0, 0))); + /// + /// let res = Duration::try_from_secs_f32(-5.0); + /// assert!(res.is_err()); + /// let res = Duration::try_from_secs_f32(f32::NAN); + /// assert!(res.is_err()); + /// let res = Duration::try_from_secs_f32(2e19); + /// assert!(res.is_err()); + /// ``` + #[unstable(feature = "duration_checked_float", issue = "83400")] + #[inline] + pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, FromFloatSecsError> { + try_from_secs!( + secs = secs, + mantissa_bits = 23, + exponent_bits = 8, + offset = 41, + bits_ty = u32, + double_ty = u64, + ) + } + + /// The checked version of [`from_secs_f64`]. + /// + /// [`from_secs_f64`]: Duration::from_secs_f64 + /// + /// This constructor will return an `Err` if `secs` is negative, overflows `Duration` or not finite. + /// + /// # Examples + /// ``` + /// #![feature(duration_checked_float)] + /// + /// use std::time::Duration; + /// + /// let res = Duration::try_from_secs_f64(0.0); + /// assert_eq!(res, Ok(Duration::new(0, 0))); + /// let res = Duration::try_from_secs_f64(1e-20); + /// assert_eq!(res, Ok(Duration::new(0, 0))); + /// let res = Duration::try_from_secs_f64(4.2e-7); + /// assert_eq!(res, Ok(Duration::new(0, 420))); + /// let res = Duration::try_from_secs_f64(2.7); + /// assert_eq!(res, Ok(Duration::new(2, 700_000_000))); + /// let res = Duration::try_from_secs_f64(3e10); + /// assert_eq!(res, Ok(Duration::new(30_000_000_000, 0))); + /// // subnormal float + /// let res = Duration::try_from_secs_f64(f64::from_bits(1)); + /// assert_eq!(res, Ok(Duration::new(0, 0))); + /// // conversion uses truncation, not rounding + /// let res = Duration::try_from_secs_f32(0.999e-9); + /// assert_eq!(res, Ok(Duration::new(0, 0))); + /// + /// let res = Duration::try_from_secs_f64(-5.0); + /// assert!(res.is_err()); + /// let res = Duration::try_from_secs_f64(f64::NAN); + /// assert!(res.is_err()); + /// let res = Duration::try_from_secs_f64(2e19); + /// assert!(res.is_err()); + /// ``` + #[unstable(feature = "duration_checked_float", issue = "83400")] + #[inline] + pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, FromFloatSecsError> { + try_from_secs!( + secs = secs, + mantissa_bits = 52, + exponent_bits = 11, + offset = 44, + bits_ty = u64, + double_ty = u128, + ) + } } diff --git a/library/core/tests/cmp.rs b/library/core/tests/cmp.rs index 58fee19ca74..2b234de6795 100644 --- a/library/core/tests/cmp.rs +++ b/library/core/tests/cmp.rs @@ -204,7 +204,6 @@ fn cmp_default() { assert_eq!(Fool(false), Fool(true)); } -#[cfg(not(bootstrap))] mod const_cmp { use super::*; diff --git a/library/core/tests/intrinsics.rs b/library/core/tests/intrinsics.rs index 7a2e4e29065..e050e810375 100644 --- a/library/core/tests/intrinsics.rs +++ b/library/core/tests/intrinsics.rs @@ -37,7 +37,6 @@ fn test_assume_can_be_in_const_contexts() { } #[test] -#[cfg(not(bootstrap))] const fn test_write_bytes_in_const_contexts() { use core::intrinsics::write_bytes; @@ -80,3 +79,25 @@ fn test_hints_in_const_contexts() { assert!(42u32 == core::hint::black_box(42u32)); } } + +#[cfg(not(bootstrap))] +#[test] +fn test_const_allocate_at_runtime() { + use core::intrinsics::const_allocate; + unsafe { + assert!(const_allocate(4, 4).is_null()); + } +} + +#[cfg(not(bootstrap))] +#[test] +fn test_const_deallocate_at_runtime() { + use core::intrinsics::const_deallocate; + const X: &u32 = &42u32; + let x = &0u32; + unsafe { + const_deallocate(X as *const _ as *mut u8, 4, 4); // nop + const_deallocate(x as *const _ as *mut u8, 4, 4); // nop + const_deallocate(core::ptr::null_mut(), 1, 1); // nop + } +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 841c114063d..a2bef2012cf 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -13,10 +13,13 @@ #![feature(const_bool_to_option)] #![feature(const_cell_into_inner)] #![feature(const_convert)] +#![feature(const_heap)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_assume_init)] #![feature(const_maybe_uninit_assume_init_read)] +#![feature(const_nonnull_new)] #![feature(const_num_from_num)] +#![feature(const_ptr_as_ref)] #![feature(const_ptr_read)] #![feature(const_ptr_write)] #![feature(const_ptr_offset)] diff --git a/library/core/tests/ops.rs b/library/core/tests/ops.rs index aa79dbac8f3..0c81cba35b3 100644 --- a/library/core/tests/ops.rs +++ b/library/core/tests/ops.rs @@ -232,3 +232,9 @@ fn deref_on_ref() { let y = deref(&mut x); assert_eq!(y, 4); } + +#[test] +#[allow(unreachable_code)] +fn test_not_never() { + if !return () {} +} diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index b9c0d75b702..9c65871ac4b 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -251,7 +251,6 @@ fn test_set_memory() { } #[test] -#[cfg(not(bootstrap))] fn test_set_memory_const() { const XS: [u8; 20] = { let mut xs = [0u8; 20]; @@ -275,6 +274,21 @@ fn test_unsized_nonnull() { } #[test] +fn test_const_nonnull_new() { + const { + assert!(NonNull::new(core::ptr::null_mut::<()>()).is_none()); + + let value = &mut 0u32; + let mut ptr = NonNull::new(value).unwrap(); + unsafe { *ptr.as_mut() = 42 }; + + let reference = unsafe { &*ptr.as_ref() }; + assert!(*reference == *value); + assert!(*reference == 42); + }; +} + +#[test] #[allow(warnings)] // Have a symbol for the test below. It doesn’t need to be an actual variadic function, match the // ABI, or even point to an actual executable code, because the function itself is never invoked. diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index e5753ccae2d..7f05c82ac28 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -39,6 +39,10 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "hermit")] { #[path = "hermit.rs"] mod real_imp; + } else if #[cfg(target_os = "l4re")] { + // L4Re is unix family but does not yet support unwinding. + #[path = "dummy.rs"] + mod real_imp; } else if #[cfg(target_env = "msvc")] { #[path = "seh.rs"] mod real_imp; diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 232ccdf39d4..83cb119dbf9 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -15,11 +15,11 @@ cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core" } -libc = { version = "0.2.108", default-features = false, features = ['rustc-dep-of-std'] } +libc = { version = "0.2.116", default-features = false, features = ['rustc-dep-of-std'] } compiler_builtins = { version = "0.1.66" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } -hashbrown = { version = "0.11", default-features = false, features = ['rustc-dep-of-std'] } +hashbrown = { version = "0.12", default-features = false, features = ['rustc-dep-of-std'] } std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] } # Dependencies of the `backtrace` crate @@ -45,7 +45,7 @@ fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] } hermit-abi = { version = "0.1.19", features = ['rustc-dep-of-std'] } [target.wasm32-wasi.dependencies] -wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false } +wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false } [features] backtrace = [ diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index eac884bfe0f..30da22b8084 100644 --- a/library/std/src/collections/hash/map/tests.rs +++ b/library/std/src/collections/hash/map/tests.rs @@ -817,6 +817,7 @@ fn test_retain() { } #[test] +#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc fn test_try_reserve() { let mut empty_bytes: HashMap<u8, u8> = HashMap::new(); @@ -828,11 +829,21 @@ fn test_try_reserve() { "usize::MAX should trigger an overflow!" ); - assert_matches!( - empty_bytes.try_reserve(MAX_USIZE / 8).map_err(|e| e.kind()), - Err(AllocError { .. }), - "usize::MAX / 8 should trigger an OOM!" - ); + if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 16).map_err(|e| e.kind()) { + } else { + // This may succeed if there is enough free memory. Attempt to + // allocate a few more hashmaps to ensure the allocation will fail. + let mut empty_bytes2: HashMap<u8, u8> = HashMap::new(); + let _ = empty_bytes2.try_reserve(MAX_USIZE / 16); + let mut empty_bytes3: HashMap<u8, u8> = HashMap::new(); + let _ = empty_bytes3.try_reserve(MAX_USIZE / 16); + let mut empty_bytes4: HashMap<u8, u8> = HashMap::new(); + assert_matches!( + empty_bytes4.try_reserve(MAX_USIZE / 16).map_err(|e| e.kind()), + Err(AllocError { .. }), + "usize::MAX / 16 should trigger an OOM!" + ); + } } #[test] diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 643108b88bf..1a96b9c9282 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -602,7 +602,7 @@ impl Error for char::ParseCharError { impl Error for alloc::collections::TryReserveError {} #[unstable(feature = "duration_checked_float", issue = "83400")] -impl Error for time::FromSecsError {} +impl Error for time::FromFloatSecsError {} // Copied from `any.rs`. impl dyn Error + 'static { diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index d859bff1a45..66fee2fe548 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -973,7 +973,8 @@ impl<'a> From<&'a CString> for Cow<'a, CStr> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<CString> for Arc<CStr> { - /// Converts a [`CString`] into an <code>[Arc]<[CStr]></code> without copying or allocating. + /// Converts a [`CString`] into an <code>[Arc]<[CStr]></code> by moving the [`CString`] + /// data into a new [`Arc`] buffer. #[inline] fn from(s: CString) -> Arc<CStr> { let arc: Arc<[u8]> = Arc::from(s.into_inner()); @@ -992,7 +993,8 @@ impl From<&CStr> for Arc<CStr> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<CString> for Rc<CStr> { - /// Converts a [`CString`] into an <code>[Rc]<[CStr]></code> without copying or allocating. + /// Converts a [`CString`] into an <code>[Rc]<[CStr]></code> by moving the [`CString`] + /// data into a new [`Arc`] buffer. #[inline] fn from(s: CString) -> Rc<CStr> { let rc: Rc<[u8]> = Rc::from(s.into_inner()); diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 982ad189878..81f72e34d93 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -989,7 +989,8 @@ impl Clone for Box<OsStr> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<OsString> for Arc<OsStr> { - /// Converts an [`OsString`] into an <code>[Arc]<[OsStr]></code> without copying or allocating. + /// Converts an [`OsString`] into an <code>[Arc]<[OsStr]></code> by moving the [`OsString`] + /// data into a new [`Arc`] buffer. #[inline] fn from(s: OsString) -> Arc<OsStr> { let arc = s.inner.into_arc(); @@ -1008,7 +1009,8 @@ impl From<&OsStr> for Arc<OsStr> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<OsString> for Rc<OsStr> { - /// Converts an [`OsString`] into an <code>[Rc]<[OsStr]></code> without copying or allocating. + /// Converts an [`OsString`] into an <code>[Rc]<[OsStr]></code> by moving the [`OsString`] + /// data into a new [`Rc`] buffer. #[inline] fn from(s: OsString) -> Rc<OsStr> { let rc = s.inner.into_rc(); diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index a62c01ef29b..16b8bf68242 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1504,3 +1504,19 @@ fn create_dir_long_paths() { let path = Path::new(""); assert_eq!(path.canonicalize().unwrap_err().kind(), crate::io::ErrorKind::NotFound); } + +/// Ensure ReadDir works on large directories. +/// Regression test for https://github.com/rust-lang/rust/issues/93384. +#[test] +fn read_large_dir() { + let tmpdir = tmpdir(); + + let count = 32 * 1024; + for i in 0..count { + check!(fs::File::create(tmpdir.join(&i.to_string()))); + } + + for entry in fs::read_dir(tmpdir.path()).unwrap() { + entry.unwrap(); + } +} diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index c072f0cafe4..3d6de20d860 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -7,7 +7,7 @@ use crate::io::prelude::*; use crate::cell::{Cell, RefCell}; use crate::fmt; -use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines, Split}; +use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines}; use crate::lazy::SyncOnceCell; use crate::pin::Pin; use crate::sync::atomic::{AtomicBool, Ordering}; @@ -465,29 +465,6 @@ impl Stdin { pub fn lines(self) -> Lines<StdinLock<'static>> { self.into_locked().lines() } - - /// Consumes this handle and returns an iterator over input bytes, - /// split at the specified byte value. - /// - /// For detailed semantics of this method, see the documentation on - /// [`BufRead::split`]. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(stdin_forwarders)] - /// use std::io; - /// - /// let splits = io::stdin().split(b'-'); - /// for split in splits { - /// println!("got a chunk: {}", String::from_utf8_lossy(&split.unwrap())); - /// } - /// ``` - #[must_use = "`self` will be dropped if the result is not used"] - #[unstable(feature = "stdin_forwarders", issue = "87096")] - pub fn split(self, byte: u8) -> Split<StdinLock<'static>> { - self.into_locked().split(byte) - } } #[stable(feature = "std_debug", since = "1.16.0")] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 17fe0011569..3a6b931f53b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -195,15 +195,12 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] -#![cfg_attr( - not(bootstrap), - doc(cfg_hide( - not(test), - not(any(test, bootstrap)), - no_global_oom_handling, - not(no_global_oom_handling) - )) -)] +#![doc(cfg_hide( + not(test), + not(any(test, bootstrap)), + no_global_oom_handling, + not(no_global_oom_handling) +))] // Don't link to std. We are std. #![no_std] #![warn(deprecated_in_future)] @@ -249,7 +246,7 @@ #![feature(cfg_target_thread_local)] #![feature(char_error_internals)] #![feature(char_internals)] -#![cfg_attr(not(bootstrap), feature(concat_bytes))] +#![feature(concat_bytes)] #![feature(concat_idents)] #![feature(const_fn_floating_point_arithmetic)] #![feature(const_fn_fn_ptr_basics)] @@ -311,6 +308,7 @@ #![feature(once_cell)] #![feature(panic_info_message)] #![feature(panic_internals)] +#![feature(panic_can_unwind)] #![feature(panic_unwind)] #![feature(pin_static_ref)] #![feature(portable_simd)] @@ -402,13 +400,6 @@ pub use alloc_crate::string; pub use alloc_crate::vec; #[stable(feature = "rust1", since = "1.0.0")] pub use core::any; -#[stable(feature = "simd_arch", since = "1.27.0")] -// The `no_inline`-attribute is required to make the documentation of all -// targets available. -// See https://github.com/rust-lang/rust/pull/57808#issuecomment-457390549 for -// more information. -#[doc(no_inline)] // Note (#82861): required for correct documentation -pub use core::arch; #[stable(feature = "core_array", since = "1.36.0")] pub use core::array; #[stable(feature = "rust1", since = "1.0.0")] @@ -526,6 +517,31 @@ pub mod task { pub use alloc::task::*; } +#[doc = include_str!("../../stdarch/crates/core_arch/src/core_arch_docs.md")] +#[stable(feature = "simd_arch", since = "1.27.0")] +pub mod arch { + #[stable(feature = "simd_arch", since = "1.27.0")] + // The `no_inline`-attribute is required to make the documentation of all + // targets available. + // See https://github.com/rust-lang/rust/pull/57808#issuecomment-457390549 for + // more information. + #[doc(no_inline)] // Note (#82861): required for correct documentation + pub use core::arch::*; + + #[stable(feature = "simd_x86", since = "1.27.0")] + pub use std_detect::is_x86_feature_detected; + #[unstable(feature = "stdsimd", issue = "48556")] + pub use std_detect::{ + is_aarch64_feature_detected, is_arm_feature_detected, is_mips64_feature_detected, + is_mips_feature_detected, is_powerpc64_feature_detected, is_powerpc_feature_detected, + is_riscv_feature_detected, + }; +} + +// This was stabilized in the crate root so we have to keep it there. +#[stable(feature = "simd_x86", since = "1.27.0")] +pub use std_detect::is_x86_feature_detected; + // The runtime entry point and a few unstable public functions used by the // compiler #[macro_use] @@ -544,18 +560,6 @@ mod panicking; #[allow(dead_code, unused_attributes)] mod backtrace_rs; -#[stable(feature = "simd_x86", since = "1.27.0")] -pub use std_detect::is_x86_feature_detected; -#[doc(hidden)] -#[unstable(feature = "stdsimd", issue = "48556")] -pub use std_detect::*; -#[unstable(feature = "stdsimd", issue = "48556")] -pub use std_detect::{ - is_aarch64_feature_detected, is_arm_feature_detected, is_mips64_feature_detected, - is_mips_feature_detected, is_powerpc64_feature_detected, is_powerpc_feature_detected, - is_riscv_feature_detected, -}; - // Re-export macros defined in libcore. #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] @@ -578,7 +582,6 @@ pub use core::{ issue = "87555", reason = "`concat_bytes` is not stable enough for use and is subject to change" )] -#[cfg(not(bootstrap))] pub use core::concat_bytes; #[stable(feature = "core_primitive", since = "1.43.0")] diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 52d7d4690d3..0b6588db92c 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -8,6 +8,8 @@ use crate::fmt; use crate::fs; use crate::marker::PhantomData; use crate::mem::forget; +#[cfg(not(target_os = "wasi"))] +use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; /// A borrowed file descriptor. @@ -67,6 +69,37 @@ impl BorrowedFd<'_> { } } +impl OwnedFd { + /// Creates a new `OwnedFd` instance that shares the same underlying file handle + /// as the existing `OwnedFd` instance. + #[cfg(not(target_os = "wasi"))] + pub fn try_clone(&self) -> crate::io::Result<Self> { + // We want to atomically duplicate this file descriptor and set the + // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This + // is a POSIX flag that was added to Linux in 2.6.24. + #[cfg(not(target_os = "espidf"))] + let cmd = libc::F_DUPFD_CLOEXEC; + + // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics + // will never be supported, as this is a bare metal framework with + // no capabilities for multi-process execution. While F_DUPFD is also + // not supported yet, it might be (currently it returns ENOSYS). + #[cfg(target_os = "espidf")] + let cmd = libc::F_DUPFD; + + let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?; + Ok(unsafe { Self::from_raw_fd(fd) }) + } + + #[cfg(target_os = "wasi")] + pub fn try_clone(&self) -> crate::io::Result<Self> { + Err(crate::io::Error::new_const( + crate::io::ErrorKind::Unsupported, + &"operation not supported on WASI yet", + )) + } +} + #[unstable(feature = "io_safety", issue = "87074")] impl AsRawFd for BorrowedFd<'_> { #[inline] diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs index f0b38d29845..b6d5199341c 100644 --- a/library/std/src/os/raw/mod.rs +++ b/library/std/src/os/raw/mod.rs @@ -45,94 +45,13 @@ macro_rules! type_alias { } } -type_alias! { "char.md", c_char = u8, NonZero_c_char = NonZeroU8; -#[doc(cfg(all()))] -#[cfg(any( - all( - target_os = "linux", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "hexagon", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - target_arch = "riscv64", - target_arch = "riscv32" - ) - ), - all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), - all(target_os = "l4re", target_arch = "x86_64"), - all( - target_os = "freebsd", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "riscv64" - ) - ), - all( - target_os = "netbsd", - any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc") - ), - all(target_os = "openbsd", target_arch = "aarch64"), - all( - target_os = "vxworks", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc64", - target_arch = "powerpc" - ) - ), - all(target_os = "fuchsia", target_arch = "aarch64") -))]} -type_alias! { "char.md", c_char = i8, NonZero_c_char = NonZeroI8; -#[doc(cfg(all()))] -#[cfg(not(any( - all( - target_os = "linux", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "hexagon", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - target_arch = "riscv64", - target_arch = "riscv32" - ) - ), - all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), - all(target_os = "l4re", target_arch = "x86_64"), - all( - target_os = "freebsd", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "riscv64" - ) - ), - all( - target_os = "netbsd", - any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc") - ), - all(target_os = "openbsd", target_arch = "aarch64"), - all( - target_os = "vxworks", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc64", - target_arch = "powerpc" - ) - ), - all(target_os = "fuchsia", target_arch = "aarch64") -)))]} +type_alias! { "char.md", c_char = c_char_definition::c_char, NonZero_c_char = c_char_definition::NonZero_c_char; +// Make this type alias appear cfg-dependent so that Clippy does not suggest +// replacing `0 as c_char` with `0_i8`/`0_u8`. This #[cfg(all())] can be removed +// after the false positive in https://github.com/rust-lang/rust-clippy/issues/8093 +// is fixed. +#[cfg(all())] +#[doc(cfg(all()))] } type_alias! { "schar.md", c_schar = i8, NonZero_c_schar = NonZeroI8; } type_alias! { "uchar.md", c_uchar = u8, NonZero_c_uchar = NonZeroU8; } type_alias! { "short.md", c_short = i16, NonZero_c_short = NonZeroI16; } @@ -180,3 +99,58 @@ pub type c_ptrdiff_t = isize; /// platforms where this is not the case. #[unstable(feature = "c_size_t", issue = "88345")] pub type c_ssize_t = isize; + +mod c_char_definition { + cfg_if::cfg_if! { + // These are the targets on which c_char is unsigned. + if #[cfg(any( + all( + target_os = "linux", + any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "hexagon", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x", + target_arch = "riscv64", + target_arch = "riscv32" + ) + ), + all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), + all(target_os = "l4re", target_arch = "x86_64"), + all( + target_os = "freebsd", + any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "riscv64" + ) + ), + all( + target_os = "netbsd", + any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc") + ), + all(target_os = "openbsd", target_arch = "aarch64"), + all( + target_os = "vxworks", + any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc64", + target_arch = "powerpc" + ) + ), + all(target_os = "fuchsia", target_arch = "aarch64") + ))] { + pub type c_char = u8; + pub type NonZero_c_char = core::num::NonZeroU8; + } else { + // On every other target, c_char is signed. + pub type c_char = i8; + pub type NonZero_c_char = core::num::NonZeroI8; + } + } +} diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index f450e41bfea..9dbd4548bc9 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -2,7 +2,7 @@ use crate::ffi::OsStr; use crate::os::unix::ffi::OsStrExt; use crate::path::Path; use crate::sys::cvt; -use crate::{ascii, fmt, io, iter, mem}; +use crate::{ascii, fmt, io, mem, ptr}; // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? #[cfg(not(unix))] @@ -22,8 +22,9 @@ fn sun_path_offset(addr: &libc::sockaddr_un) -> usize { path - base } -pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { - let mut addr: libc::sockaddr_un = mem::zeroed(); +pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { + // SAFETY: All zeros is a valid representation for `sockaddr_un`. + let mut addr: libc::sockaddr_un = unsafe { mem::zeroed() }; addr.sun_family = libc::AF_UNIX as libc::sa_family_t; let bytes = path.as_os_str().as_bytes(); @@ -41,11 +42,13 @@ pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, &"path must be shorter than SUN_LEN", )); } - for (dst, src) in iter::zip(&mut addr.sun_path, bytes) { - *dst = *src as libc::c_char; - } - // null byte for pathname addresses is already there because we zeroed the - // struct + // SAFETY: `bytes` and `addr.sun_path` are not overlapping and + // both point to valid memory. + // NOTE: We zeroed the memory above, so the path is already null + // terminated. + unsafe { + ptr::copy_nonoverlapping(bytes.as_ptr(), addr.sun_path.as_mut_ptr().cast(), bytes.len()) + }; let mut len = sun_path_offset(&addr) + bytes.len(); match bytes.get(0) { @@ -127,6 +130,43 @@ impl SocketAddr { Ok(SocketAddr { addr, len }) } + /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path. + /// + /// # Errors + /// + /// Returns an error if the path is longer than `SUN_LEN` or if it contains + /// NULL bytes. + /// + /// # Examples + /// + /// ``` + /// #![feature(unix_socket_creation)] + /// use std::os::unix::net::SocketAddr; + /// use std::path::Path; + /// + /// # fn main() -> std::io::Result<()> { + /// let address = SocketAddr::from_path("/path/to/socket")?; + /// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket"))); + /// # Ok(()) + /// # } + /// ``` + /// + /// Creating a `SocketAddr` with a NULL byte results in an error. + /// + /// ``` + /// #![feature(unix_socket_creation)] + /// use std::os::unix::net::SocketAddr; + /// + /// assert!(SocketAddr::from_path("/path/with/\0/bytes").is_err()); + /// ``` + #[unstable(feature = "unix_socket_creation", issue = "93423")] + pub fn from_path<P>(path: P) -> io::Result<SocketAddr> + where + P: AsRef<Path>, + { + sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len }) + } + /// Returns `true` if the address is unnamed. /// /// # Examples diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs index 5c62679f552..37126069f94 100644 --- a/library/std/src/os/wasi/fs.rs +++ b/library/std/src/os/wasi/fs.rs @@ -250,6 +250,21 @@ impl FileExt for fs::File { } fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> { + let advice = match advice { + a if a == wasi::ADVICE_NORMAL.raw() => wasi::ADVICE_NORMAL, + a if a == wasi::ADVICE_SEQUENTIAL.raw() => wasi::ADVICE_SEQUENTIAL, + a if a == wasi::ADVICE_RANDOM.raw() => wasi::ADVICE_RANDOM, + a if a == wasi::ADVICE_WILLNEED.raw() => wasi::ADVICE_WILLNEED, + a if a == wasi::ADVICE_DONTNEED.raw() => wasi::ADVICE_DONTNEED, + a if a == wasi::ADVICE_NOREUSE.raw() => wasi::ADVICE_NOREUSE, + _ => { + return Err(io::Error::new_const( + io::ErrorKind::InvalidInput, + &"invalid parameter 'advice'", + )); + } + }; + self.as_inner().as_inner().advise(offset, len, advice) } diff --git a/library/std/src/os/wasi/net/mod.rs b/library/std/src/os/wasi/net/mod.rs index e6bcf87887f..73c097d4a50 100644 --- a/library/std/src/os/wasi/net/mod.rs +++ b/library/std/src/os/wasi/net/mod.rs @@ -1,3 +1,23 @@ //! WASI-specific networking functionality #![unstable(feature = "wasi_ext", issue = "71213")] + +use crate::io; +use crate::net; +use crate::sys_common::AsInner; + +/// WASI-specific extensions to [`std::net::TcpListener`]. +/// +/// [`std::net::TcpListener`]: crate::net::TcpListener +pub trait TcpListenerExt { + /// Accept a socket. + /// + /// This corresponds to the `sock_accept` syscall. + fn sock_accept(&self, flags: u16) -> io::Result<u32>; +} + +impl TcpListenerExt for net::TcpListener { + fn sock_accept(&self, flags: u16) -> io::Result<u32> { + self.as_inner().as_inner().as_inner().sock_accept(flags) + } +} diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 1527f5b6b07..e37ce633a12 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -6,9 +6,11 @@ use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; use crate::convert::TryFrom; use crate::fmt; use crate::fs; +use crate::io; use crate::marker::PhantomData; use crate::mem::forget; use crate::sys::c; +use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; /// A borrowed handle. @@ -144,6 +146,36 @@ impl TryFrom<HandleOrNull> for OwnedHandle { } } +impl OwnedHandle { + /// Creates a new `OwnedHandle` instance that shares the same underlying file handle + /// as the existing `OwnedHandle` instance. + pub fn try_clone(&self) -> crate::io::Result<Self> { + self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS) + } + + pub(crate) fn duplicate( + &self, + access: c::DWORD, + inherit: bool, + options: c::DWORD, + ) -> io::Result<Self> { + let mut ret = 0 as c::HANDLE; + cvt(unsafe { + let cur_proc = c::GetCurrentProcess(); + c::DuplicateHandle( + cur_proc, + self.as_raw_handle(), + cur_proc, + &mut ret, + access, + inherit as c::BOOL, + options, + ) + })?; + unsafe { Ok(Self::from_raw_handle(ret)) } + } +} + impl TryFrom<HandleOrInvalid> for OwnedHandle { type Error = (); diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 23db66df09f..26b569bcdd3 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -4,9 +4,13 @@ use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; use crate::fmt; +use crate::io; use crate::marker::PhantomData; +use crate::mem; use crate::mem::forget; +use crate::sys; use crate::sys::c; +use crate::sys::cvt; /// A borrowed socket. /// @@ -69,6 +73,77 @@ impl BorrowedSocket<'_> { } } +impl OwnedSocket { + /// Creates a new `OwnedSocket` instance that shares the same underlying socket + /// as the existing `OwnedSocket` instance. + pub fn try_clone(&self) -> io::Result<Self> { + let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() }; + let result = unsafe { + c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info) + }; + sys::net::cvt(result)?; + let socket = unsafe { + c::WSASocketW( + info.iAddressFamily, + info.iSocketType, + info.iProtocol, + &mut info, + 0, + c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT, + ) + }; + + if socket != c::INVALID_SOCKET { + unsafe { Ok(OwnedSocket::from_raw_socket(socket)) } + } else { + let error = unsafe { c::WSAGetLastError() }; + + if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL { + return Err(io::Error::from_raw_os_error(error)); + } + + let socket = unsafe { + c::WSASocketW( + info.iAddressFamily, + info.iSocketType, + info.iProtocol, + &mut info, + 0, + c::WSA_FLAG_OVERLAPPED, + ) + }; + + if socket == c::INVALID_SOCKET { + return Err(last_error()); + } + + unsafe { + let socket = OwnedSocket::from_raw_socket(socket); + socket.set_no_inherit()?; + Ok(socket) + } + } + } + + #[cfg(not(target_vendor = "uwp"))] + pub(crate) fn set_no_inherit(&self) -> io::Result<()> { + cvt(unsafe { + c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0) + }) + .map(drop) + } + + #[cfg(target_vendor = "uwp")] + pub(crate) fn set_no_inherit(&self) -> io::Result<()> { + Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Unavailable on UWP")) + } +} + +/// Returns the last error from the Windows socket interface. +fn last_error() -> io::Error { + io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() }) +} + impl AsRawSocket for BorrowedSocket<'_> { #[inline] fn as_raw_socket(&self) -> RawSocket { diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index d0f332fe5e8..83ab13c963d 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -576,9 +576,14 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! { let msg = info.message().unwrap(); // The current implementation always returns Some crate::sys_common::backtrace::__rust_end_short_backtrace(move || { if let Some(msg) = msg.as_str() { - rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc); + rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc, info.can_unwind()); } else { - rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc); + rust_panic_with_hook( + &mut PanicPayload::new(msg), + info.message(), + loc, + info.can_unwind(), + ); } }) } @@ -602,7 +607,7 @@ pub const fn begin_panic<M: Any + Send>(msg: M) -> ! { let loc = Location::caller(); return crate::sys_common::backtrace::__rust_end_short_backtrace(move || { - rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc) + rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc, true) }); struct PanicPayload<A> { @@ -647,6 +652,7 @@ fn rust_panic_with_hook( payload: &mut dyn BoxMeUp, message: Option<&fmt::Arguments<'_>>, location: &Location<'_>, + can_unwind: bool, ) -> ! { let (must_abort, panics) = panic_count::increase(); @@ -663,14 +669,14 @@ fn rust_panic_with_hook( } else { // Unfortunately, this does not print a backtrace, because creating // a `Backtrace` will allocate, which we must to avoid here. - let panicinfo = PanicInfo::internal_constructor(message, location); + let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind); rtprintpanic!("{}\npanicked after panic::always_abort(), aborting.\n", panicinfo); } - intrinsics::abort() + crate::sys::abort_internal(); } unsafe { - let mut info = PanicInfo::internal_constructor(message, location); + let mut info = PanicInfo::internal_constructor(message, location, can_unwind); let _guard = HOOK_LOCK.read(); match HOOK { // Some platforms (like wasm) know that printing to stderr won't ever actually @@ -691,13 +697,13 @@ fn rust_panic_with_hook( }; } - if panics > 1 { + if panics > 1 || !can_unwind { // If a thread panics while it's already unwinding then we // have limited options. Currently our preference is to // just abort. In the future we may consider resuming // unwinding or otherwise exiting the thread cleanly. rtprintpanic!("thread panicked while panicking. aborting.\n"); - intrinsics::abort() + crate::sys::abort_internal(); } rust_panic(payload) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index f509403fe2e..e540f860160 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -72,6 +72,7 @@ mod tests; use crate::borrow::{Borrow, Cow}; use crate::cmp; +use crate::collections::TryReserveError; use crate::error::Error; use crate::fmt; use crate::fs; @@ -1512,6 +1513,15 @@ impl PathBuf { self.inner.reserve(additional) } + /// Invokes [`try_reserve`] on the underlying instance of [`OsString`]. + /// + /// [`try_reserve`]: OsString::try_reserve + #[unstable(feature = "try_reserve_2", issue = "91789")] + #[inline] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.inner.try_reserve(additional) + } + /// Invokes [`reserve_exact`] on the underlying instance of [`OsString`]. /// /// [`reserve_exact`]: OsString::reserve_exact @@ -1521,6 +1531,15 @@ impl PathBuf { self.inner.reserve_exact(additional) } + /// Invokes [`try_reserve_exact`] on the underlying instance of [`OsString`]. + /// + /// [`try_reserve_exact`]: OsString::try_reserve_exact + #[unstable(feature = "try_reserve_2", issue = "91789")] + #[inline] + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.inner.try_reserve_exact(additional) + } + /// Invokes [`shrink_to_fit`] on the underlying instance of [`OsString`]. /// /// [`shrink_to_fit`]: OsString::shrink_to_fit @@ -1766,7 +1785,8 @@ impl<'a> From<Cow<'a, Path>> for PathBuf { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<PathBuf> for Arc<Path> { - /// Converts a [`PathBuf`] into an [`Arc`] by moving the [`PathBuf`] data into a new [`Arc`] buffer. + /// Converts a [`PathBuf`] into an <code>[Arc]<[Path]></code> by moving the [`PathBuf`] data + /// into a new [`Arc`] buffer. #[inline] fn from(s: PathBuf) -> Arc<Path> { let arc: Arc<OsStr> = Arc::from(s.into_os_string()); @@ -1786,7 +1806,8 @@ impl From<&Path> for Arc<Path> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<PathBuf> for Rc<Path> { - /// Converts a [`PathBuf`] into an [`Rc`] by moving the [`PathBuf`] data into a new `Rc` buffer. + /// Converts a [`PathBuf`] into an <code>[Rc]<[Path]></code> by moving the [`PathBuf`] data into + /// a new [`Rc`] buffer. #[inline] fn from(s: PathBuf) -> Rc<Path> { let rc: Rc<OsStr> = Rc::from(s.into_os_string()); @@ -1796,7 +1817,7 @@ impl From<PathBuf> for Rc<Path> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&Path> for Rc<Path> { - /// Converts a [`Path`] into an [`Rc`] by copying the [`Path`] data into a new `Rc` buffer. + /// Converts a [`Path`] into an [`Rc`] by copying the [`Path`] data into a new [`Rc`] buffer. #[inline] fn from(s: &Path) -> Rc<Path> { let rc: Rc<OsStr> = Rc::from(s.as_os_str()); diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 53124daa3a6..0226c4d7a25 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -49,7 +49,6 @@ pub use core::prelude::v1::{ issue = "87555", reason = "`concat_bytes` is not stable enough for use and is subject to change" )] -#[cfg(not(bootstrap))] #[doc(no_inline)] pub use core::prelude::v1::concat_bytes; diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index 57f1dcca30e..3ea0a6c3937 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -188,12 +188,9 @@ unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {} /// [`lock`]: Mutex::lock /// [`try_lock`]: Mutex::try_lock #[must_use = "if unused the Mutex will immediately unlock"] -#[cfg_attr( - not(bootstrap), - must_not_suspend = "holding a MutexGuard across suspend \ +#[must_not_suspend = "holding a MutexGuard across suspend \ points can cause deadlocks, delays, \ - and cause Futures to not implement `Send`" -)] + and cause Futures to not implement `Send`"] #[stable(feature = "rust1", since = "1.0.0")] pub struct MutexGuard<'a, T: ?Sized + 'a> { lock: &'a Mutex<T>, diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index 2f4395ceefd..2e72a9ef54e 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -95,12 +95,9 @@ unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {} /// [`read`]: RwLock::read /// [`try_read`]: RwLock::try_read #[must_use = "if unused the RwLock will immediately unlock"] -#[cfg_attr( - not(bootstrap), - must_not_suspend = "holding a RwLockReadGuard across suspend \ +#[must_not_suspend = "holding a RwLockReadGuard across suspend \ points can cause deadlocks, delays, \ - and cause Futures to not implement `Send`" -)] + and cause Futures to not implement `Send`"] #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { lock: &'a RwLock<T>, @@ -121,12 +118,9 @@ unsafe impl<T: ?Sized + Sync> Sync for RwLockReadGuard<'_, T> {} /// [`write`]: RwLock::write /// [`try_write`]: RwLock::try_write #[must_use = "if unused the RwLock will immediately unlock"] -#[cfg_attr( - not(bootstrap), - must_not_suspend = "holding a RwLockWriteGuard across suspend \ +#[must_not_suspend = "holding a RwLockWriteGuard across suspend \ points can cause deadlocks, delays, \ - and cause Future's to not implement `Send`" -)] + and cause Future's to not implement `Send`"] #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { lock: &'a RwLock<T>, diff --git a/library/std/src/sys/common/alloc.rs b/library/std/src/sys/common/alloc.rs index 9665d1fa892..e06eaf6db1a 100644 --- a/library/std/src/sys/common/alloc.rs +++ b/library/std/src/sys/common/alloc.rs @@ -14,8 +14,8 @@ use crate::ptr; target_arch = "asmjs", target_arch = "wasm32", target_arch = "hexagon", - target_arch = "riscv32", - target_arch = "xtensa" + all(target_arch = "riscv32", not(target_os = "espidf")), + all(target_arch = "xtensa", not(target_os = "espidf")), )))] pub const MIN_ALIGN: usize = 8; #[cfg(all(any( @@ -28,6 +28,12 @@ pub const MIN_ALIGN: usize = 8; target_arch = "wasm64", )))] pub const MIN_ALIGN: usize = 16; +// The allocator on the esp-idf platform guarentees 4 byte alignment. +#[cfg(all(any( + all(target_arch = "riscv32", target_os = "espidf"), + all(target_arch = "xtensa", target_os = "espidf"), +)))] +pub const MIN_ALIGN: usize = 4; pub unsafe fn realloc_fallback( alloc: &System, diff --git a/library/std/src/sys/solid/abi/sockets.rs b/library/std/src/sys/solid/abi/sockets.rs index 7c21d0dd25e..eb06a6dd927 100644 --- a/library/std/src/sys/solid/abi/sockets.rs +++ b/library/std/src/sys/solid/abi/sockets.rs @@ -175,6 +175,9 @@ extern "C" { #[link_name = "SOLID_NET_Close"] pub fn close(s: c_int) -> c_int; + #[link_name = "SOLID_NET_Dup"] + pub fn dup(s: c_int) -> c_int; + #[link_name = "SOLID_NET_GetPeerName"] pub fn getpeername(s: c_int, name: *mut sockaddr, namelen: *mut socklen_t) -> c_int; diff --git a/library/std/src/sys/solid/net.rs b/library/std/src/sys/solid/net.rs index 63ba6341c79..c91ecce4d72 100644 --- a/library/std/src/sys/solid/net.rs +++ b/library/std/src/sys/solid/net.rs @@ -107,7 +107,7 @@ impl FileDesc { } fn duplicate(&self) -> io::Result<FileDesc> { - super::unsupported() + cvt(unsafe { netc::dup(self.fd) }).map(Self::new) } } diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 2362bff913f..3de7c68a686 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -259,22 +259,9 @@ impl FileDesc { } } + #[inline] pub fn duplicate(&self) -> io::Result<FileDesc> { - // We want to atomically duplicate this file descriptor and set the - // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This - // is a POSIX flag that was added to Linux in 2.6.24. - #[cfg(not(target_os = "espidf"))] - let cmd = libc::F_DUPFD_CLOEXEC; - - // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics - // will never be supported, as this is a bare metal framework with - // no capabilities for multi-process execution. While F_DUPFD is also - // not supported yet, it might be (currently it returns ENOSYS). - #[cfg(target_os = "espidf")] - let cmd = libc::F_DUPFD; - - let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?; - Ok(unsafe { FileDesc::from_raw_fd(fd) }) + Ok(Self(self.0.try_clone()?)) } } diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index f8deda93fe2..65e000d9215 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -34,7 +34,20 @@ use libc::c_char; use libc::dirfd; #[cfg(any(target_os = "linux", target_os = "emscripten"))] use libc::fstatat64; +#[cfg(any( + target_os = "android", + target_os = "solaris", + target_os = "fuchsia", + target_os = "redox", + target_os = "illumos" +))] +use libc::readdir as readdir64; +#[cfg(target_os = "linux")] +use libc::readdir64; +#[cfg(any(target_os = "emscripten", target_os = "l4re"))] +use libc::readdir64_r; #[cfg(not(any( + target_os = "android", target_os = "linux", target_os = "emscripten", target_os = "solaris", @@ -60,9 +73,7 @@ use libc::{ lstat as lstat64, off_t as off64_t, open as open64, stat as stat64, }; #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))] -use libc::{ - dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, readdir64_r, stat64, -}; +use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, stat64}; pub use crate::sys_common::fs::try_exists; @@ -202,6 +213,8 @@ struct InnerReadDir { pub struct ReadDir { inner: Arc<InnerReadDir>, #[cfg(not(any( + target_os = "android", + target_os = "linux", target_os = "solaris", target_os = "illumos", target_os = "fuchsia", @@ -218,11 +231,12 @@ unsafe impl Sync for Dir {} pub struct DirEntry { entry: dirent64, dir: Arc<InnerReadDir>, - // We need to store an owned copy of the entry name - // on Solaris and Fuchsia because a) it uses a zero-length - // array to store the name, b) its lifetime between readdir - // calls is not guaranteed. + // We need to store an owned copy of the entry name on platforms that use + // readdir() (not readdir_r()), because a) struct dirent may use a flexible + // array to store the name, b) it lives only until the next readdir() call. #[cfg(any( + target_os = "android", + target_os = "linux", target_os = "solaris", target_os = "illumos", target_os = "fuchsia", @@ -449,6 +463,8 @@ impl Iterator for ReadDir { type Item = io::Result<DirEntry>; #[cfg(any( + target_os = "android", + target_os = "linux", target_os = "solaris", target_os = "fuchsia", target_os = "redox", @@ -457,12 +473,13 @@ impl Iterator for ReadDir { fn next(&mut self) -> Option<io::Result<DirEntry>> { unsafe { loop { - // Although readdir_r(3) would be a correct function to use here because - // of the thread safety, on Illumos and Fuchsia the readdir(3C) function - // is safe to use in threaded applications and it is generally preferred - // over the readdir_r(3C) function. + // As of POSIX.1-2017, readdir() is not required to be thread safe; only + // readdir_r() is. However, readdir_r() cannot correctly handle platforms + // with unlimited or variable NAME_MAX. Many modern platforms guarantee + // thread safety for readdir() as long an individual DIR* is not accessed + // concurrently, which is sufficient for Rust. super::os::set_errno(0); - let entry_ptr = libc::readdir(self.inner.dirp.0); + let entry_ptr = readdir64(self.inner.dirp.0); if entry_ptr.is_null() { // null can mean either the end is reached or an error occurred. // So we had to clear errno beforehand to check for an error now. @@ -472,10 +489,18 @@ impl Iterator for ReadDir { }; } + // Only d_reclen bytes of *entry_ptr are valid, so we can't just copy the + // whole thing (#93384). Instead, copy everything except the name. + let entry_bytes = entry_ptr as *const u8; + let entry_name = ptr::addr_of!((*entry_ptr).d_name) as *const u8; + let name_offset = entry_name.offset_from(entry_bytes) as usize; + let mut entry: dirent64 = mem::zeroed(); + ptr::copy_nonoverlapping(entry_bytes, &mut entry as *mut _ as *mut u8, name_offset); + let ret = DirEntry { - entry: *entry_ptr, + entry, // d_name is guaranteed to be null-terminated. - name: CStr::from_ptr((*entry_ptr).d_name.as_ptr()).to_owned(), + name: CStr::from_ptr(entry_name as *const _).to_owned(), dir: Arc::clone(&self.inner), }; if ret.name_bytes() != b"." && ret.name_bytes() != b".." { @@ -486,6 +511,8 @@ impl Iterator for ReadDir { } #[cfg(not(any( + target_os = "android", + target_os = "linux", target_os = "solaris", target_os = "fuchsia", target_os = "redox", @@ -531,17 +558,17 @@ impl Drop for Dir { impl DirEntry { pub fn path(&self) -> PathBuf { - self.dir.root.join(OsStr::from_bytes(self.name_bytes())) + self.dir.root.join(self.file_name_os_str()) } pub fn file_name(&self) -> OsString { - OsStr::from_bytes(self.name_bytes()).to_os_string() + self.file_name_os_str().to_os_string() } #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] pub fn metadata(&self) -> io::Result<FileAttr> { let fd = cvt(unsafe { dirfd(self.dir.dirp.0) })?; - let name = self.entry.d_name.as_ptr(); + let name = self.name_cstr().as_ptr(); cfg_has_statx! { if let Some(ret) = unsafe { try_statx( @@ -639,29 +666,21 @@ impl DirEntry { ) } } - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "emscripten", - target_os = "l4re", - target_os = "haiku", - target_os = "vxworks", - target_os = "espidf" - ))] - fn name_bytes(&self) -> &[u8] { - unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() } - } - #[cfg(any( - target_os = "solaris", - target_os = "illumos", - target_os = "fuchsia", - target_os = "redox" - ))] + #[cfg(not(any( + target_os = "macos", + target_os = "ios", + target_os = "netbsd", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly" + )))] fn name_bytes(&self) -> &[u8] { - self.name.as_bytes() + self.name_cstr().to_bytes() } #[cfg(not(any( + target_os = "android", + target_os = "linux", target_os = "solaris", target_os = "illumos", target_os = "fuchsia", @@ -670,7 +689,14 @@ impl DirEntry { fn name_cstr(&self) -> &CStr { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) } } - #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "fuchsia"))] + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "solaris", + target_os = "illumos", + target_os = "fuchsia", + target_os = "redox" + ))] fn name_cstr(&self) -> &CStr { &self.name } @@ -1076,6 +1102,8 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> { Ok(ReadDir { inner: Arc::new(inner), #[cfg(not(any( + target_os = "android", + target_os = "linux", target_os = "solaris", target_os = "illumos", target_os = "fuchsia", @@ -1448,8 +1476,8 @@ pub fn chroot(dir: &Path) -> io::Result<()> { pub use remove_dir_impl::remove_dir_all; -// Fallback for REDOX -#[cfg(target_os = "redox")] +// Fallback for REDOX and ESP-IDF +#[cfg(any(target_os = "redox", target_os = "espidf"))] mod remove_dir_impl { pub use crate::sys_common::fs::remove_dir_all; } @@ -1573,7 +1601,11 @@ mod remove_dir_impl { } // Modern implementation using openat(), unlinkat() and fdopendir() -#[cfg(not(any(all(target_os = "macos", target_arch = "x86_64"), target_os = "redox")))] +#[cfg(not(any( + all(target_os = "macos", target_arch = "x86_64"), + target_os = "redox", + target_os = "espidf" +)))] mod remove_dir_impl { use super::{cstr, lstat, Dir, DirEntry, InnerReadDir, ReadDir}; use crate::ffi::CStr; @@ -1611,6 +1643,8 @@ mod remove_dir_impl { ReadDir { inner: Arc::new(InnerReadDir { dirp, root: dummy_root }), #[cfg(not(any( + target_os = "android", + target_os = "linux", target_os = "solaris", target_os = "illumos", target_os = "fuchsia", @@ -1627,7 +1661,6 @@ mod remove_dir_impl { target_os = "illumos", target_os = "haiku", target_os = "vxworks", - target_os = "fuchsia" ))] fn is_dir(_ent: &DirEntry) -> Option<bool> { None @@ -1638,7 +1671,6 @@ mod remove_dir_impl { target_os = "illumos", target_os = "haiku", target_os = "vxworks", - target_os = "fuchsia" )))] fn is_dir(ent: &DirEntry) -> Option<bool> { match ent.entry.d_type { diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 8a028d99306..7466c77356c 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -75,7 +75,7 @@ pub fn errno() -> i32 { } /// Sets the platform-specific value of errno -#[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall! +#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall! #[allow(dead_code)] // but not all target cfgs actually end up using it pub fn set_errno(e: i32) { unsafe { *errno_location() = e as c_int } diff --git a/library/std/src/sys/unix/process/process_unix/tests.rs b/library/std/src/sys/unix/process/process_unix/tests.rs index 157debf2d25..560c62155d9 100644 --- a/library/std/src/sys/unix/process/process_unix/tests.rs +++ b/library/std/src/sys/unix/process/process_unix/tests.rs @@ -53,5 +53,10 @@ fn test_command_fork_no_unwind() { let status = got.expect("panic unexpectedly propagated"); dbg!(status); let signal = status.signal().expect("expected child process to die of signal"); - assert!(signal == libc::SIGABRT || signal == libc::SIGILL || signal == libc::SIGTRAP); + assert!( + signal == libc::SIGABRT + || signal == libc::SIGILL + || signal == libc::SIGTRAP + || signal == libc::SIGSEGV + ); } diff --git a/library/std/src/sys/wasi/fd.rs b/library/std/src/sys/wasi/fd.rs index e4f4456611c..0b9c8e61db8 100644 --- a/library/std/src/sys/wasi/fd.rs +++ b/library/std/src/sys/wasi/fd.rs @@ -228,6 +228,10 @@ impl WasiFd { unsafe { wasi::path_remove_directory(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) } } + pub fn sock_accept(&self, flags: wasi::Fdflags) -> io::Result<wasi::Fd> { + unsafe { wasi::sock_accept(self.as_raw_fd() as wasi::Fd, flags).map_err(err2io) } + } + pub fn sock_recv( &self, ri_data: &mut [IoSliceMut<'_>], diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs index 8d62335aae5..f878941939c 100644 --- a/library/std/src/sys/wasi/mod.rs +++ b/library/std/src/sys/wasi/mod.rs @@ -61,23 +61,26 @@ pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind { if errno > u16::MAX as i32 || errno < 0 { return Uncategorized; } - match errno as u16 { - wasi::ERRNO_CONNREFUSED => ConnectionRefused, - wasi::ERRNO_CONNRESET => ConnectionReset, - wasi::ERRNO_PERM | wasi::ERRNO_ACCES => PermissionDenied, - wasi::ERRNO_PIPE => BrokenPipe, - wasi::ERRNO_NOTCONN => NotConnected, - wasi::ERRNO_CONNABORTED => ConnectionAborted, - wasi::ERRNO_ADDRNOTAVAIL => AddrNotAvailable, - wasi::ERRNO_ADDRINUSE => AddrInUse, - wasi::ERRNO_NOENT => NotFound, - wasi::ERRNO_INTR => Interrupted, - wasi::ERRNO_INVAL => InvalidInput, - wasi::ERRNO_TIMEDOUT => TimedOut, - wasi::ERRNO_EXIST => AlreadyExists, - wasi::ERRNO_AGAIN => WouldBlock, - wasi::ERRNO_NOSYS => Unsupported, - wasi::ERRNO_NOMEM => OutOfMemory, + + match errno { + e if e == wasi::ERRNO_CONNREFUSED.raw().into() => ConnectionRefused, + e if e == wasi::ERRNO_CONNRESET.raw().into() => ConnectionReset, + e if e == wasi::ERRNO_PERM.raw().into() || e == wasi::ERRNO_ACCES.raw().into() => { + PermissionDenied + } + e if e == wasi::ERRNO_PIPE.raw().into() => BrokenPipe, + e if e == wasi::ERRNO_NOTCONN.raw().into() => NotConnected, + e if e == wasi::ERRNO_CONNABORTED.raw().into() => ConnectionAborted, + e if e == wasi::ERRNO_ADDRNOTAVAIL.raw().into() => AddrNotAvailable, + e if e == wasi::ERRNO_ADDRINUSE.raw().into() => AddrInUse, + e if e == wasi::ERRNO_NOENT.raw().into() => NotFound, + e if e == wasi::ERRNO_INTR.raw().into() => Interrupted, + e if e == wasi::ERRNO_INVAL.raw().into() => InvalidInput, + e if e == wasi::ERRNO_TIMEDOUT.raw().into() => TimedOut, + e if e == wasi::ERRNO_EXIST.raw().into() => AlreadyExists, + e if e == wasi::ERRNO_AGAIN.raw().into() => WouldBlock, + e if e == wasi::ERRNO_NOSYS.raw().into() => Unsupported, + e if e == wasi::ERRNO_NOMEM.raw().into() => OutOfMemory, _ => Uncategorized, } } @@ -96,6 +99,6 @@ pub fn hashmap_random_keys() -> (u64, u64) { return ret; } -fn err2io(err: wasi::Error) -> std_io::Error { - std_io::Error::from_raw_os_error(err.raw_error().into()) +fn err2io(err: wasi::Errno) -> std_io::Error { + std_io::Error::from_raw_os_error(err.raw().into()) } diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs index a4dbb225376..c66e0e4d328 100644 --- a/library/std/src/sys/wasi/net.rs +++ b/library/std/src/sys/wasi/net.rs @@ -1,5 +1,6 @@ #![deny(unsafe_op_in_unsafe_fn)] +use super::err2io; use super::fd::WasiFd; use crate::convert::TryFrom; use crate::fmt; @@ -87,24 +88,24 @@ impl TcpStream { unsupported() } - pub fn read(&self, _: &mut [u8]) -> io::Result<usize> { - unsupported() + pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { + self.read_vectored(&mut [IoSliceMut::new(buf)]) } - pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - unsupported() + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { + self.socket().as_inner().read(bufs) } pub fn is_read_vectored(&self) -> bool { true } - pub fn write(&self, _: &[u8]) -> io::Result<usize> { - unsupported() + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { + self.write_vectored(&[IoSlice::new(buf)]) } - pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> { - unsupported() + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { + self.socket().as_inner().write(bufs) } pub fn is_write_vectored(&self) -> bool { @@ -155,8 +156,23 @@ impl TcpStream { unsupported() } - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - unsupported() + pub fn set_nonblocking(&self, state: bool) -> io::Result<()> { + let fdstat = unsafe { + wasi::fd_fdstat_get(self.socket().as_inner().as_raw_fd() as wasi::Fd).map_err(err2io)? + }; + + let mut flags = fdstat.fs_flags; + + if state { + flags |= wasi::FDFLAGS_NONBLOCK; + } else { + flags &= !wasi::FDFLAGS_NONBLOCK; + } + + unsafe { + wasi::fd_fdstat_set_flags(self.socket().as_inner().as_raw_fd() as wasi::Fd, flags) + .map_err(err2io) + } } pub fn socket(&self) -> &Socket { @@ -194,7 +210,16 @@ impl TcpListener { } pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { - unsupported() + let fd = unsafe { + wasi::sock_accept(self.as_inner().as_inner().as_raw_fd() as _, 0).map_err(err2io)? + }; + + Ok(( + TcpStream::from_inner(unsafe { Socket::from_raw_fd(fd as _) }), + // WASI has no concept of SocketAddr yet + // return an unspecified IPv4Addr + SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 0), + )) } pub fn duplicate(&self) -> io::Result<TcpListener> { @@ -221,8 +246,23 @@ impl TcpListener { unsupported() } - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - unsupported() + pub fn set_nonblocking(&self, state: bool) -> io::Result<()> { + let fdstat = unsafe { + wasi::fd_fdstat_get(self.socket().as_inner().as_raw_fd() as wasi::Fd).map_err(err2io)? + }; + + let mut flags = fdstat.fs_flags; + + if state { + flags |= wasi::FDFLAGS_NONBLOCK; + } else { + flags &= !wasi::FDFLAGS_NONBLOCK; + } + + unsafe { + wasi::fd_fdstat_set_flags(self.socket().as_inner().as_raw_fd() as wasi::Fd, flags) + .map_err(err2io) + } } pub fn socket(&self) -> &Socket { diff --git a/library/std/src/sys/wasi/stdio.rs b/library/std/src/sys/wasi/stdio.rs index 2c8f394cd47..4cc0e4ed5a4 100644 --- a/library/std/src/sys/wasi/stdio.rs +++ b/library/std/src/sys/wasi/stdio.rs @@ -104,7 +104,7 @@ impl io::Write for Stderr { pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(wasi::ERRNO_BADF.into()) + err.raw_os_error() == Some(wasi::ERRNO_BADF.raw().into()) } pub fn panic_output() -> Option<impl io::Write> { diff --git a/library/std/src/sys/wasi/thread.rs b/library/std/src/sys/wasi/thread.rs index 2e4e474c449..e7a6ab4be82 100644 --- a/library/std/src/sys/wasi/thread.rs +++ b/library/std/src/sys/wasi/thread.rs @@ -41,8 +41,7 @@ impl Thread { let in_ = wasi::Subscription { userdata: USERDATA, - r#type: wasi::EVENTTYPE_CLOCK, - u: wasi::SubscriptionU { clock }, + u: wasi::SubscriptionU { tag: 0, u: wasi::SubscriptionUU { clock } }, }; unsafe { let mut event: wasi::Event = mem::zeroed(); @@ -51,7 +50,10 @@ impl Thread { ( Ok(1), wasi::Event { - userdata: USERDATA, error: 0, r#type: wasi::EVENTTYPE_CLOCK, .. + userdata: USERDATA, + error: wasi::ERRNO_SUCCESS, + type_: wasi::EVENTTYPE_CLOCK, + .. }, ) => {} _ => panic!("thread::sleep(): unexpected result of poll_oneoff"), diff --git a/library/std/src/sys/wasi/time.rs b/library/std/src/sys/wasi/time.rs index 2e720d11603..db0ddecf0c6 100644 --- a/library/std/src/sys/wasi/time.rs +++ b/library/std/src/sys/wasi/time.rs @@ -10,7 +10,7 @@ pub struct SystemTime(Duration); pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); -fn current_time(clock: u32) -> Duration { +fn current_time(clock: wasi::Clockid) -> Duration { let ts = unsafe { wasi::clock_time_get( clock, 1, // precision... seems ignored though? diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index dd21c6b4389..028b6b30099 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -460,7 +460,7 @@ impl File { } pub fn duplicate(&self) -> io::Result<File> { - Ok(File { handle: self.handle.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)? }) + Ok(Self { handle: self.handle.try_clone()? }) } fn reparse_point<'a>( diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index c3a3482f910..daab39bb00c 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -262,26 +262,17 @@ impl Handle { Ok(written as usize) } + pub fn try_clone(&self) -> io::Result<Self> { + Ok(Self(self.0.try_clone()?)) + } + pub fn duplicate( &self, access: c::DWORD, inherit: bool, options: c::DWORD, - ) -> io::Result<Handle> { - let mut ret = 0 as c::HANDLE; - cvt(unsafe { - let cur_proc = c::GetCurrentProcess(); - c::DuplicateHandle( - cur_proc, - self.as_raw_handle(), - cur_proc, - &mut ret, - access, - inherit as c::BOOL, - options, - ) - })?; - unsafe { Ok(Handle::from_raw_handle(ret)) } + ) -> io::Result<Self> { + Ok(Self(self.0.duplicate(access, inherit, options)?)) } } diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index 084af4325e7..ad4492f9d1f 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -285,6 +285,7 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD { #[allow(unreachable_code)] pub fn abort_internal() -> ! { const FAST_FAIL_FATAL_APP_EXIT: usize = 7; + #[cfg(not(miri))] // inline assembly does not work in Miri unsafe { cfg_if::cfg_if! { if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index 9c631e7e51c..14d5f15d202 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -134,7 +134,7 @@ impl Socket { unsafe { let socket = Self::from_raw_socket(socket); - socket.set_no_inherit()?; + socket.0.set_no_inherit()?; Ok(socket) } } @@ -213,52 +213,7 @@ impl Socket { } pub fn duplicate(&self) -> io::Result<Socket> { - let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() }; - let result = unsafe { - c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info) - }; - cvt(result)?; - let socket = unsafe { - c::WSASocketW( - info.iAddressFamily, - info.iSocketType, - info.iProtocol, - &mut info, - 0, - c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT, - ) - }; - - if socket != c::INVALID_SOCKET { - unsafe { Ok(Self::from_inner(OwnedSocket::from_raw_socket(socket))) } - } else { - let error = unsafe { c::WSAGetLastError() }; - - if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL { - return Err(io::Error::from_raw_os_error(error)); - } - - let socket = unsafe { - c::WSASocketW( - info.iAddressFamily, - info.iSocketType, - info.iProtocol, - &mut info, - 0, - c::WSA_FLAG_OVERLAPPED, - ) - }; - - if socket == c::INVALID_SOCKET { - return Err(last_error()); - } - - unsafe { - let socket = Self::from_inner(OwnedSocket::from_raw_socket(socket)); - socket.set_no_inherit()?; - Ok(socket) - } - } + Ok(Self(self.0.try_clone()?)) } fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> { @@ -421,19 +376,6 @@ impl Socket { } } - #[cfg(not(target_vendor = "uwp"))] - fn set_no_inherit(&self) -> io::Result<()> { - sys::cvt(unsafe { - c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0) - }) - .map(drop) - } - - #[cfg(target_vendor = "uwp")] - fn set_no_inherit(&self) -> io::Result<()> { - Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Unavailable on UWP")) - } - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { let how = match how { Shutdown::Write => c::SD_SEND, diff --git a/library/std/src/sys_common/io.rs b/library/std/src/sys_common/io.rs index ea9108f1713..d1e9fed41fc 100644 --- a/library/std/src/sys_common/io.rs +++ b/library/std/src/sys_common/io.rs @@ -8,6 +8,7 @@ pub mod test { use crate::env; use crate::fs; use crate::path::{Path, PathBuf}; + use crate::thread; use rand::RngCore; pub struct TempDir(PathBuf); @@ -29,7 +30,12 @@ pub mod test { // Gee, seeing how we're testing the fs module I sure hope that we // at least implement this correctly! let TempDir(ref p) = *self; - fs::remove_dir_all(p).unwrap(); + let result = fs::remove_dir_all(p); + // Avoid panicking while panicking as this causes the process to + // immediately abort, without displaying test results. + if !thread::panicking() { + result.unwrap(); + } } } diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 546f8a15b70..f8d790c3785 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -180,6 +180,12 @@ use crate::time::Duration; #[macro_use] mod local; +#[unstable(feature = "scoped_threads", issue = "93203")] +mod scoped; + +#[unstable(feature = "scoped_threads", issue = "93203")] +pub use scoped::{scope, Scope, ScopedJoinHandle}; + #[stable(feature = "rust1", since = "1.0.0")] pub use self::local::{AccessError, LocalKey}; @@ -447,6 +453,20 @@ impl Builder { F: Send + 'a, T: Send + 'a, { + Ok(JoinHandle(unsafe { self.spawn_unchecked_(f, None) }?)) + } + + unsafe fn spawn_unchecked_<'a, 'scope, F, T>( + self, + f: F, + scope_data: Option<&'scope scoped::ScopeData>, + ) -> io::Result<JoinInner<'scope, T>> + where + F: FnOnce() -> T, + F: Send + 'a, + T: Send + 'a, + 'scope: 'a, + { let Builder { name, stack_size } = self; let stack_size = stack_size.unwrap_or_else(thread::min_stack); @@ -456,7 +476,8 @@ impl Builder { })); let their_thread = my_thread.clone(); - let my_packet: Arc<UnsafeCell<Option<Result<T>>>> = Arc::new(UnsafeCell::new(None)); + let my_packet: Arc<Packet<'scope, T>> = + Arc::new(Packet { scope: scope_data, result: UnsafeCell::new(None) }); let their_packet = my_packet.clone(); let output_capture = crate::io::set_output_capture(None); @@ -480,10 +501,14 @@ impl Builder { // closure (it is an Arc<...>) and `my_packet` will be stored in the // same `JoinInner` as this closure meaning the mutation will be // safe (not modify it and affect a value far away). - unsafe { *their_packet.get() = Some(try_result) }; + unsafe { *their_packet.result.get() = Some(try_result) }; }; - Ok(JoinHandle(JoinInner { + if let Some(scope_data) = scope_data { + scope_data.increment_num_running_threads(); + } + + Ok(JoinInner { // SAFETY: // // `imp::Thread::new` takes a closure with a `'static` lifetime, since it's passed @@ -506,8 +531,8 @@ impl Builder { )? }, thread: my_thread, - packet: Packet(my_packet), - })) + packet: my_packet, + }) } } @@ -1242,34 +1267,48 @@ impl fmt::Debug for Thread { #[stable(feature = "rust1", since = "1.0.0")] pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>; -// This packet is used to communicate the return value between the spawned thread -// and the rest of the program. Memory is shared through the `Arc` within and there's -// no need for a mutex here because synchronization happens with `join()` (the -// caller will never read this packet until the thread has exited). +// This packet is used to communicate the return value between the spawned +// thread and the rest of the program. It is shared through an `Arc` and +// there's no need for a mutex here because synchronization happens with `join()` +// (the caller will never read this packet until the thread has exited). // -// This packet itself is then stored into a `JoinInner` which in turns is placed -// in `JoinHandle` and `JoinGuard`. Due to the usage of `UnsafeCell` we need to -// manually worry about impls like Send and Sync. The type `T` should -// already always be Send (otherwise the thread could not have been created) and -// this type is inherently Sync because no methods take &self. Regardless, -// however, we add inheriting impls for Send/Sync to this type to ensure it's -// Send/Sync and that future modifications will still appropriately classify it. -struct Packet<T>(Arc<UnsafeCell<Option<Result<T>>>>); - -unsafe impl<T: Send> Send for Packet<T> {} -unsafe impl<T: Sync> Sync for Packet<T> {} +// An Arc to the packet is stored into a `JoinInner` which in turns is placed +// in `JoinHandle`. +struct Packet<'scope, T> { + scope: Option<&'scope scoped::ScopeData>, + result: UnsafeCell<Option<Result<T>>>, +} + +// Due to the usage of `UnsafeCell` we need to manually implement Sync. +// The type `T` should already always be Send (otherwise the thread could not +// have been created) and the Packet is Sync because all access to the +// `UnsafeCell` synchronized (by the `join()` boundary), and `ScopeData` is Sync. +unsafe impl<'scope, T: Sync> Sync for Packet<'scope, T> {} + +impl<'scope, T> Drop for Packet<'scope, T> { + fn drop(&mut self) { + // Book-keeping so the scope knows when it's done. + if let Some(scope) = self.scope { + // If this packet was for a thread that ran in a scope, the thread + // panicked, and nobody consumed the panic payload, we make sure + // the scope function will panic. + let unhandled_panic = matches!(self.result.get_mut(), Some(Err(_))); + scope.decrement_num_running_threads(unhandled_panic); + } + } +} /// Inner representation for JoinHandle -struct JoinInner<T> { +struct JoinInner<'scope, T> { native: imp::Thread, thread: Thread, - packet: Packet<T>, + packet: Arc<Packet<'scope, T>>, } -impl<T> JoinInner<T> { +impl<'scope, T> JoinInner<'scope, T> { fn join(mut self) -> Result<T> { self.native.join(); - Arc::get_mut(&mut self.packet.0).unwrap().get_mut().take().unwrap() + Arc::get_mut(&mut self.packet).unwrap().result.get_mut().take().unwrap() } } @@ -1336,7 +1375,7 @@ impl<T> JoinInner<T> { /// [`thread::Builder::spawn`]: Builder::spawn /// [`thread::spawn`]: spawn #[stable(feature = "rust1", since = "1.0.0")] -pub struct JoinHandle<T>(JoinInner<T>); +pub struct JoinHandle<T>(JoinInner<'static, T>); #[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")] unsafe impl<T> Send for JoinHandle<T> {} @@ -1404,13 +1443,13 @@ impl<T> JoinHandle<T> { self.0.join() } - /// Checks if the the associated thread is still running its main function. + /// Checks if the associated thread is still running its main function. /// /// This might return `false` for a brief moment after the thread's main /// function has returned, but before the thread itself has stopped running. #[unstable(feature = "thread_is_running", issue = "90470")] pub fn is_running(&self) -> bool { - Arc::strong_count(&self.0.packet.0) > 1 + Arc::strong_count(&self.0.packet) > 1 } } diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs new file mode 100644 index 00000000000..9dd7c15fc59 --- /dev/null +++ b/library/std/src/thread/scoped.rs @@ -0,0 +1,316 @@ +use super::{current, park, Builder, JoinInner, Result, Thread}; +use crate::fmt; +use crate::io; +use crate::marker::PhantomData; +use crate::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; +use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use crate::sync::Arc; + +/// A scope to spawn scoped threads in. +/// +/// See [`scope`] for details. +pub struct Scope<'env> { + data: ScopeData, + /// Invariance over 'env, to make sure 'env cannot shrink, + /// which is necessary for soundness. + /// + /// Without invariance, this would compile fine but be unsound: + /// + /// ```compile_fail + /// #![feature(scoped_threads)] + /// + /// std::thread::scope(|s| { + /// s.spawn(|s| { + /// let a = String::from("abcd"); + /// s.spawn(|_| println!("{:?}", a)); // might run after `a` is dropped + /// }); + /// }); + /// ``` + env: PhantomData<&'env mut &'env ()>, +} + +/// An owned permission to join on a scoped thread (block on its termination). +/// +/// See [`Scope::spawn`] for details. +pub struct ScopedJoinHandle<'scope, T>(JoinInner<'scope, T>); + +pub(super) struct ScopeData { + num_running_threads: AtomicUsize, + a_thread_panicked: AtomicBool, + main_thread: Thread, +} + +impl ScopeData { + pub(super) fn increment_num_running_threads(&self) { + // We check for 'overflow' with usize::MAX / 2, to make sure there's no + // chance it overflows to 0, which would result in unsoundness. + if self.num_running_threads.fetch_add(1, Ordering::Relaxed) > usize::MAX / 2 { + // This can only reasonably happen by mem::forget()'ing many many ScopedJoinHandles. + self.decrement_num_running_threads(false); + panic!("too many running threads in thread scope"); + } + } + pub(super) fn decrement_num_running_threads(&self, panic: bool) { + if panic { + self.a_thread_panicked.store(true, Ordering::Relaxed); + } + if self.num_running_threads.fetch_sub(1, Ordering::Release) == 1 { + self.main_thread.unpark(); + } + } +} + +/// Create a scope for spawning scoped threads. +/// +/// The function passed to `scope` will be provided a [`Scope`] object, +/// through which scoped threads can be [spawned][`Scope::spawn`]. +/// +/// Unlike non-scoped threads, scoped threads can borrow non-`'static` data, +/// as the scope guarantees all threads will be joined at the end of the scope. +/// +/// All threads spawned within the scope that haven't been manually joined +/// will be automatically joined before this function returns. +/// +/// # Panics +/// +/// If any of the automatically joined threads panicked, this function will panic. +/// +/// If you want to handle panics from spawned threads, +/// [`join`][ScopedJoinHandle::join] them before the end of the scope. +/// +/// # Example +/// +/// ``` +/// #![feature(scoped_threads)] +/// use std::thread; +/// +/// let mut a = vec![1, 2, 3]; +/// let mut x = 0; +/// +/// thread::scope(|s| { +/// s.spawn(|_| { +/// println!("hello from the first scoped thread"); +/// // We can borrow `a` here. +/// dbg!(&a); +/// }); +/// s.spawn(|_| { +/// println!("hello from the second scoped thread"); +/// // We can even mutably borrow `x` here, +/// // because no other threads are using it. +/// x += a[0] + a[2]; +/// }); +/// println!("hello from the main thread"); +/// }); +/// +/// // After the scope, we can modify and access our variables again: +/// a.push(4); +/// assert_eq!(x, a.len()); +/// ``` +#[track_caller] +pub fn scope<'env, F, T>(f: F) -> T +where + F: FnOnce(&Scope<'env>) -> T, +{ + let scope = Scope { + data: ScopeData { + num_running_threads: AtomicUsize::new(0), + main_thread: current(), + a_thread_panicked: AtomicBool::new(false), + }, + env: PhantomData, + }; + + // Run `f`, but catch panics so we can make sure to wait for all the threads to join. + let result = catch_unwind(AssertUnwindSafe(|| f(&scope))); + + // Wait until all the threads are finished. + while scope.data.num_running_threads.load(Ordering::Acquire) != 0 { + park(); + } + + // Throw any panic from `f`, or the return value of `f` if no thread panicked. + match result { + Err(e) => resume_unwind(e), + Ok(_) if scope.data.a_thread_panicked.load(Ordering::Relaxed) => { + panic!("a scoped thread panicked") + } + Ok(result) => result, + } +} + +impl<'env> Scope<'env> { + /// Spawns a new thread within a scope, returning a [`ScopedJoinHandle`] for it. + /// + /// Unlike non-scoped threads, threads spawned with this function may + /// borrow non-`'static` data from the outside the scope. See [`scope`] for + /// details. + /// + /// The join handle provides a [`join`] method that can be used to join the spawned + /// thread. If the spawned thread panics, [`join`] will return an [`Err`] containing + /// the panic payload. + /// + /// If the join handle is dropped, the spawned thread will implicitly joined at the + /// end of the scope. In that case, if the spawned thread panics, [`scope`] will + /// panic after all threads are joined. + /// + /// This call will create a thread using default parameters of [`Builder`]. + /// If you want to specify the stack size or the name of the thread, use + /// [`Builder::spawn_scoped`] instead. + /// + /// # Panics + /// + /// Panics if the OS fails to create a thread; use [`Builder::spawn_scoped`] + /// to recover from such errors. + /// + /// [`join`]: ScopedJoinHandle::join + pub fn spawn<'scope, F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T> + where + F: FnOnce(&Scope<'env>) -> T + Send + 'env, + T: Send + 'env, + { + Builder::new().spawn_scoped(self, f).expect("failed to spawn thread") + } +} + +impl Builder { + /// Spawns a new scoped thread using the settings set through this `Builder`. + /// + /// Unlike [`Scope::spawn`], this method yields an [`io::Result`] to + /// capture any failure to create the thread at the OS level. + /// + /// [`io::Result`]: crate::io::Result + /// + /// # Panics + /// + /// Panics if a thread name was set and it contained null bytes. + /// + /// # Example + /// + /// ``` + /// #![feature(scoped_threads)] + /// use std::thread; + /// + /// let mut a = vec![1, 2, 3]; + /// let mut x = 0; + /// + /// thread::scope(|s| { + /// thread::Builder::new() + /// .name("first".to_string()) + /// .spawn_scoped(s, |_| + /// { + /// println!("hello from the {:?} scoped thread", thread::current().name()); + /// // We can borrow `a` here. + /// dbg!(&a); + /// }) + /// .unwrap(); + /// thread::Builder::new() + /// .name("second".to_string()) + /// .spawn_scoped(s, |_| + /// { + /// println!("hello from the {:?} scoped thread", thread::current().name()); + /// // We can even mutably borrow `x` here, + /// // because no other threads are using it. + /// x += a[0] + a[2]; + /// }) + /// .unwrap(); + /// println!("hello from the main thread"); + /// }); + /// + /// // After the scope, we can modify and access our variables again: + /// a.push(4); + /// assert_eq!(x, a.len()); + /// ``` + pub fn spawn_scoped<'scope, 'env, F, T>( + self, + scope: &'scope Scope<'env>, + f: F, + ) -> io::Result<ScopedJoinHandle<'scope, T>> + where + F: FnOnce(&Scope<'env>) -> T + Send + 'env, + T: Send + 'env, + { + Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(|| f(scope), Some(&scope.data)) }?)) + } +} + +impl<'scope, T> ScopedJoinHandle<'scope, T> { + /// Extracts a handle to the underlying thread. + /// + /// # Examples + /// + /// ``` + /// #![feature(scoped_threads)] + /// #![feature(thread_is_running)] + /// + /// use std::thread; + /// + /// thread::scope(|s| { + /// let t = s.spawn(|_| { + /// println!("hello"); + /// }); + /// println!("thread id: {:?}", t.thread().id()); + /// }); + /// ``` + #[must_use] + pub fn thread(&self) -> &Thread { + &self.0.thread + } + + /// Waits for the associated thread to finish. + /// + /// This function will return immediately if the associated thread has already finished. + /// + /// In terms of [atomic memory orderings], the completion of the associated + /// thread synchronizes with this function returning. + /// In other words, all operations performed by that thread + /// [happen before](https://doc.rust-lang.org/nomicon/atomics.html#data-accesses) + /// all operations that happen after `join` returns. + /// + /// If the associated thread panics, [`Err`] is returned with the panic payload. + /// + /// [atomic memory orderings]: crate::sync::atomic + /// + /// # Examples + /// + /// ``` + /// #![feature(scoped_threads)] + /// #![feature(thread_is_running)] + /// + /// use std::thread; + /// + /// thread::scope(|s| { + /// let t = s.spawn(|_| { + /// panic!("oh no"); + /// }); + /// assert!(t.join().is_err()); + /// }); + /// ``` + pub fn join(self) -> Result<T> { + self.0.join() + } + + /// Checks if the associated thread is still running its main function. + /// + /// This might return `false` for a brief moment after the thread's main + /// function has returned, but before the thread itself has stopped running. + #[unstable(feature = "thread_is_running", issue = "90470")] + pub fn is_running(&self) -> bool { + Arc::strong_count(&self.0.packet) > 1 + } +} + +impl<'env> fmt::Debug for Scope<'env> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Scope") + .field("num_running_threads", &self.data.num_running_threads.load(Ordering::Relaxed)) + .field("a_thread_panicked", &self.data.a_thread_panicked.load(Ordering::Relaxed)) + .field("main_thread", &self.data.main_thread) + .finish_non_exhaustive() + } +} + +impl<'scope, T> fmt::Debug for ScopedJoinHandle<'scope, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ScopedJoinHandle").finish_non_exhaustive() + } +} diff --git a/library/std/src/time.rs b/library/std/src/time.rs index b6867e68df7..b4f9d8ea28d 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -45,7 +45,7 @@ use crate::sys_common::FromInner; pub use core::time::Duration; #[unstable(feature = "duration_checked_float", issue = "83400")] -pub use core::time::FromSecsError; +pub use core::time::FromFloatSecsError; /// A measurement of a monotonically nondecreasing clock. /// Opaque and useful only with [`Duration`]. diff --git a/library/std/tests/run-time-detect.rs b/library/std/tests/run-time-detect.rs index 079f00a5753..14a9e3acca4 100644 --- a/library/std/tests/run-time-detect.rs +++ b/library/std/tests/run-time-detect.rs @@ -14,6 +14,7 @@ #[test] #[cfg(all(target_arch = "arm", any(target_os = "linux", target_os = "android")))] fn arm_linux() { + use std::arch::is_arm_feature_detected; println!("neon: {}", is_arm_feature_detected!("neon")); println!("pmull: {}", is_arm_feature_detected!("pmull")); println!("crypto: {}", is_arm_feature_detected!("crypto")); @@ -25,6 +26,7 @@ fn arm_linux() { #[test] #[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))] fn aarch64_linux() { + use std::arch::is_aarch64_feature_detected; println!("neon: {}", is_aarch64_feature_detected!("neon")); println!("asimd: {}", is_aarch64_feature_detected!("asimd")); println!("pmull: {}", is_aarch64_feature_detected!("pmull")); @@ -71,6 +73,7 @@ fn aarch64_linux() { #[test] #[cfg(all(target_arch = "powerpc", target_os = "linux"))] fn powerpc_linux() { + use std::arch::is_powerpc_feature_detected; println!("altivec: {}", is_powerpc_feature_detected!("altivec")); println!("vsx: {}", is_powerpc_feature_detected!("vsx")); println!("power8: {}", is_powerpc_feature_detected!("power8")); @@ -79,6 +82,7 @@ fn powerpc_linux() { #[test] #[cfg(all(target_arch = "powerpc64", target_os = "linux"))] fn powerpc64_linux() { + use std::arch::is_powerpc64_feature_detected; println!("altivec: {}", is_powerpc64_feature_detected!("altivec")); println!("vsx: {}", is_powerpc64_feature_detected!("vsx")); println!("power8: {}", is_powerpc64_feature_detected!("power8")); @@ -87,6 +91,8 @@ fn powerpc64_linux() { #[test] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn x86_all() { + use std::arch::is_x86_feature_detected; + // the below is the set of features we can test at runtime, but don't actually // use to gate anything and are thus not part of the X86_ALLOWED_FEATURES list diff --git a/library/stdarch b/library/stdarch -Subproject 11c98f6eb9c4ba48b2362ad4960343b312d056b +Subproject eaee02ffdf5d820729ccdf2f95fa08b08c7d24d diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 6ccf8b1d522..4f88b5854b6 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -7,7 +7,7 @@ use std::fmt::Debug; use std::fs; use std::hash::Hash; use std::ops::Deref; -use std::path::{Path, PathBuf}; +use std::path::{Component, Path, PathBuf}; use std::process::Command; use std::time::{Duration, Instant}; @@ -105,6 +105,44 @@ struct StepDescription { should_run: fn(ShouldRun<'_>) -> ShouldRun<'_>, make_run: fn(RunConfig<'_>), name: &'static str, + kind: Kind, +} + +#[derive(Clone, PartialOrd, Ord, PartialEq, Eq)] +pub struct TaskPath { + pub path: PathBuf, + pub kind: Option<Kind>, +} + +impl TaskPath { + pub fn parse(path: impl Into<PathBuf>) -> TaskPath { + let mut kind = None; + let mut path = path.into(); + + let mut components = path.components(); + if let Some(Component::Normal(os_str)) = components.next() { + if let Some(str) = os_str.to_str() { + if let Some((found_kind, found_prefix)) = str.split_once("::") { + if found_kind.is_empty() { + panic!("empty kind in task path {}", path.display()); + } + kind = Some(Kind::parse(found_kind)); + path = Path::new(found_prefix).join(components.as_path()); + } + } + } + + TaskPath { path, kind } + } +} + +impl Debug for TaskPath { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if let Some(kind) = &self.kind { + write!(f, "{}::", kind.as_str())?; + } + write!(f, "{}", self.path.display()) + } } /// Collection of paths used to match a task rule. @@ -115,14 +153,14 @@ pub enum PathSet { /// These are generally matched as a path suffix. For example, a /// command-line value of `libstd` will match if `src/libstd` is in the /// set. - Set(BTreeSet<PathBuf>), + Set(BTreeSet<TaskPath>), /// A "suite" of paths. /// /// These can match as a path suffix (like `Set`), or as a prefix. For /// example, a command-line value of `src/test/ui/abi/variadic-ffi.rs` /// will match `src/test/ui`. A command-line value of `ui` would also /// match `src/test/ui`. - Suite(PathBuf), + Suite(TaskPath), } impl PathSet { @@ -130,35 +168,46 @@ impl PathSet { PathSet::Set(BTreeSet::new()) } - fn one<P: Into<PathBuf>>(path: P) -> PathSet { + fn one<P: Into<PathBuf>>(path: P, kind: Kind) -> PathSet { let mut set = BTreeSet::new(); - set.insert(path.into()); + set.insert(TaskPath { path: path.into(), kind: Some(kind.into()) }); PathSet::Set(set) } - fn has(&self, needle: &Path) -> bool { + fn has(&self, needle: &Path, module: Option<Kind>) -> bool { + let check = |p: &TaskPath| { + if let (Some(p_kind), Some(kind)) = (&p.kind, module) { + p.path.ends_with(needle) && *p_kind == kind + } else { + p.path.ends_with(needle) + } + }; + match self { - PathSet::Set(set) => set.iter().any(|p| p.ends_with(needle)), - PathSet::Suite(suite) => suite.ends_with(needle), + PathSet::Set(set) => set.iter().any(check), + PathSet::Suite(suite) => check(suite), } } fn path(&self, builder: &Builder<'_>) -> PathBuf { match self { - PathSet::Set(set) => set.iter().next().unwrap_or(&builder.build.src).to_path_buf(), - PathSet::Suite(path) => PathBuf::from(path), + PathSet::Set(set) => { + set.iter().next().map(|p| &p.path).unwrap_or(&builder.build.src).clone() + } + PathSet::Suite(path) => path.path.clone(), } } } impl StepDescription { - fn from<S: Step>() -> StepDescription { + fn from<S: Step>(kind: Kind) -> StepDescription { StepDescription { default: S::DEFAULT, only_hosts: S::ONLY_HOSTS, should_run: S::should_run, make_run: S::make_run, name: std::any::type_name::<S>(), + kind, } } @@ -177,7 +226,7 @@ impl StepDescription { } fn is_excluded(&self, builder: &Builder<'_>, pathset: &PathSet) -> bool { - if builder.config.exclude.iter().any(|e| pathset.has(e)) { + if builder.config.exclude.iter().any(|e| pathset.has(&e.path, e.kind)) { eprintln!("Skipping {:?} because it is excluded", pathset); return true; } @@ -192,8 +241,10 @@ impl StepDescription { } fn run(v: &[StepDescription], builder: &Builder<'_>, paths: &[PathBuf]) { - let should_runs = - v.iter().map(|desc| (desc.should_run)(ShouldRun::new(builder))).collect::<Vec<_>>(); + let should_runs = v + .iter() + .map(|desc| (desc.should_run)(ShouldRun::new(builder, desc.kind))) + .collect::<Vec<_>>(); // sanity checks on rules for (desc, should_run) in v.iter().zip(&should_runs) { @@ -226,7 +277,7 @@ impl StepDescription { if let Some(suite) = should_run.is_suite_path(path) { attempted_run = true; desc.maybe_run(builder, suite); - } else if let Some(pathset) = should_run.pathset_for_path(path) { + } else if let Some(pathset) = should_run.pathset_for_path(path, desc.kind) { attempted_run = true; desc.maybe_run(builder, pathset); } @@ -246,6 +297,8 @@ enum ReallyDefault<'a> { pub struct ShouldRun<'a> { pub builder: &'a Builder<'a>, + kind: Kind, + // use a BTreeSet to maintain sort order paths: BTreeSet<PathSet>, @@ -255,9 +308,10 @@ pub struct ShouldRun<'a> { } impl<'a> ShouldRun<'a> { - fn new(builder: &'a Builder<'_>) -> ShouldRun<'a> { + fn new(builder: &'a Builder<'_>, kind: Kind) -> ShouldRun<'a> { ShouldRun { builder, + kind, paths: BTreeSet::new(), is_really_default: ReallyDefault::Bool(true), // by default no additional conditions } @@ -293,7 +347,7 @@ impl<'a> ShouldRun<'a> { let mut set = BTreeSet::new(); for krate in self.builder.in_tree_crates(name, None) { let path = krate.local_path(self.builder); - set.insert(path); + set.insert(TaskPath { path, kind: Some(self.kind) }); } self.paths.insert(PathSet::Set(set)); self @@ -306,7 +360,7 @@ impl<'a> ShouldRun<'a> { pub fn krate(mut self, name: &str) -> Self { for krate in self.builder.in_tree_crates(name, None) { let path = krate.local_path(self.builder); - self.paths.insert(PathSet::one(path)); + self.paths.insert(PathSet::one(path, self.kind)); } self } @@ -318,19 +372,25 @@ impl<'a> ShouldRun<'a> { // multiple aliases for the same job pub fn paths(mut self, paths: &[&str]) -> Self { - self.paths.insert(PathSet::Set(paths.iter().map(PathBuf::from).collect())); + self.paths.insert(PathSet::Set( + paths + .iter() + .map(|p| TaskPath { path: p.into(), kind: Some(self.kind.into()) }) + .collect(), + )); self } pub fn is_suite_path(&self, path: &Path) -> Option<&PathSet> { self.paths.iter().find(|pathset| match pathset { - PathSet::Suite(p) => path.starts_with(p), + PathSet::Suite(p) => path.starts_with(&p.path), PathSet::Set(_) => false, }) } pub fn suite_path(mut self, suite: &str) -> Self { - self.paths.insert(PathSet::Suite(PathBuf::from(suite))); + self.paths + .insert(PathSet::Suite(TaskPath { path: suite.into(), kind: Some(self.kind.into()) })); self } @@ -340,12 +400,12 @@ impl<'a> ShouldRun<'a> { self } - fn pathset_for_path(&self, path: &Path) -> Option<&PathSet> { - self.paths.iter().find(|pathset| pathset.has(path)) + fn pathset_for_path(&self, path: &Path, kind: Kind) -> Option<&PathSet> { + self.paths.iter().find(|pathset| pathset.has(path, Some(kind))) } } -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] pub enum Kind { Build, Check, @@ -359,11 +419,44 @@ pub enum Kind { Run, } +impl Kind { + fn parse(string: &str) -> Kind { + match string { + "build" => Kind::Build, + "check" => Kind::Check, + "clippy" => Kind::Clippy, + "fix" => Kind::Fix, + "test" => Kind::Test, + "bench" => Kind::Bench, + "dist" => Kind::Dist, + "doc" => Kind::Doc, + "install" => Kind::Install, + "run" => Kind::Run, + other => panic!("unknown kind: {}", other), + } + } + + fn as_str(&self) -> &'static str { + match self { + Kind::Build => "build", + Kind::Check => "check", + Kind::Clippy => "clippy", + Kind::Fix => "fix", + Kind::Test => "test", + Kind::Bench => "bench", + Kind::Dist => "dist", + Kind::Doc => "doc", + Kind::Install => "install", + Kind::Run => "run", + } + } +} + impl<'a> Builder<'a> { fn get_step_descriptions(kind: Kind) -> Vec<StepDescription> { macro_rules! describe { ($($rule:ty),+ $(,)?) => {{ - vec![$(StepDescription::from::<$rule>()),+] + vec![$(StepDescription::from::<$rule>(kind)),+] }}; } match kind { @@ -495,7 +588,6 @@ impl<'a> Builder<'a> { dist::RustcDev, dist::Analysis, dist::Src, - dist::PlainSourceTarball, dist::Cargo, dist::Rls, dist::RustAnalyzer, @@ -506,6 +598,11 @@ impl<'a> Builder<'a> { dist::LlvmTools, dist::RustDev, dist::Extended, + // It seems that PlainSourceTarball somehow changes how some of the tools + // perceive their dependencies (see #93033) which would invaliate fingerprints + // and force us to rebuild tools after vendoring dependencies. + // To work around this, create the Tarball after building all the tools. + dist::PlainSourceTarball, dist::BuildManifest, dist::ReproducibleArtifacts, ), @@ -540,8 +637,11 @@ impl<'a> Builder<'a> { let builder = Self::new_internal(build, kind, vec![]); let builder = &builder; - let mut should_run = ShouldRun::new(builder); + // The "build" kind here is just a placeholder, it will be replaced with something else in + // the following statement. + let mut should_run = ShouldRun::new(builder, Kind::Build); for desc in Builder::get_step_descriptions(builder.kind) { + should_run.kind = desc.kind; should_run = (desc.should_run)(should_run); } let mut help = String::from("Available paths:\n"); @@ -552,11 +652,11 @@ impl<'a> Builder<'a> { match pathset { PathSet::Set(set) => { for path in set { - add_path(&path); + add_path(&path.path); } } PathSet::Suite(path) => { - add_path(&path.join("...")); + add_path(&path.path.join("...")); } } } @@ -988,20 +1088,11 @@ impl<'a> Builder<'a> { } }; - // cfg(bootstrap) -- drop the compiler.stage == 0 branch. - if compiler.stage == 0 { - if use_new_symbol_mangling { - rustflags.arg("-Zsymbol-mangling-version=v0"); - } else { - rustflags.arg("-Zsymbol-mangling-version=legacy"); - } + if use_new_symbol_mangling { + rustflags.arg("-Csymbol-mangling-version=v0"); } else { - if use_new_symbol_mangling { - rustflags.arg("-Csymbol-mangling-version=v0"); - } else { - rustflags.arg("-Csymbol-mangling-version=legacy"); - rustflags.arg("-Zunstable-options"); - } + rustflags.arg("-Csymbol-mangling-version=legacy"); + rustflags.arg("-Zunstable-options"); } // FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`, @@ -1626,9 +1717,10 @@ impl<'a> Builder<'a> { pub(crate) fn ensure_if_default<T, S: Step<Output = Option<T>>>( &'a self, step: S, + kind: Kind, ) -> S::Output { - let desc = StepDescription::from::<S>(); - let should_run = (desc.should_run)(ShouldRun::new(self)); + let desc = StepDescription::from::<S>(kind); + let should_run = (desc.should_run)(ShouldRun::new(self, desc.kind)); // Avoid running steps contained in --exclude for pathset in &should_run.paths { @@ -1642,13 +1734,16 @@ impl<'a> Builder<'a> { } /// Checks if any of the "should_run" paths is in the `Builder` paths. - pub(crate) fn was_invoked_explicitly<S: Step>(&'a self) -> bool { - let desc = StepDescription::from::<S>(); - let should_run = (desc.should_run)(ShouldRun::new(self)); + pub(crate) fn was_invoked_explicitly<S: Step>(&'a self, kind: Kind) -> bool { + let desc = StepDescription::from::<S>(kind); + let should_run = (desc.should_run)(ShouldRun::new(self, desc.kind)); for path in &self.paths { - if should_run.paths.iter().any(|s| s.has(path)) - && !desc.is_excluded(self, &PathSet::Suite(path.clone())) + if should_run.paths.iter().any(|s| s.has(path, Some(desc.kind))) + && !desc.is_excluded( + self, + &PathSet::Suite(TaskPath { path: path.clone(), kind: Some(desc.kind.into()) }), + ) { return true; } diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index bb3ea04d4ac..bc710344969 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -499,7 +499,7 @@ mod dist { let host = TargetSelection::from_user("A"); builder.run_step_descriptions( - &[StepDescription::from::<test::Crate>()], + &[StepDescription::from::<test::Crate>(Kind::Test)], &["library/std".into()], ); @@ -520,7 +520,7 @@ mod dist { #[test] fn test_exclude() { let mut config = configure(&["A"], &["A"]); - config.exclude = vec!["src/tools/tidy".into()]; + config.exclude = vec![TaskPath::parse("src/tools/tidy")]; config.cmd = Subcommand::Test { paths: Vec::new(), test_args: Vec::new(), diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 5af9248583c..683cfc630e7 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -12,6 +12,7 @@ use std::fs; use std::path::{Path, PathBuf}; use std::str::FromStr; +use crate::builder::TaskPath; use crate::cache::{Interned, INTERNER}; use crate::channel::GitInfo; pub use crate::flags::Subcommand; @@ -62,7 +63,7 @@ pub struct Config { pub sanitizers: bool, pub profiler: bool, pub ignore_git: bool, - pub exclude: Vec<PathBuf>, + pub exclude: Vec<TaskPath>, pub include_default_paths: bool, pub rustc_error_format: Option<String>, pub json_output: bool, @@ -635,7 +636,7 @@ impl Config { let flags = Flags::parse(&args); let mut config = Config::default_opts(); - config.exclude = flags.exclude; + config.exclude = flags.exclude.into_iter().map(|path| TaskPath::parse(path)).collect(); config.include_default_paths = flags.include_default_paths; config.rustc_error_format = flags.rustc_error_format; config.json_output = flags.json_output; diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index a46a4e63714..66b63cd1278 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -16,7 +16,7 @@ use std::process::Command; use build_helper::{output, t}; -use crate::builder::{Builder, RunConfig, ShouldRun, Step}; +use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; use crate::compile; use crate::config::TargetSelection; @@ -1368,7 +1368,7 @@ impl Step for Extended { let mut built_tools = HashSet::new(); macro_rules! add_component { ($name:expr => $step:expr) => { - if let Some(tarball) = builder.ensure_if_default($step) { + if let Some(tarball) = builder.ensure_if_default($step, Kind::Dist) { tarballs.push(tarball); built_tools.insert($name); } diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index f0f31c447bd..23b5ddcd47a 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -15,7 +15,7 @@ use std::path::{Path, PathBuf}; use crate::Mode; use build_helper::{t, up_to_date}; -use crate::builder::{Builder, Compiler, RunConfig, ShouldRun, Step}; +use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; use crate::compile; use crate::config::{Config, TargetSelection}; @@ -240,7 +240,7 @@ impl Step for TheBook { invoke_rustdoc(builder, compiler, target, path); } - if builder.was_invoked_explicitly::<Self>() { + if builder.was_invoked_explicitly::<Self>(Kind::Doc) { let out = builder.doc_out(target); let index = out.join("book").join("index.html"); open(builder, &index); @@ -400,7 +400,7 @@ impl Step for Standalone { // We open doc/index.html as the default if invoked as `x.py doc --open` // with no particular explicit doc requested (e.g. library/core). - if builder.paths.is_empty() || builder.was_invoked_explicitly::<Self>() { + if builder.paths.is_empty() || builder.was_invoked_explicitly::<Self>(Kind::Doc) { let index = out.join("index.html"); open(builder, &index); } @@ -902,7 +902,7 @@ impl Step for RustcBook { name: INTERNER.intern_str("rustc"), src: INTERNER.intern_path(out_base), }); - if builder.was_invoked_explicitly::<Self>() { + if builder.was_invoked_explicitly::<Self>(Kind::Doc) { let out = builder.doc_out(self.target); let index = out.join("rustc").join("index.html"); open(builder, &index); diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index cb1b0ebf8db..176c06114e0 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1540,6 +1540,9 @@ note: if you're sure you want to do this, please open an issue as to why. In the } } cmd.env("RUSTC_BOOTSTRAP", "1"); + // Override the rustc version used in symbol hashes to reduce the amount of normalization + // needed when diffing test output. + cmd.env("RUSTC_FORCE_RUSTC_VERSION", "compiletest"); cmd.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel()); builder.add_rust_test_threads(&mut cmd); diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index ee58bedcc87..2c78ceb1e5b 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -282,9 +282,10 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef<Path>>( if !path.starts_with(suite_path) { return None; } - let exists = path.is_dir() || path.is_file(); + let abs_path = builder.src.join(path); + let exists = abs_path.is_dir() || abs_path.is_file(); if !exists { - if let Some(p) = path.to_str() { + if let Some(p) = abs_path.to_str() { builder.info(&format!("Warning: Skipping \"{}\": not a regular file or directory", p)); } return None; diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index b1ec072f3f8..28e95d81bb7 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -55,12 +55,6 @@ pub fn restore_library_path() { } } -/// Run the command, printing what we are running. -pub fn run_verbose(cmd: &mut Command) { - println!("running: {:?}", cmd); - run(cmd); -} - pub fn run(cmd: &mut Command) { if !try_run(cmd) { std::process::exit(1); @@ -108,16 +102,6 @@ pub fn try_run_suppressed(cmd: &mut Command) -> bool { output.status.success() } -pub fn gnu_target(target: &str) -> &str { - match target { - "i686-pc-windows-msvc" => "i686-pc-win32", - "x86_64-pc-windows-msvc" => "x86_64-pc-win32", - "i686-pc-windows-gnu" => "i686-w64-mingw32", - "x86_64-pc-windows-gnu" => "x86_64-w64-mingw32", - s => s, - } -} - pub fn make(host: &str) -> PathBuf { if host.contains("dragonfly") || host.contains("freebsd") diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index d4701a25614..c547e12f5b6 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -72,7 +72,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}" # https://github.com/puppeteer/puppeteer/issues/375 # # We also specify the version in case we need to update it to go around cache limitations. -RUN npm install -g browser-ui-test@0.5.3 --unsafe-perm=true +RUN npm install -g browser-ui-test@0.5.8 --unsafe-perm=true ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 80348468976..1a1472ea861 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -452,12 +452,10 @@ jobs: # macOS Builders # #################### - # Only generate documentation for x86_64-apple-darwin, not other - # tier 2 targets produced by this builder. - name: dist-x86_64-apple env: - SCRIPT: ./x.py dist --exclude rust-docs --exclude extended && ./x.py dist --target=x86_64-apple-darwin rust-docs && ./x.py dist extended - RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false + SCRIPT: ./x.py dist --host=x86_64-apple-darwin --target=x86_64-apple-darwin + RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 MACOSX_DEPLOYMENT_TARGET: 10.7 NO_LLVM_ASSERTIONS: 1 @@ -466,6 +464,17 @@ jobs: DIST_REQUIRE_ALL_TOOLS: 1 <<: *job-macos-xl + - name: dist-apple-various + env: + SCRIPT: ./x.py dist --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim + RUST_CONFIGURE_ARGS: --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + NO_OVERFLOW_CHECKS: 1 + <<: *job-macos-xl + - name: dist-x86_64-apple-alt env: SCRIPT: ./x.py dist diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject 1ca6a7bd1d73edc4a3e6c7d6a40f5d4b66c1e51 +Subproject 18c0055b8aea49391e8f758a4400097999c9cf1 diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 53f7108aca3..146408900ab 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -15,7 +15,9 @@ - [Platform Support](platform-support.md) - [Template for target-specific documentation](platform-support/TEMPLATE.md) - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md) + - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md) - [\*-kmc-solid_\*](platform-support/kmc-solid.md) + - [*-unknown-openbsd](platform-support/openbsd.md) - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md) - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md) - [Target Tier Policy](target-tier-policy.md) diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md index 18f1be6a1fa..941c65922d8 100644 --- a/src/doc/rustc/src/linker-plugin-lto.md +++ b/src/doc/rustc/src/linker-plugin-lto.md @@ -86,6 +86,48 @@ option: rustc -Clinker-plugin-lto="/path/to/LLVMgold.so" -L. -Copt-level=2 ./main.rs ``` +### Usage with clang-cl and x86_64-pc-windows-msvc + +Cross language LTO can be used with the x86_64-pc-windows-msvc target, but this requires using the +clang-cl compiler instead of the MSVC cl.exe included with Visual Studio Build Tools, and linking +with lld-link. Both clang-cl and lld-link can be downloaded from [LLVM's download page](https://releases.llvm.org/download.html). +Note that most crates in the ecosystem are likely to assume you are using cl.exe if using this target +and that some things, like for example vcpkg, [don't work very well with clang-cl](https://github.com/microsoft/vcpkg/issues/2087). + +You will want to make sure your rust major LLVM version matches your installed LLVM tooling version, +otherwise it is likely you will get linker errors: + +```bat +rustc -V --verbose +clang-cl --version +``` + +If you are compiling any proc-macros, you will get this error: + +```bash +error: Linker plugin based LTO is not supported together with `-C prefer-dynamic` when +targeting Windows-like targets +``` + +This is fixed if you explicitly set the target, for example +`cargo build --target x86_64-pc-windows-msvc` +Without an explicit --target the flags will be passed to all compiler invocations (including build +scripts and proc macros), see [cargo docs on rustflags](https://doc.rust-lang.org/cargo/reference/config.html#buildrustflags) + +If you have dependencies using the `cc` crate, you will need to set these +environment variables: +```bat +set CC=clang-cl +set CXX=clang-cl +set CFLAGS=/clang:-flto=thin /clang:-fuse-ld=lld-link +set CXXFLAGS=/clang:-flto=thin /clang:-fuse-ld=lld-link +REM Needed because msvc's lib.exe crashes on LLVM LTO .obj files +set AR=llvm-lib +``` + +If you are specifying lld-link as your linker by setting `linker = "lld-link.exe"` in your cargo config, +you may run into issues with some crates that compile code with separate cargo invocations. You should be +able to get around this problem by setting `-Clinker=lld-link` in RUSTFLAGS ## Toolchain Compatibility diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index f4f659ffa27..a31e08f0d12 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -208,7 +208,7 @@ target | std | host | notes `aarch64-unknown-uefi` | * | | ARM64 UEFI `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) `aarch64-unknown-netbsd` | ✓ | ✓ | -`aarch64-unknown-openbsd` | ✓ | ✓ | ARM64 OpenBSD +[`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD `aarch64-unknown-redox` | ? | | ARM64 Redox OS `aarch64-uwp-windows-msvc` | ? | | `aarch64-wrs-vxworks` | ? | | @@ -220,7 +220,7 @@ target | std | host | notes `armv6-unknown-netbsd-eabihf` | ? | | `armv6k-nintendo-3ds` | * | | ARMv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain) `armv7-apple-ios` | ✓ | | ARMv7 iOS, Cortex-a8 -`armv7-unknown-linux-uclibceabihf` | ✓ | ? | ARMv7 Linux uClibc +[`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | ARMv7 Linux uClibc `armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD `armv7-unknown-netbsd-eabihf` | ✓ | ✓ | `armv7-wrs-vxworks-eabihf` | ? | | @@ -237,7 +237,7 @@ target | std | host | notes `i686-pc-windows-msvc` | ✓ | | 32-bit Windows XP support `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku `i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2 -`i686-unknown-openbsd` | ✓ | ✓ | 32-bit OpenBSD +[`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD `i686-unknown-uefi` | * | | 32-bit UEFI `i686-uwp-windows-gnu` | ? | | `i686-uwp-windows-msvc` | ? | | @@ -272,7 +272,7 @@ target | std | host | notes `s390x-unknown-linux-musl` | | | S390x Linux (kernel 2.6.32, MUSL) `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64 -`sparc64-unknown-openbsd` | ? | | +[`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64 `thumbv4t-none-eabi` | * | | ARMv4T T32 `thumbv7a-pc-windows-msvc` | ? | | `thumbv7a-uwp-windows-msvc` | ✓ | | @@ -289,7 +289,7 @@ target | std | host | notes [`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * | | Freestanding/bare-metal x86_64, softfloat `x86_64-unknown-none-hermitkernel` | ? | | HermitCore kernel `x86_64-unknown-none-linuxkernel` | * | | Linux kernel modules -`x86_64-unknown-openbsd` | ✓ | ✓ | 64-bit OpenBSD +[`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD `x86_64-unknown-uefi` | * | | 64-bit UEFI `x86_64-uwp-windows-gnu` | ✓ | | `x86_64-uwp-windows-msvc` | ✓ | | diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md index b3a4275c6ee..1f029406367 100644 --- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md +++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md @@ -18,7 +18,7 @@ This target is cross compiled, and requires a cross toolchain. You can find sui Compiling rust for this target has been tested on `x86_64` linux hosts. Other host types have not been tested, but may work, if you can find a suitable cross compilation toolchain for them. -If you don't already have a suitable toolchain, download one [here](https://toolchains.bootlin.com/downloads/releases/toolchains/armv7-eabihf/tarballs/armv7-eabihf--uclibc--bleeding-edge-2020.08-1.tar.bz2), and unpack it into a directory. +If you don't already have a suitable toolchain, download one [here](https://toolchains.bootlin.com/downloads/releases/toolchains/armv7-eabihf/tarballs/armv7-eabihf--uclibc--bleeding-edge-2021.11-1.tar.bz2), and unpack it into a directory. ### Configure rust diff --git a/src/doc/rustc/src/platform-support/openbsd.md b/src/doc/rustc/src/platform-support/openbsd.md new file mode 100644 index 00000000000..b2ac776eada --- /dev/null +++ b/src/doc/rustc/src/platform-support/openbsd.md @@ -0,0 +1,56 @@ +# \*-unknown-openbsd + +**Tier: 3** + +[OpenBSD] multi-platform 4.4BSD-based UNIX-like operating system. + +[OpenBSD]: https://www.openbsd.org/ + +The target names follow this format: `$ARCH-unknown-openbsd`, where `$ARCH` specifies the target processor architecture. The following targets are currently defined: + +| Target name | C++ library | OpenBSD Platform | +|--------------------------------|-------------|------------------| +| `aarch64-unknown-openbsd` | libc++ | [64-bit ARM systems](https://www.openbsd.org/arm64.html) | +| `i686-unknown-openbsd` | libc++ | [Standard PC and clones based on the Intel i386 architecture and compatible processors](https://www.openbsd.org/i386.html) | +| `sparc64-unknown-openbsd` | estdc++ | [Sun UltraSPARC and Fujitsu SPARC64 systems](https://www.openbsd.org/sparc64.html) | +| `x86_64-unknown-openbsd` | libc++ | [AMD64-based systems](https://www.openbsd.org/amd64.html) | + +Note that all OS versions are *major* even if using X.Y notation (`6.8` and `6.9` are different major versions) and could be binary incompatibles (with breaking changes). + + +## Designated Developers + +- [@semarie](https://github.com/semarie), `semarie@openbsd.org` +- [lang/rust](https://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/lang/rust/Makefile?rev=HEAD&content-type=text/x-cvsweb-markup) maintainer (see MAINTAINER variable) + +Fallback to ports@openbsd.org, OpenBSD third parties public mailing-list (with openbsd developers readers) + + +## Requirements + +These targets are natively compiled and could be cross-compiled. +C compiler toolchain is required for the purpose of building Rust and functional binaries. + +## Building + +The target can be built by enabling it for a `rustc` build. + +```toml +[build] +target = ["$ARCH-unknown-openbsd"] + +[target.$ARCH-unknown-openbsd] +cc = "$ARCH-openbsd-cc" +``` + +## Cross-compilation + +These targets can be cross-compiled, but LLVM might not build out-of-box. + +## Testing + +The Rust testsuite could be run natively. + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for these targets. diff --git a/src/doc/rustdoc/src/references.md b/src/doc/rustdoc/src/references.md index b0e2437392c..45cf4e88eef 100644 --- a/src/doc/rustdoc/src/references.md +++ b/src/doc/rustdoc/src/references.md @@ -16,13 +16,13 @@ If you know of other great resources, please submit a pull request! - [Github tagged RFCs] - [Github tagged issues] - [RFC (stalled) front page styleguide] -- [Guide on how to write documenation for a Rust crate] +- [Guide on how to write documentation for a Rust crate] [API Guidelines]: https://rust-lang.github.io/api-guidelines/documentation.html [Github tagged RFCs]: https://github.com/rust-lang/rfcs/issues?q=label%3AT-rustdoc [Github tagged issues]: https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+label%3AT-rustdoc -[Guide on how to write documenation for a Rust crate]: https://blog.guillaume-gomez.fr/articles/2020-03-12+Guide+on+how+to+write+documentation+for+a+Rust+crate +[Guide on how to write documentation for a Rust crate]: https://blog.guillaume-gomez.fr/articles/2020-03-12+Guide+on+how+to+write+documentation+for+a+Rust+crate [Learn Rust]: https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#making-useful-documentation-comments [RFC 1574: More API Documentation Conventions]: https://rust-lang.github.io/rfcs/1574-more-api-documentation-conventions.html [RFC 1946: Intra Rustdoc Links]: https://rust-lang.github.io/rfcs/1946-intra-rustdoc-links.html diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index ec97eaa8b2b..37fd67447c1 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -15,6 +15,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect - BPF - SPIR-V - AVR +- MSP430 ## Register classes @@ -39,6 +40,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | AVR | `reg_pair` | `r3r2` .. `r25r24`, `X`, `Z` | `r` | | AVR | `reg_iw` | `r25r24`, `X`, `Z` | `w` | | AVR | `reg_ptr` | `X`, `Z` | `e` | +| MSP430 | `reg` | `r[0-15]` | `r` | > **Notes**: > - NVPTX doesn't have a fixed register set, so named registers are not supported. @@ -67,6 +69,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | BPF | `wreg` | `alu32` | `i8` `i16` `i32` | | AVR | `reg`, `reg_upper` | None | `i8` | | AVR | `reg_pair`, `reg_iw`, `reg_ptr` | None | `i16` | +| MSP430 | `reg` | None | `i8`, `i16` | ## Register aliases @@ -80,13 +83,22 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | AVR | `XL` | `r26` | | AVR | `ZH` | `r31` | | AVR | `ZL` | `r30` | +| MSP430 | `r0` | `pc` | +| MSP430 | `r1` | `sp` | +| MSP430 | `r2` | `sr` | +| MSP430 | `r3` | `cg` | +| MSP430 | `r4` | `fp` | + +> **Notes**: +> - TI does not mandate a frame pointer for MSP430, but toolchains are allowed + to use one; LLVM uses `r4`. ## Unsupported registers | Architecture | Unsupported register | Reason | | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR) | The frame pointer cannot be used as an input or output. | +| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430) | The frame pointer cannot be used as an input or output. | | All | `r19` (Hexagon) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. | | MIPS | `$1` or `$at` | Reserved for assembler. | @@ -95,6 +107,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | MIPS | `$ra` | Return address cannot be used as inputs or outputs. | | Hexagon | `lr` | This is the link register which cannot be used as an input or output. | | AVR | `r0`, `r1`, `r1r0` | Due to an issue in LLVM, the `r0` and `r1` registers cannot be used as inputs or outputs. If modified, they must be restored to their original values before the end of the block. | +|MSP430 | `r0`, `r2`, `r3` | These are the program counter, status register, and constant generator respectively. Neither the status register nor constant generator can be written to. | ## Template modifiers @@ -115,3 +128,5 @@ This feature tracks `asm!` and `global_asm!` support for the following architect These flags registers must be restored upon exiting the asm block if the `preserves_flags` option is set: - AVR - The status register `SREG`. +- MSP430 + - The status register `r2`. diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 67d167e86df..45285c1f442 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -11,7 +11,7 @@ arrayvec = { version = "0.7", default-features = false } askama = { version = "0.11", default-features = false, features = ["config"] } atty = "0.2" pulldown-cmark = { version = "0.9", default-features = false } -minifier = "0.0.41" +minifier = "0.0.42" rayon = "1.5.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index eafc74b9945..75ee663b926 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -101,6 +101,27 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { cx.generated_synthetics.insert((ty, trait_def_id)); + let hir_imp = impl_def_id.as_local() + .map(|local| cx.tcx.hir().expect_item(local)) + .and_then(|item| if let hir::ItemKind::Impl(i) = &item.kind { + Some(i) + } else { + None + }); + + let items = match hir_imp { + Some(imp) => imp + .items + .iter() + .map(|ii| cx.tcx.hir().impl_item(ii.id).clean(cx)) + .collect::<Vec<_>>(), + None => cx.tcx + .associated_items(impl_def_id) + .in_definition_order() + .map(|x| x.clean(cx)) + .collect::<Vec<_>>(), + }; + impls.push(Item { name: None, attrs: Default::default(), @@ -117,12 +138,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { // the post-inference `trait_ref`, as it's more accurate. trait_: Some(trait_ref.clean(cx)), for_: ty.clean(cx), - items: cx - .tcx - .associated_items(impl_def_id) - .in_definition_order() - .map(|x| x.clean(cx)) - .collect::<Vec<_>>(), + items, polarity: ty::ImplPolarity::Positive, kind: ImplKind::Blanket(box trait_ref.self_ty().clean(cx)), }), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e759baa0458..7d209accec9 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -5,6 +5,7 @@ mod auto_trait; mod blanket_impl; crate mod cfg; crate mod inline; +mod render_macro_matchers; mod simplify; crate mod types; crate mod utils; @@ -387,7 +388,7 @@ impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> { let trait_ = lifted.trait_ref(cx.tcx).clean(cx); let self_type = self.self_ty().clean(cx); Type::QPath { - name: cx.tcx.associated_item(self.item_def_id).ident.name, + name: cx.tcx.associated_item(self.item_def_id).name, self_def_id: self_type.def_id(&cx.cache), self_type: box self_type, trait_, @@ -1131,7 +1132,7 @@ impl Clean<Item> for ty::AssocItem { } } ty::AssocKind::Type => { - let my_name = self.ident.name; + let my_name = self.name; if let ty::TraitContainer(_) = self.container { let bounds = tcx.explicit_item_bounds(self.def_id); @@ -1197,7 +1198,7 @@ impl Clean<Item> for ty::AssocItem { } }; - Item::from_def_id_and_parts(self.def_id, Some(self.ident.name), kind, cx) + Item::from_def_id_and_parts(self.def_id, Some(self.name), kind, cx) } } @@ -1521,7 +1522,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { let mut bindings = vec![]; for pb in obj.projection_bounds() { bindings.push(TypeBinding { - name: cx.tcx.associated_item(pb.item_def_id()).ident.name, + name: cx.tcx.associated_item(pb.item_def_id()).name, kind: TypeBindingKind::Equality { term: pb.skip_binder().term.clean(cx).into(), }, @@ -1592,7 +1593,6 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { name: cx .tcx .associated_item(proj.projection_ty.item_def_id) - .ident .name, kind: TypeBindingKind::Equality { term: proj.term.clean(cx), diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs new file mode 100644 index 00000000000..dff370ab750 --- /dev/null +++ b/src/librustdoc/clean/render_macro_matchers.rs @@ -0,0 +1,240 @@ +use rustc_ast::token::{self, BinOpToken, DelimToken}; +use rustc_ast::tokenstream::{TokenStream, TokenTree}; +use rustc_ast_pretty::pprust::state::State as Printer; +use rustc_ast_pretty::pprust::PrintState; +use rustc_middle::ty::TyCtxt; +use rustc_session::parse::ParseSess; +use rustc_span::source_map::FilePathMapping; +use rustc_span::symbol::{kw, Ident, Symbol}; +use rustc_span::Span; + +/// Render a macro matcher in a format suitable for displaying to the user +/// as part of an item declaration. +pub(super) fn render_macro_matcher(tcx: TyCtxt<'_>, matcher: &TokenTree) -> String { + if let Some(snippet) = snippet_equal_to_token(tcx, matcher) { + // If the original source code is known, we display the matcher exactly + // as present in the source code. + return snippet; + } + + // If the matcher is macro-generated or some other reason the source code + // snippet is not available, we attempt to nicely render the token tree. + let mut printer = Printer::new(); + + // If the inner ibox fits on one line, we get: + // + // macro_rules! macroname { + // (the matcher) => {...}; + // } + // + // If the inner ibox gets wrapped, the cbox will break and get indented: + // + // macro_rules! macroname { + // ( + // the matcher ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! + // ) => {...}; + // } + printer.cbox(8); + printer.word("("); + printer.zerobreak(); + printer.ibox(0); + match matcher { + TokenTree::Delimited(_span, _delim, tts) => print_tts(&mut printer, tts), + // Matcher which is not a Delimited is unexpected and should've failed + // to compile, but we render whatever it is wrapped in parens. + TokenTree::Token(_) => print_tt(&mut printer, matcher), + } + printer.end(); + printer.break_offset_if_not_bol(0, -4); + printer.word(")"); + printer.end(); + printer.s.eof() +} + +/// Find the source snippet for this token's Span, reparse it, and return the +/// snippet if the reparsed TokenTree matches the argument TokenTree. +fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String> { + // Find what rustc thinks is the source snippet. + // This may not actually be anything meaningful if this matcher was itself + // generated by a macro. + let source_map = tcx.sess.source_map(); + let span = matcher.span(); + let snippet = source_map.span_to_snippet(span).ok()?; + + // Create a Parser. + let sess = ParseSess::new(FilePathMapping::empty()); + let file_name = source_map.span_to_filename(span); + let mut parser = + match rustc_parse::maybe_new_parser_from_source_str(&sess, file_name, snippet.clone()) { + Ok(parser) => parser, + Err(diagnostics) => { + for mut diagnostic in diagnostics { + diagnostic.cancel(); + } + return None; + } + }; + + // Reparse a single token tree. + let mut reparsed_trees = match parser.parse_all_token_trees() { + Ok(reparsed_trees) => reparsed_trees, + Err(mut diagnostic) => { + diagnostic.cancel(); + return None; + } + }; + if reparsed_trees.len() != 1 { + return None; + } + let reparsed_tree = reparsed_trees.pop().unwrap(); + + // Compare against the original tree. + if reparsed_tree.eq_unspanned(matcher) { Some(snippet) } else { None } +} + +fn print_tt(printer: &mut Printer<'_>, tt: &TokenTree) { + match tt { + TokenTree::Token(token) => { + let token_str = printer.token_to_string(token); + printer.word(token_str); + if let token::DocComment(..) = token.kind { + printer.hardbreak() + } + } + TokenTree::Delimited(_span, delim, tts) => { + let open_delim = printer.token_kind_to_string(&token::OpenDelim(*delim)); + printer.word(open_delim); + if !tts.is_empty() { + if *delim == DelimToken::Brace { + printer.space(); + } + print_tts(printer, tts); + if *delim == DelimToken::Brace { + printer.space(); + } + } + let close_delim = printer.token_kind_to_string(&token::CloseDelim(*delim)); + printer.word(close_delim); + } + } +} + +fn print_tts(printer: &mut Printer<'_>, tts: &TokenStream) { + #[derive(Copy, Clone, PartialEq)] + enum State { + Start, + Dollar, + DollarIdent, + DollarIdentColon, + DollarParen, + DollarParenSep, + Pound, + PoundBang, + Ident, + Other, + } + + use State::*; + + let mut state = Start; + for tt in tts.trees() { + let (needs_space, next_state) = match &tt { + TokenTree::Token(tt) => match (state, &tt.kind) { + (Dollar, token::Ident(..)) => (false, DollarIdent), + (DollarIdent, token::Colon) => (false, DollarIdentColon), + (DollarIdentColon, token::Ident(..)) => (false, Other), + ( + DollarParen, + token::BinOp(BinOpToken::Plus | BinOpToken::Star) | token::Question, + ) => (false, Other), + (DollarParen, _) => (false, DollarParenSep), + (DollarParenSep, token::BinOp(BinOpToken::Plus | BinOpToken::Star)) => { + (false, Other) + } + (Pound, token::Not) => (false, PoundBang), + (_, token::Ident(symbol, /* is_raw */ false)) + if !usually_needs_space_between_keyword_and_open_delim(*symbol, tt.span) => + { + (true, Ident) + } + (_, token::Comma | token::Semi) => (false, Other), + (_, token::Dollar) => (true, Dollar), + (_, token::Pound) => (true, Pound), + (_, _) => (true, Other), + }, + TokenTree::Delimited(_, delim, _) => match (state, delim) { + (Dollar, DelimToken::Paren) => (false, DollarParen), + (Pound | PoundBang, DelimToken::Bracket) => (false, Other), + (Ident, DelimToken::Paren | DelimToken::Bracket) => (false, Other), + (_, _) => (true, Other), + }, + }; + if state != Start && needs_space { + printer.space(); + } + print_tt(printer, &tt); + state = next_state; + } +} + +fn usually_needs_space_between_keyword_and_open_delim(symbol: Symbol, span: Span) -> bool { + let ident = Ident { name: symbol, span }; + let is_keyword = ident.is_used_keyword() || ident.is_unused_keyword(); + if !is_keyword { + // An identifier that is not a keyword usually does not need a space + // before an open delim. For example: `f(0)` or `f[0]`. + return false; + } + + match symbol { + // No space after keywords that are syntactically an expression. For + // example: a tuple struct created with `let _ = Self(0, 0)`, or if + // someone has `impl Index<MyStruct> for bool` then `true[MyStruct]`. + kw::False | kw::SelfLower | kw::SelfUpper | kw::True => false, + + // No space, as in `let _: fn();` + kw::Fn => false, + + // No space, as in `pub(crate) type T;` + kw::Pub => false, + + // No space for keywords that can end an expression, as in `fut.await()` + // where fut's Output type is `fn()`. + kw::Await => false, + + // Otherwise space after keyword. Some examples: + // + // `expr as [T; 2]` + // ^ + // `box (tuple,)` + // ^ + // `break (tuple,)` + // ^ + // `type T = dyn (Fn() -> dyn Trait) + Send;` + // ^ + // `for (tuple,) in iter {}` + // ^ + // `if (tuple,) == v {}` + // ^ + // `impl [T] {}` + // ^ + // `for x in [..] {}` + // ^ + // `let () = unit;` + // ^ + // `match [x, y] {...}` + // ^ + // `&mut (x as T)` + // ^ + // `return [];` + // ^ + // `fn f<T>() where (): Into<T>` + // ^ + // `while (a + b).what() {}` + // ^ + // `yield [];` + // ^ + _ => true, + } +} diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 993503005d7..02633698273 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -5,7 +5,7 @@ use std::lazy::SyncOnceCell as OnceCell; use std::path::PathBuf; use std::rc::Rc; use std::sync::Arc; -use std::{slice, vec}; +use std::vec; use arrayvec::ArrayVec; @@ -338,6 +338,7 @@ impl ExternalCrate { } /// Indicates where an external crate can be found. +#[derive(Debug)] crate enum ExternalLocation { /// Remote URL root of the external crate Remote(String), @@ -429,7 +430,7 @@ impl Item { /// Convenience wrapper around [`Self::from_def_id_and_parts`] which converts /// `hir_id` to a [`DefId`] - pub fn from_hir_id_and_parts( + crate fn from_hir_id_and_parts( hir_id: hir::HirId, name: Option<Symbol>, kind: ItemKind, @@ -438,7 +439,7 @@ impl Item { Item::from_def_id_and_parts(cx.tcx.hir().local_def_id(hir_id).to_def_id(), name, kind, cx) } - pub fn from_def_id_and_parts( + crate fn from_def_id_and_parts( def_id: DefId, name: Option<Symbol>, kind: ItemKind, @@ -456,7 +457,7 @@ impl Item { ) } - pub fn from_def_id_and_attrs_and_parts( + crate fn from_def_id_and_attrs_and_parts( def_id: DefId, name: Option<Symbol>, kind: ItemKind, @@ -733,43 +734,12 @@ crate struct Module { crate span: Span, } -crate struct ListAttributesIter<'a> { - attrs: slice::Iter<'a, ast::Attribute>, - current_list: vec::IntoIter<ast::NestedMetaItem>, - name: Symbol, -} - -impl<'a> Iterator for ListAttributesIter<'a> { - type Item = ast::NestedMetaItem; - - fn next(&mut self) -> Option<Self::Item> { - if let Some(nested) = self.current_list.next() { - return Some(nested); - } - - for attr in &mut self.attrs { - if let Some(list) = attr.meta_item_list() { - if attr.has_name(self.name) { - self.current_list = list.into_iter(); - if let Some(nested) = self.current_list.next() { - return Some(nested); - } - } - } - } - - None - } - - fn size_hint(&self) -> (usize, Option<usize>) { - let lower = self.current_list.len(); - (lower, None) - } -} - crate trait AttributesExt { - /// Finds an attribute as List and returns the list of attributes nested inside. - fn lists(&self, name: Symbol) -> ListAttributesIter<'_>; + type AttributeIterator<'a>: Iterator<Item = ast::NestedMetaItem> + where + Self: 'a; + + fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a>; fn span(&self) -> Option<rustc_span::Span>; @@ -781,8 +751,13 @@ crate trait AttributesExt { } impl AttributesExt for [ast::Attribute] { - fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { - ListAttributesIter { attrs: self.iter(), current_list: Vec::new().into_iter(), name } + type AttributeIterator<'a> = impl Iterator<Item = ast::NestedMetaItem> + 'a; + + fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a> { + self.iter() + .filter(move |attr| attr.has_name(name)) + .filter_map(ast::Attribute::meta_item_list) + .flatten() } /// Return the span of the first doc-comment, if it exists. @@ -902,12 +877,9 @@ crate trait NestedAttributesExt { fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem>; } -impl<I> NestedAttributesExt for I -where - I: IntoIterator<Item = ast::NestedMetaItem>, -{ - fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem> { - self.into_iter().find(|attr| attr.is_word() && attr.has_name(word)) +impl<I: Iterator<Item = ast::NestedMetaItem>> NestedAttributesExt for I { + fn get_word_attr(mut self, word: Symbol) -> Option<ast::NestedMetaItem> { + self.find(|attr| attr.is_word() && attr.has_name(word)) } } @@ -984,26 +956,26 @@ crate fn collapse_doc_fragments(doc_strings: &[DocFragment]) -> String { #[derive(Clone, Debug, PartialEq, Eq, Hash)] crate struct ItemLink { /// The original link written in the markdown - pub(crate) link: String, + crate link: String, /// The link text displayed in the HTML. /// /// This may not be the same as `link` if there was a disambiguator /// in an intra-doc link (e.g. \[`fn@f`\]) - pub(crate) link_text: String, - pub(crate) did: DefId, + crate link_text: String, + crate did: DefId, /// The url fragment to append to the link - pub(crate) fragment: Option<UrlFragment>, + crate fragment: Option<UrlFragment>, } pub struct RenderedLink { /// The text the link was original written as. /// /// This could potentially include disambiguators and backticks. - pub(crate) original_text: String, + crate original_text: String, /// The text to display in the HTML - pub(crate) new_text: String, + crate new_text: String, /// The URL to put in the `href` - pub(crate) href: String, + crate href: String, } /// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`, @@ -1015,7 +987,7 @@ crate struct Attributes { } impl Attributes { - crate fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { + crate fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::NestedMetaItem> + '_ { self.other_attrs.lists(name) } @@ -1568,23 +1540,10 @@ impl Type { /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s. /// - /// See [`Self::def_id_no_primitives`] for more. - /// /// [clean]: crate::clean crate fn def_id(&self, cache: &Cache) -> Option<DefId> { self.inner_def_id(Some(cache)) } - - /// Use this method to get the [`DefId`] of a [`clean`] AST node. - /// This will return [`None`] when called on a primitive [`clean::Type`]. - /// Use [`Self::def_id`] if you want to include primitives. - /// - /// [`clean`]: crate::clean - /// [`clean::Type`]: crate::clean::Type - // FIXME: get rid of this function and always use `def_id` - crate fn def_id_no_primitives(&self) -> Option<DefId> { - self.inner_def_id(None) - } } /// A primitive (aka, builtin) type. @@ -2223,7 +2182,7 @@ impl Impl { self.trait_ .as_ref() .map(|t| t.def_id()) - .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect()) + .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name).collect()) .unwrap_or_default() } } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 38da9a4635d..dabf1e878c9 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -1,5 +1,6 @@ use crate::clean::auto_trait::AutoTraitFinder; use crate::clean::blanket_impl::BlanketImplFinder; +use crate::clean::render_macro_matchers::render_macro_matcher; use crate::clean::{ inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime, Path, PathSegment, Primitive, PrimitiveType, Type, TypeBinding, Visibility, @@ -17,8 +18,6 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, DefIdTree, TyCtxt}; -use rustc_session::parse::ParseSess; -use rustc_span::source_map::FilePathMapping; use rustc_span::symbol::{kw, sym, Symbol}; use std::fmt::Write as _; use std::mem; @@ -500,57 +499,6 @@ pub(super) fn render_macro_arms<'a>( out } -/// Render a macro matcher in a format suitable for displaying to the user -/// as part of an item declaration. -pub(super) fn render_macro_matcher(tcx: TyCtxt<'_>, matcher: &TokenTree) -> String { - if let Some(snippet) = snippet_equal_to_token(tcx, matcher) { - snippet - } else { - rustc_ast_pretty::pprust::tt_to_string(matcher) - } -} - -/// Find the source snippet for this token's Span, reparse it, and return the -/// snippet if the reparsed TokenTree matches the argument TokenTree. -fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String> { - // Find what rustc thinks is the source snippet. - // This may not actually be anything meaningful if this matcher was itself - // generated by a macro. - let source_map = tcx.sess.source_map(); - let span = matcher.span(); - let snippet = source_map.span_to_snippet(span).ok()?; - - // Create a Parser. - let sess = ParseSess::new(FilePathMapping::empty()); - let file_name = source_map.span_to_filename(span); - let mut parser = - match rustc_parse::maybe_new_parser_from_source_str(&sess, file_name, snippet.clone()) { - Ok(parser) => parser, - Err(diagnostics) => { - for mut diagnostic in diagnostics { - diagnostic.cancel(); - } - return None; - } - }; - - // Reparse a single token tree. - let mut reparsed_trees = match parser.parse_all_token_trees() { - Ok(reparsed_trees) => reparsed_trees, - Err(mut diagnostic) => { - diagnostic.cancel(); - return None; - } - }; - if reparsed_trees.len() != 1 { - return None; - } - let reparsed_tree = reparsed_trees.pop().unwrap(); - - // Compare against the original tree. - if reparsed_tree.eq_unspanned(matcher) { Some(snippet) } else { None } -} - pub(super) fn display_macro_source( cx: &mut DocContext<'_>, name: Symbol, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 3b926e44403..1f14a333c00 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -4,9 +4,9 @@ use rustc_errors::emitter::{Emitter, EmitterWriter}; use rustc_errors::json::JsonEmitter; use rustc_feature::UnstableFeatures; use rustc_hir::def::Res; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{HirId, Path}; +use rustc_hir::{HirId, Path, TraitCandidate}; use rustc_interface::interface; use rustc_middle::hir::nested_filter; use rustc_middle::middle::privacy::AccessLevels; @@ -33,8 +33,11 @@ use crate::passes::{self, Condition::*}; crate use rustc_session::config::{DebuggingOptions, Input, Options}; crate struct ResolverCaches { - pub all_traits: Option<Vec<DefId>>, - pub all_trait_impls: Option<Vec<DefId>>, + /// Traits in scope for a given module. + /// See `collect_intra_doc_links::traits_implemented_by` for more details. + crate traits_in_scope: DefIdMap<Vec<TraitCandidate>>, + crate all_traits: Option<Vec<DefId>>, + crate all_trait_impls: Option<Vec<DefId>>, } crate struct DocContext<'tcx> { @@ -67,11 +70,6 @@ crate struct DocContext<'tcx> { crate auto_traits: Vec<DefId>, /// The options given to rustdoc that could be relevant to a pass. crate render_options: RenderOptions, - /// The traits in scope for a given module. - /// - /// See `collect_intra_doc_links::traits_implemented_by` for more details. - /// `map<module, set<trait>>` - crate module_trait_cache: FxHashMap<DefId, FxHashSet<DefId>>, /// This same cache is used throughout rustdoc, including in [`crate::html::render`]. crate cache: Cache, /// Used by [`clean::inline`] to tell if an item has already been inlined. @@ -350,7 +348,6 @@ crate fn run_global_ctxt( impl_trait_bounds: Default::default(), generated_synthetics: Default::default(), auto_traits, - module_trait_cache: FxHashMap::default(), cache: Cache::new(access_levels, render_options.document_private), inlined: FxHashSet::default(), output_format, diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index a8fef4a3178..53159709586 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -303,7 +303,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { desc, parent, parent_idx: None, - search_type: get_function_type_for_search(&item, self.tcx), + search_type: get_function_type_for_search(&item, self.tcx, self.cache), aliases: item.attrs.get_doc_aliases(), }); } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 8badce8226f..cc12b7ba05b 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -175,14 +175,14 @@ crate struct StylePath { } impl StylePath { - pub fn basename(&self) -> Result<String, Error> { + crate fn basename(&self) -> Result<String, Error> { Ok(try_none!(try_none!(self.path.file_stem(), &self.path).to_str(), &self.path).to_string()) } } fn write_srclink(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) { if let Some(l) = cx.src_href(item) { - write!(buf, "<a class=\"srclink\" href=\"{}\" title=\"goto source code\">source</a>", l) + write!(buf, "<a class=\"srclink\" href=\"{}\">source</a>", l) } } @@ -376,25 +376,21 @@ impl Setting { description, ), Setting::Select { js_data_name, description, default_value, ref options } => format!( - "<div class=\"setting-line\">\ - <div>{}</div>\ - <label class=\"select-wrapper\">\ - <select id=\"{}\" autocomplete=\"off\">{}</select>\ - <img src=\"{}down-arrow{}.svg\" alt=\"Select item\">\ - </label>\ - </div>", - description, + "<div class=\"setting-line\"><div class=\"radio-line\" id=\"{}\"><span class=\"setting-name\">{}</span>{}</div></div>", js_data_name, + description, options .iter() .map(|opt| format!( - "<option value=\"{name}\" {}>{name}</option>", - if opt == default_value { "selected" } else { "" }, + "<label for=\"{js_data_name}-{name}\" class=\"choice\"> + <input type=\"radio\" name=\"{js_data_name}\" id=\"{js_data_name}-{name}\" value=\"{name}\" {checked}>\ + {name}\ + </label>", + js_data_name = js_data_name, name = opt, + checked = if opt == default_value { "checked" } else { "" }, )) .collect::<String>(), - root_path, - suffix, ), } } @@ -418,31 +414,25 @@ impl<T: Into<Setting>> From<(&'static str, Vec<T>)> for Setting { fn settings(root_path: &str, suffix: &str, theme_names: Vec<String>) -> Result<String, Error> { // (id, explanation, default value) let settings: &[Setting] = &[ - ( - "Theme preferences", - vec![ - Setting::from(("use-system-theme", "Use system theme", true)), - Setting::Select { - js_data_name: "theme", - description: "Theme", - default_value: "light", - options: theme_names.clone(), - }, - Setting::Select { - js_data_name: "preferred-dark-theme", - description: "Preferred dark theme", - default_value: "dark", - options: theme_names.clone(), - }, - Setting::Select { - js_data_name: "preferred-light-theme", - description: "Preferred light theme", - default_value: "light", - options: theme_names, - }, - ], - ) - .into(), + Setting::from(("use-system-theme", "Use system theme", true)), + Setting::Select { + js_data_name: "theme", + description: "Theme", + default_value: "light", + options: theme_names.clone(), + }, + Setting::Select { + js_data_name: "preferred-light-theme", + description: "Preferred light theme", + default_value: "light", + options: theme_names.clone(), + }, + Setting::Select { + js_data_name: "preferred-dark-theme", + description: "Preferred dark theme", + default_value: "dark", + options: theme_names, + }, ("auto-hide-large-items", "Auto-hide item contents for large items.", true).into(), ("auto-hide-method-docs", "Auto-hide item methods' documentation", false).into(), ("auto-hide-trait-implementations", "Auto-hide trait implementation documentation", false) @@ -454,9 +444,14 @@ fn settings(root_path: &str, suffix: &str, theme_names: Vec<String>) -> Result<S ]; Ok(format!( - "<h1 class=\"fqn\">\ - <span class=\"in-band\">Rustdoc settings</span>\ - </h1>\ + "<div class=\"main-heading\"> + <h1 class=\"fqn\">\ + <span class=\"in-band\">Rustdoc settings</span>\ + </h1>\ + <span class=\"out-of-band\">\ + <a id=\"back\" href=\"javascript:void(0)\">Back</a>\ + </span>\ + </div>\ <div class=\"settings\">{}</div>\ <link rel=\"stylesheet\" href=\"{root_path}settings{suffix}.css\">\ <script src=\"{root_path}settings{suffix}.js\"></script>", @@ -1681,11 +1676,12 @@ fn render_rightside( containing_item.stable_since(tcx), const_stable_since, ); - if has_stability { + let mut tmp_buf = Buffer::empty_from(w); + write_srclink(cx, item, &mut tmp_buf); + if has_stability && !tmp_buf.is_empty() { w.write_str(" · "); } - - write_srclink(cx, item, w); + w.push_buffer(tmp_buf); w.write_str("</div>"); } diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 87138b9571c..0ee67467c38 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{kw, Symbol}; use serde::ser::{Serialize, SerializeStruct, Serializer}; use crate::clean; @@ -33,7 +33,7 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt< desc, parent: Some(did), parent_idx: None, - search_type: get_function_type_for_search(item, tcx), + search_type: get_function_type_for_search(item, tcx, &cache), aliases: item.attrs.get_doc_aliases(), }); } @@ -188,11 +188,12 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt< crate fn get_function_type_for_search<'tcx>( item: &clean::Item, tcx: TyCtxt<'tcx>, + cache: &Cache, ) -> Option<IndexItemFunctionType> { let (mut inputs, mut output) = match *item.kind { - clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx), - clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx), - clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx), + clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx, cache), + clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx, cache), + clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx, cache), _ => return None, }; @@ -219,7 +220,8 @@ fn get_index_type_name(clean_type: &clean::Type) -> Option<Symbol> { let path = &bounds[0].trait_; Some(path.segments.last().unwrap().name) } - clean::Generic(s) => Some(s), + // We return an empty name because we don't care about the generic name itself. + clean::Generic(_) => Some(kw::Empty), clean::Primitive(ref p) => Some(p.as_sym()), clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_), clean::BareFunction(_) @@ -240,24 +242,27 @@ fn get_index_type_name(clean_type: &clean::Type) -> Option<Symbol> { /// /// Important note: It goes through generics recursively. So if you have /// `T: Option<Result<(), ()>>`, it'll go into `Option` and then into `Result`. -#[instrument(level = "trace", skip(tcx, res))] +#[instrument(level = "trace", skip(tcx, res, cache))] fn add_generics_and_bounds_as_types<'tcx>( generics: &Generics, arg: &Type, tcx: TyCtxt<'tcx>, recurse: usize, res: &mut Vec<TypeWithKind>, + cache: &Cache, ) { fn insert_ty( res: &mut Vec<TypeWithKind>, tcx: TyCtxt<'_>, ty: Type, mut generics: Vec<TypeWithKind>, + cache: &Cache, ) { let is_full_generic = ty.is_full_generic(); + let generics_empty = generics.is_empty(); if is_full_generic { - if generics.is_empty() { + if generics_empty { // This is a type parameter with no trait bounds (for example: `T` in // `fn f<T>(p: T)`, so not useful for the rustdoc search because we would end up // with an empty type with an empty name. Let's just discard it. @@ -304,14 +309,14 @@ fn add_generics_and_bounds_as_types<'tcx>( } } let mut index_ty = get_index_type(&ty, generics); - if index_ty.name.as_ref().map(|s| s.is_empty()).unwrap_or(true) { + if index_ty.name.as_ref().map(|s| s.is_empty() && generics_empty).unwrap_or(true) { return; } if is_full_generic { // We remove the name of the full generic because we have no use for it. index_ty.name = Some(String::new()); res.push(TypeWithKind::from((index_ty, ItemType::Generic))); - } else if let Some(kind) = ty.def_id_no_primitives().map(|did| tcx.def_kind(did).into()) { + } else if let Some(kind) = ty.def_id(cache).map(|did| tcx.def_kind(did).into()) { res.push(TypeWithKind::from((index_ty, kind))); } else if ty.is_primitive() { // This is a primitive, let's store it as such. @@ -330,9 +335,7 @@ fn add_generics_and_bounds_as_types<'tcx>( if let Type::Generic(arg_s) = *arg { // First we check if the bounds are in a `where` predicate... if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g { - WherePredicate::BoundPredicate { ty, .. } => { - ty.def_id_no_primitives() == arg.def_id_no_primitives() - } + WherePredicate::BoundPredicate { ty, .. } => ty.def_id(cache) == arg.def_id(cache), _ => false, }) { let mut ty_generics = Vec::new(); @@ -348,6 +351,7 @@ fn add_generics_and_bounds_as_types<'tcx>( tcx, recurse + 1, &mut ty_generics, + cache, ) } _ => {} @@ -355,7 +359,7 @@ fn add_generics_and_bounds_as_types<'tcx>( } } } - insert_ty(res, tcx, arg.clone(), ty_generics); + insert_ty(res, tcx, arg.clone(), ty_generics, cache); } // Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`... if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) { @@ -369,10 +373,11 @@ fn add_generics_and_bounds_as_types<'tcx>( tcx, recurse + 1, &mut ty_generics, + cache, ); } } - insert_ty(res, tcx, arg.clone(), ty_generics); + insert_ty(res, tcx, arg.clone(), ty_generics, cache); } } else { // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're @@ -383,10 +388,17 @@ fn add_generics_and_bounds_as_types<'tcx>( let mut ty_generics = Vec::new(); if let Some(arg_generics) = arg.generics() { for gen in arg_generics.iter() { - add_generics_and_bounds_as_types(generics, gen, tcx, recurse + 1, &mut ty_generics); + add_generics_and_bounds_as_types( + generics, + gen, + tcx, + recurse + 1, + &mut ty_generics, + cache, + ); } } - insert_ty(res, tcx, arg.clone(), ty_generics); + insert_ty(res, tcx, arg.clone(), ty_generics, cache); } } @@ -397,6 +409,7 @@ fn add_generics_and_bounds_as_types<'tcx>( fn get_fn_inputs_and_outputs<'tcx>( func: &Function, tcx: TyCtxt<'tcx>, + cache: &Cache, ) -> (Vec<TypeWithKind>, Vec<TypeWithKind>) { let decl = &func.decl; let generics = &func.generics; @@ -407,12 +420,11 @@ fn get_fn_inputs_and_outputs<'tcx>( continue; } let mut args = Vec::new(); - add_generics_and_bounds_as_types(generics, &arg.type_, tcx, 0, &mut args); + add_generics_and_bounds_as_types(generics, &arg.type_, tcx, 0, &mut args, cache); if !args.is_empty() { all_types.extend(args); } else { - if let Some(kind) = arg.type_.def_id_no_primitives().map(|did| tcx.def_kind(did).into()) - { + if let Some(kind) = arg.type_.def_id(cache).map(|did| tcx.def_kind(did).into()) { all_types.push(TypeWithKind::from((get_index_type(&arg.type_, vec![]), kind))); } } @@ -421,11 +433,9 @@ fn get_fn_inputs_and_outputs<'tcx>( let mut ret_types = Vec::new(); match decl.output { FnRetTy::Return(ref return_type) => { - add_generics_and_bounds_as_types(generics, return_type, tcx, 0, &mut ret_types); + add_generics_and_bounds_as_types(generics, return_type, tcx, 0, &mut ret_types, cache); if ret_types.is_empty() { - if let Some(kind) = - return_type.def_id_no_primitives().map(|did| tcx.def_kind(did).into()) - { + if let Some(kind) = return_type.def_id(cache).map(|did| tcx.def_kind(did).into()) { ret_types.push(TypeWithKind::from((get_index_type(return_type, vec![]), kind))); } } diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 586f34cd2c8..731e18b1eec 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -134,11 +134,13 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { if let Some(hir_id) = segment.hir_id { let hir = self.tcx.hir(); let body_id = hir.enclosing_body_owner(hir_id); - let typeck_results = self.tcx.sess.with_disabled_diagnostic(|| { - self.tcx.typeck_body( - hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"), - ) - }); + // FIXME: this is showing error messages for parts of the code that are not + // compiled (because of cfg)! + // + // See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352 + let typeck_results = self.tcx.typeck_body( + hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"), + ); if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) { self.matches.insert( segment.ident.span, diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index bdd8aa430b2..87403a8b834 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -150,7 +150,6 @@ h1.fqn { display: flex; flex-wrap: wrap; justify-content: space-between; - border-bottom: 1px dashed #DDDDDD; padding-bottom: 6px; margin-bottom: 15px; } @@ -398,7 +397,7 @@ nav.sub { } .source .sidebar > *:not(:first-child) { - transition: opacity 0.5s, visibility 0.2s; + transition: opacity 0.5s; opacity: 0; visibility: hidden; } @@ -485,6 +484,10 @@ nav.sub { overflow: hidden; } +.sidebar-links a { + white-space: nowrap; +} + .sidebar h2 { border-bottom: none; font-weight: 500; @@ -671,7 +674,6 @@ nav.sub { margin: .5em 0; width: calc(100% - 2px); overflow-x: auto; - overflow-wrap: normal; display: block; } @@ -858,6 +860,31 @@ h2.small-section-header > .anchor { .block a.current.crate { font-weight: 500; } +/* In most contexts we use `overflow-wrap: anywhere` to ensure that we can wrap + as much as needed on mobile (see + src/test/rustdoc-gui/type-declaration-overflow.goml for an example of why + this matters). The `anywhere` value means: + + "Soft wrap opportunities introduced by the word break are considered when + calculating min-content intrinsic sizes." + + https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap#values + + For table layouts, that becomes a problem: the browser tries to make each + column as narrow as possible, and `overflow-wrap: anywhere` means it can do + so by breaking words - even if some other column could be shrunk without + breaking words! This shows up, for instance, in the `Structs` / `Modules` / + `Functions` (etcetera) sections of a module page, and when a docblock + contains a table. + + So, for table layouts, override the default with break-word, which does + _not_ affect min-content intrinsic sizes. +*/ +table, +.item-table { + overflow-wrap: break-word; +} + .item-table { display: table; } @@ -873,11 +900,11 @@ h2.small-section-header > .anchor { .search-container { position: relative; - max-width: 960px; + display: flex; + height: 34px; } -.search-container > div { - display: inline-flex; - width: calc(100% - 63px); +.search-container > * { + height: 100%; } .search-results-title { display: inline; @@ -908,10 +935,8 @@ h2.small-section-header > .anchor { background-position: calc(100% - 1px) 56%; background-image: /* AUTOREPLACE: */url("down-arrow.svg"); } -.search-container > .top-button { - position: absolute; - right: 0; - top: 10px; +.search-container { + margin-top: 4px; } .search-input { /* Override Normalize.css: it has a rule that sets @@ -924,23 +949,14 @@ h2.small-section-header > .anchor { -moz-box-sizing: border-box !important; box-sizing: border-box !important; outline: none; - border: none; - border-radius: 1px; - margin-top: 5px; - padding: 10px 16px; + border: 1px solid; + border-radius: 2px; + padding: 5px 8px; font-size: 1.0625rem; transition: border-color 300ms ease; - transition: border-radius 300ms ease-in-out; - transition: box-shadow 300ms ease-in-out; width: 100%; } -.search-input:focus { - border-radius: 2px; - border: 0; - outline: 0; -} - .search-results { display: none; padding-bottom: 2em; @@ -1176,7 +1192,6 @@ a.test-arrow:hover{ .out-of-band > span.since { position: initial; font-size: 1.25rem; - margin-right: 5px; } h3.variant { @@ -1414,8 +1429,8 @@ pre.rust { .theme-picker { position: absolute; - left: -34px; - top: 9px; + left: -38px; + top: 4px; } .theme-picker button { @@ -1423,34 +1438,27 @@ pre.rust { } #settings-menu, #help-button { - position: absolute; - top: 10px; -} - -#settings-menu { - right: 0; + margin-left: 4px; outline: none; } +#theme-picker, #copy-path { + height: 34px; +} #theme-picker, #settings-menu, #help-button, #copy-path { - padding: 4px; - /* Rare exception to specifying font sizes in rem. Since these are acting - as icons, it's okay to specify their sizes in pixels. */ - font-size: 16px; - width: 27px; - height: 29px; + padding: 5px; + width: 33px; border: 1px solid; - border-radius: 3px; + border-radius: 2px; cursor: pointer; } #help-button { - right: 30px; font-family: "Fira Sans", Arial, sans-serif; text-align: center; /* Rare exception to specifying font sizes in rem. Since this is acting as an icon, it's okay to specify their sizes in pixels. */ - font-size: 16px; + font-size: 20px; padding-top: 2px; } @@ -1791,8 +1799,9 @@ details.rustdoc-toggle[open] > summary.hideme::after { background-color: rgba(0,0,0,0); margin: 0; padding: 0; - padding-left: 15px; z-index: 11; + /* Reduce height slightly to account for mobile topbar. */ + height: calc(100vh - 45px); } /* The source view uses a different design for the sidebar toggle, and doesn't have a topbar, @@ -1823,7 +1832,13 @@ details.rustdoc-toggle[open] > summary.hideme::after { padding: 0.3em; padding-right: 0.6em; text-overflow: ellipsis; - overflow-x: hidden; + overflow: hidden; + white-space: nowrap; + /* Rare exception to specifying font sizes in rem. Since the topbar + height is specified in pixels, this also has to be specified in + pixels to avoid overflowing the topbar when the user sets a bigger + font size. */ + font-size: 22.4px; } .mobile-topbar .logo-container { @@ -1844,7 +1859,6 @@ details.rustdoc-toggle[open] > summary.hideme::after { position: sticky; z-index: 10; font-size: 2rem; - cursor: pointer; height: 45px; width: 100%; left: 0; @@ -1857,6 +1871,9 @@ details.rustdoc-toggle[open] > summary.hideme::after { .sidebar-menu-toggle { width: 45px; + /* Rare exception to specifying font sizes in rem. Since this is acting + as an icon, it's okay to specify its sizes in pixels. */ + font-size: 32px; border: none; } @@ -1887,10 +1904,6 @@ details.rustdoc-toggle[open] > summary.hideme::after { display: none !important; } - .theme-picker { - z-index: 1; - } - .notable-traits { position: absolute; left: -22px; @@ -1977,10 +1990,6 @@ details.rustdoc-toggle[open] > summary.hideme::after { width: 100%; } - .search-container > div { - width: calc(100% - 32px); - } - /* Display an alternating layout on tablets and phones */ .search-results > a { border-bottom: 1px solid #aaa9; @@ -2025,30 +2034,11 @@ details.rustdoc-toggle[open] > summary.hideme::after { width: 50%; } - .search-container > div { - display: block; - width: calc(100% - 37px); - } - #crate-search { border-radius: 4px; border: 0; } - #theme-picker, #settings-menu { - padding: 5px; - width: 31px; - height: 31px; - } - - #theme-picker { - margin-top: -2px; - } - - #settings-menu { - top: 7px; - } - .docblock { margin-left: 12px; } @@ -2058,10 +2048,6 @@ details.rustdoc-toggle[open] > summary.hideme::after { overflow-wrap: anywhere; } - .docblock table code { - overflow-wrap: normal; - } - .sub-container { flex-direction: column; } diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css index fb8990b30e2..932000487b0 100644 --- a/src/librustdoc/html/static/css/settings.css +++ b/src/librustdoc/html/static/css/settings.css @@ -17,6 +17,30 @@ border-bottom: 1px solid; } +.setting-line .radio-line { + display: flex; + flex-wrap: wrap; +} + +.setting-line .radio-line > * { + padding: 0.3em; +} + +.setting-line .radio-line .setting-name { + flex-grow: 1; +} + +.setting-line .radio-line input { + margin-right: 0.3em; +} + +.radio-line .choice { + border-radius: 0.1em; + border: 1px solid; + margin-left: 0.5em; + min-width: 3.5em; +} + .toggle { position: relative; display: inline-block; diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index 69097b81b9f..cee45e1de39 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -191,6 +191,10 @@ pre, .rustdoc.source .example-wrap { color: #a37acc; } +.sidebar a { color: #53b1db; } +.sidebar a.current.type { color: #53b1db; } +.sidebar a.current.associatedtype { color: #53b1db; } + pre.rust .comment { color: #788797; } pre.rust .doccomment { color: #a1ac88; } @@ -212,6 +216,7 @@ a.anchor, pre.rust a, .sidebar h2 a, .sidebar h3 a, +.mobile-topbar h2 a, .in-band a { color: #c5c5c5; } @@ -233,22 +238,14 @@ details.undocumented > summary::before { filter: invert(100%); } -#crate-search { - color: #c5c5c5; +#crate-search, .search-input { background-color: #141920; - box-shadow: 0 0 0 1px #424c57,0 0 0 2px transparent; border-color: #424c57; + color: #c5c5c5; } .search-input { color: #ffffff; - background-color: #141920; - box-shadow: 0 0 0 1px #424c57,0 0 0 2px transparent; - transition: box-shadow 150ms ease-in-out; -} - -#crate-search+.search-input:focus { - box-shadow: 0 0 0 1px #148099,0 0 0 2px transparent; } .module-item .stab, @@ -493,6 +490,25 @@ a.result-static:focus {} a.result-primitive:focus {} a.result-keyword:focus {} +.sidebar a.current.enum {} +.sidebar a.current.struct {} +.sidebar a.current.foreigntype {} +.sidebar a.current.attr, +.sidebar a.current.derive, +.sidebar a.current.macro {} +.sidebar a.current.union {} +.sidebar a.current.constant +.sidebar a.current.static {} +.sidebar a.current.primitive {} +.sidebar a.current.externcrate +.sidebar a.current.mod {} +.sidebar a.current.trait {} +.sidebar a.current.traitalias {} +.sidebar a.current.fn, +.sidebar a.current.method, +.sidebar a.current.tymethod {} +.sidebar a.current.keyword {} + @media (max-width: 700px) { .sidebar-menu { background-color: #14191f; diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index 39165b2fc05..c5817ba4e73 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -148,6 +148,28 @@ a.result-keyword:focus { background-color: #884719; } .content .fnname{ color: #2BAB63; } .content span.keyword, .content a.keyword, .block a.current.keyword { color: #D2991D; } +.sidebar a { color: #fdbf35; } +.sidebar a.current.enum { color: #12ece2; } +.sidebar a.current.struct { color: #12ece2; } +.sidebar a.current.type { color: #12ece2; } +.sidebar a.current.associatedtype { color: #fdbf35; } +.sidebar a.current.foreigntype { color: #12ece2; } +.sidebar a.current.attr, +.sidebar a.current.derive, +.sidebar a.current.macro { color: #0be900; } +.sidebar a.current.union { color: #12ece2; } +.sidebar a.current.constant +.sidebar a.current.static { color: #fdbf35; } +.sidebar a.current.primitive { color: #12ece2; } +.sidebar a.current.externcrate +.sidebar a.current.mod { color: #fdbf35; } +.sidebar a.current.trait { color: #cca7ff; } +.sidebar a.current.traitalias { color: #cca7ff; } +.sidebar a.current.fn, +.sidebar a.current.method, +.sidebar a.current.tymethod { color: #32d479; } +.sidebar a.current.keyword { color: #fdbf35; } + pre.rust .comment { color: #8d8d8b; } pre.rust .doccomment { color: #8ca375; } @@ -170,6 +192,7 @@ a.anchor, pre.rust a, .sidebar h2 a, .sidebar h3 a, +.mobile-topbar h2 a, .in-band a { color: #ddd; } @@ -194,27 +217,20 @@ details.undocumented > summary::before { filter: invert(100%); } -#crate-search { +#crate-search, .search-input { color: #111; background-color: #f0f0f0; border-color: #000; - box-shadow: 0 0 0 1px #000, 0 0 0 2px transparent; } .search-input { - color: #111; - background-color: #f0f0f0; - box-shadow: 0 0 0 1px #000, 0 0 0 2px transparent; + border-color: #e0e0e0; } .search-input:focus { border-color: #008dfd; } -#crate-search + .search-input:focus { - box-shadow: 0 0 8px 4px #078dd8; -} - .module-item .stab, .import-item .stab { color: #ddd; diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 448c9ac603c..3d2cd23ae3a 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -148,6 +148,28 @@ a.result-keyword:focus { background-color: #afc6e4; } .content .fnname { color: #AD7C37; } .content span.keyword, .content a.keyword, .block a.current.keyword { color: #3873AD; } +.sidebar a { color: #356da4; } +.sidebar a.current.enum { color: #a63283; } +.sidebar a.current.struct { color: #a63283; } +.sidebar a.current.type { color: #a63283; } +.sidebar a.current.associatedtype { color: #356da4; } +.sidebar a.current.foreigntype { color: #356da4; } +.sidebar a.current.attr, +.sidebar a.current.derive, +.sidebar a.current.macro { color: #067901; } +.sidebar a.current.union { color: #a63283; } +.sidebar a.current.constant +.sidebar a.current.static { color: #356da4; } +.sidebar a.current.primitive { color: #a63283; } +.sidebar a.current.externcrate +.sidebar a.current.mod { color: #356da4; } +.sidebar a.current.trait { color: #6849c3; } +.sidebar a.current.traitalias { color: #4b349e; } +.sidebar a.current.fn, +.sidebar a.current.method, +.sidebar a.current.tymethod { color: #a67736; } +.sidebar a.current.keyword { color: #356da4; } + nav.main .current { border-top-color: #000; border-bottom-color: #000; @@ -167,6 +189,7 @@ a.anchor, pre.rust a, .sidebar h2 a, .sidebar h3 a, +.mobile-topbar h2 a, .in-band a { color: #000; } @@ -186,27 +209,16 @@ details.undocumented > summary::before { color: #999; } -#crate-search { +#crate-search, .search-input { color: #555; background-color: white; border-color: #e0e0e0; - box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent; -} - -.search-input { - color: #555; - background-color: white; - box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent; } .search-input:focus { border-color: #66afe9; } -#crate-search + .search-input:focus { - box-shadow: 0 0 8px #078dd8; -} - .module-item .stab, .import-item .stab { color: #000; diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 161b95d9993..3c21a96cef0 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -72,7 +72,7 @@ function resourcePath(basename, extension) { var mobileLocationTitle = document.querySelector(".mobile-topbar h2.location"); var locationTitle = document.querySelector(".sidebar h2.location"); if (mobileLocationTitle && locationTitle) { - mobileLocationTitle.innerText = locationTitle.innerText; + mobileLocationTitle.innerHTML = locationTitle.innerHTML; } } }()); diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index e5c7e1ea1a0..47a8fcdfd5e 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -33,19 +33,15 @@ } function showLightAndDark() { - addClass(document.getElementById("theme").parentElement.parentElement, "hidden"); - removeClass(document.getElementById("preferred-light-theme").parentElement.parentElement, - "hidden"); - removeClass(document.getElementById("preferred-dark-theme").parentElement.parentElement, - "hidden"); + addClass(document.getElementById("theme").parentElement, "hidden"); + removeClass(document.getElementById("preferred-light-theme").parentElement, "hidden"); + removeClass(document.getElementById("preferred-dark-theme").parentElement, "hidden"); } function hideLightAndDark() { - addClass(document.getElementById("preferred-light-theme").parentElement.parentElement, - "hidden"); - addClass(document.getElementById("preferred-dark-theme").parentElement.parentElement, - "hidden"); - removeClass(document.getElementById("theme").parentElement.parentElement, "hidden"); + addClass(document.getElementById("preferred-light-theme").parentElement, "hidden"); + addClass(document.getElementById("preferred-dark-theme").parentElement, "hidden"); + removeClass(document.getElementById("theme").parentElement, "hidden"); } function updateLightAndDark() { @@ -82,6 +78,19 @@ changeSetting(this.id, this.value); }; }); + onEachLazy(document.querySelectorAll("input[type=\"radio\"]"), function(elem) { + const settingId = elem.name; + const settingValue = getSettingValue(settingId); + if (settingValue !== null && settingValue !== "null") { + elem.checked = settingValue === elem.value; + } + elem.addEventListener("change", function(ev) { + changeSetting(ev.target.name, ev.target.value); + }); + }); + document.getElementById("back").addEventListener("click", function() { + history.back(); + }); } window.addEventListener("DOMContentLoaded", setEvents); diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 2394df4c715..06bb34eb115 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -216,6 +216,15 @@ var updateSystemTheme = (function() { }; })(); +function switchToSavedTheme() { + switchTheme( + window.currentTheme, + window.mainTheme, + getSettingValue("theme") || "light", + false + ); +} + if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) { // update the preferred dark theme if the user is already using a dark theme // See https://github.com/rust-lang/rust/pull/77809#issuecomment-707875732 @@ -228,10 +237,20 @@ if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) { // call the function to initialize the theme at least once! updateSystemTheme(); } else { - switchTheme( - window.currentTheme, - window.mainTheme, - getSettingValue("theme") || "light", - false - ); + switchToSavedTheme(); } + +// If we navigate away (for example to a settings page), and then use the back or +// forward button to get back to a page, the theme may have changed in the meantime. +// But scripts may not be re-loaded in such a case due to the bfcache +// (https://web.dev/bfcache/). The "pageshow" event triggers on such navigations. +// Use that opportunity to update the theme. +// We use a setTimeout with a 0 timeout here to put the change on the event queue. +// For some reason, if we try to change the theme while the `pageshow` event is +// running, it sometimes fails to take effect. The problem manifests on Chrome, +// specifically when talking to a remote website with no caching. +window.addEventListener("pageshow", function(ev) { + if (ev.persisted) { + setTimeout(switchToSavedTheme, 0); + } +}); diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 1322b854b7f..baadd3c27b4 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -110,25 +110,24 @@ <nav class="sub"> {#- -#} <div class="theme-picker hidden"> {#- -#} <button id="theme-picker" aria-label="Pick another theme!" aria-haspopup="menu" title="themes"> {#- -#} - <img width="18" height="18" alt="Pick another theme!" {# -#} + <img width="22" height="22" alt="Pick another theme!" {# -#} src="{{static_root_path|safe}}brush{{page.resource_suffix}}.svg"> {#- -#} </button> {#- -#} <div id="theme-choices" role="menu"></div> {#- -#} </div> {#- -#} <form class="search-form"> {#- -#} <div class="search-container"> {#- -#} - <div> - <input {# -#} - class="search-input" {# -#} - name="search" {# -#} - autocomplete="off" {# -#} - spellcheck="false" {# -#} - placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#} - type="search"> {#- -#} - </div> {#- -#} + <span></span> {#- This empty span is a hacky fix for Safari - See #93184 -#} + <input {# -#} + class="search-input" {# -#} + name="search" {# -#} + autocomplete="off" {# -#} + spellcheck="false" {# -#} + placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#} + type="search"> {#- -#} <button type="button" id="help-button" title="help">?</button> {#- -#} <a id="settings-menu" href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#} - <img width="18" height="18" alt="Change settings" {# -#} + <img width="22" height="22" alt="Change settings" {# -#} src="{{static_root_path|safe}}wheel{{page.resource_suffix}}.svg"> {#- -#} </a> {#- -#} </div> {#- -#} diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html index 459b01a9960..62b1b7ca729 100644 --- a/src/librustdoc/html/templates/print_item.html +++ b/src/librustdoc/html/templates/print_item.html @@ -16,11 +16,11 @@ </h1> {#- -#} <span class="out-of-band"> {#- -#} {% if !stability_since_raw.is_empty() %} - {{- stability_since_raw|safe -}} · {# -#} + {{- stability_since_raw|safe }} · {# -#} {% endif %} {%- match src_href -%} {%- when Some with (href) -%} - <a class="srclink" href="{{href|safe}}" title="goto source code">source</a> · {# -#} + <a class="srclink" href="{{href|safe}}">source</a> · {# -#} {%- else -%} {%- endmatch -%} <a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs"> {#- -#} diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 8f484766d9a..f9e9fe0d3cf 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -172,21 +172,8 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { /// the hashmap because certain items (traits and types) need to have their mappings for trait /// implementations filled out before they're inserted. fn item(&mut self, item: clean::Item) -> Result<(), Error> { - let local_blanket_impl = match item.def_id { - clean::ItemId::Blanket { impl_id, .. } => impl_id.is_local(), - clean::ItemId::Auto { .. } - | clean::ItemId::DefId(_) - | clean::ItemId::Primitive(_, _) => false, - }; - // Flatten items that recursively store other items - // FIXME(CraftSpider): We skip children of local blanket implementations, as we'll have - // already seen the actual generic impl, and the generated ones don't need documenting. - // This is necessary due to the visibility, return type, and self arg of the generated - // impls not quite matching, and will no longer be necessary when the mismatch is fixed. - if !local_blanket_impl { - item.kind.inner_items().for_each(|i| self.item(i.clone()).unwrap()); - } + item.kind.inner_items().for_each(|i| self.item(i.clone()).unwrap()); let id = item.def_id; if let Some(mut new_item) = self.convert_item(item) { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index d854aa86b3a..a7c3c0bb606 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -16,6 +16,8 @@ #![feature(once_cell)] #![feature(type_ascription)] #![feature(iter_intersperse)] +#![feature(type_alias_impl_trait)] +#![feature(generic_associated_types)] #![recursion_limit = "256"] #![warn(rustc::internal)] #![allow(clippy::collapsible_if, clippy::collapsible_else_if)] diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 7dbf00420de..86662ebaaca 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -16,7 +16,7 @@ use rustc_middle::ty::{DefIdTree, Ty, TyCtxt}; use rustc_middle::{bug, span_bug, ty}; use rustc_resolve::ParentScope; use rustc_session::lint::Lint; -use rustc_span::hygiene::{MacroKind, SyntaxContext}; +use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{BytePos, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; @@ -362,7 +362,7 @@ struct DiagnosticInfo<'a> { #[derive(Clone, Debug, Hash)] struct CachedLink { - pub res: (Res, Option<UrlFragment>), + res: (Res, Option<UrlFragment>), } struct LinkCollector<'a, 'tcx> { @@ -427,7 +427,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .inherent_impls(did) .iter() .flat_map(|imp| tcx.associated_items(*imp).in_definition_order()) - .any(|item| item.ident.name == variant_name) + .any(|item| item.name == variant_name) { // This is just to let `fold_item` know that this shouldn't be considered; // it's a bug for the error to make it to the user @@ -920,25 +920,15 @@ fn trait_assoc_to_impl_assoc_item<'tcx>( /// /// NOTE: this cannot be a query because more traits could be available when more crates are compiled! /// So it is not stable to serialize cross-crate. +#[instrument(level = "debug", skip(cx))] fn trait_impls_for<'a>( cx: &mut DocContext<'a>, ty: Ty<'a>, module: DefId, ) -> FxHashSet<(DefId, DefId)> { - let mut resolver = cx.resolver.borrow_mut(); - let in_scope_traits = cx.module_trait_cache.entry(module).or_insert_with(|| { - resolver.access(|resolver| { - let parent_scope = &ParentScope::module(resolver.expect_module(module), resolver); - resolver - .traits_in_scope(None, parent_scope, SyntaxContext::root(), None) - .into_iter() - .map(|candidate| candidate.def_id) - .collect() - }) - }); - let tcx = cx.tcx; - let iter = in_scope_traits.iter().flat_map(|&trait_| { + let iter = cx.resolver_caches.traits_in_scope[&module].iter().flat_map(|trait_candidate| { + let trait_ = trait_candidate.def_id; trace!("considering explicit impl for trait {:?}", trait_); // Look at each trait implementation to see if it's an impl for `did` diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs index 31d6ac44a94..edd4e9da66d 100644 --- a/src/librustdoc/passes/collect_intra_doc_links/early.rs +++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs @@ -7,11 +7,15 @@ use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast::{self as ast, ItemKind}; use rustc_ast_lowering::ResolverAstLowering; use rustc_hir::def::Namespace::TypeNS; -use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; -use rustc_resolve::Resolver; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, CRATE_DEF_ID}; +use rustc_hir::TraitCandidate; +use rustc_middle::ty::{DefIdTree, Visibility}; +use rustc_resolve::{ParentScope, Resolver}; use rustc_session::config::Externs; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{Span, SyntaxContext, DUMMY_SP}; +use std::collections::hash_map::Entry; use std::mem; crate fn early_resolve_intra_doc_links( @@ -22,15 +26,23 @@ crate fn early_resolve_intra_doc_links( let mut loader = IntraLinkCrateLoader { resolver, current_mod: CRATE_DEF_ID, + visited_mods: Default::default(), + traits_in_scope: Default::default(), all_traits: Default::default(), all_trait_impls: Default::default(), }; + // Because of the `crate::` prefix, any doc comment can reference + // the crate root's set of in-scope traits. This line makes sure + // it's available. + loader.add_traits_in_scope(CRATE_DEF_ID.to_def_id()); + // Overridden `visit_item` below doesn't apply to the crate root, - // so we have to visit its attributes and exports separately. + // so we have to visit its attributes and reexports separately. loader.load_links_in_attrs(&krate.attrs, krate.span); + loader.process_module_children_or_reexports(CRATE_DEF_ID.to_def_id()); visit::walk_crate(&mut loader, krate); - loader.fill_resolver_caches(); + loader.add_foreign_traits_in_scope(); // FIXME: somehow rustdoc is still missing crates even though we loaded all // the known necessary crates. Load them all unconditionally until we find a way to fix this. @@ -46,6 +58,7 @@ crate fn early_resolve_intra_doc_links( } ResolverCaches { + traits_in_scope: loader.traits_in_scope, all_traits: Some(loader.all_traits), all_trait_impls: Some(loader.all_trait_impls), } @@ -54,27 +67,87 @@ crate fn early_resolve_intra_doc_links( struct IntraLinkCrateLoader<'r, 'ra> { resolver: &'r mut Resolver<'ra>, current_mod: LocalDefId, + visited_mods: DefIdSet, + traits_in_scope: DefIdMap<Vec<TraitCandidate>>, all_traits: Vec<DefId>, all_trait_impls: Vec<DefId>, } impl IntraLinkCrateLoader<'_, '_> { - fn fill_resolver_caches(&mut self) { - for cnum in self.resolver.cstore().crates_untracked() { - let all_traits = self.resolver.cstore().traits_in_crate_untracked(cnum); - let all_trait_impls = self.resolver.cstore().trait_impls_in_crate_untracked(cnum); + fn add_traits_in_scope(&mut self, def_id: DefId) { + // Calls to `traits_in_scope` are expensive, so try to avoid them if only possible. + // Keys in the `traits_in_scope` cache are always module IDs. + if let Entry::Vacant(entry) = self.traits_in_scope.entry(def_id) { + let module = self.resolver.get_nearest_non_block_module(def_id); + let module_id = module.def_id(); + let entry = if module_id == def_id { + Some(entry) + } else if let Entry::Vacant(entry) = self.traits_in_scope.entry(module_id) { + Some(entry) + } else { + None + }; + if let Some(entry) = entry { + entry.insert(self.resolver.traits_in_scope( + None, + &ParentScope::module(module, self.resolver), + SyntaxContext::root(), + None, + )); + } + } + } + + fn add_traits_in_parent_scope(&mut self, def_id: DefId) { + if let Some(module_id) = self.resolver.parent(def_id) { + self.add_traits_in_scope(module_id); + } + } + + /// Add traits in scope for links in impls collected by the `collect-intra-doc-links` pass. + /// That pass filters impls using type-based information, but we don't yet have such + /// information here, so we just conservatively calculate traits in scope for *all* modules + /// having impls in them. + fn add_foreign_traits_in_scope(&mut self) { + for cnum in Vec::from_iter(self.resolver.cstore().crates_untracked()) { + // FIXME: Due to #78696 rustdoc can query traits in scope for any crate root. + self.add_traits_in_scope(cnum.as_def_id()); + + let all_traits = Vec::from_iter(self.resolver.cstore().traits_in_crate_untracked(cnum)); + let all_trait_impls = + Vec::from_iter(self.resolver.cstore().trait_impls_in_crate_untracked(cnum)); + + // Querying traits in scope is expensive so we try to prune the impl and traits lists + // using privacy, private traits and impls from other crates are never documented in + // the current crate, and links in their doc comments are not resolved. + for &def_id in &all_traits { + if self.resolver.cstore().visibility_untracked(def_id) == Visibility::Public { + self.add_traits_in_parent_scope(def_id); + } + } + for &(trait_def_id, impl_def_id, simplified_self_ty) in &all_trait_impls { + if self.resolver.cstore().visibility_untracked(trait_def_id) == Visibility::Public + && simplified_self_ty.and_then(|ty| ty.def()).map_or(true, |ty_def_id| { + self.resolver.cstore().visibility_untracked(ty_def_id) == Visibility::Public + }) + { + self.add_traits_in_parent_scope(impl_def_id); + } + } self.all_traits.extend(all_traits); - self.all_trait_impls.extend(all_trait_impls.into_iter().map(|(def_id, _)| def_id)); + self.all_trait_impls.extend(all_trait_impls.into_iter().map(|(_, def_id, _)| def_id)); } } fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) { - // FIXME: this needs to consider export inlining. + // FIXME: this needs to consider reexport inlining. let attrs = clean::Attributes::from_ast(attrs, None); for (parent_module, doc) in attrs.collapsed_doc_value_by_module_level() { let module_id = parent_module.unwrap_or(self.current_mod.to_def_id()); + self.add_traits_in_scope(module_id); + for link in markdown_links(&doc.as_str()) { let path_str = if let Some(Ok(x)) = preprocess_link(&link) { x.path_str @@ -85,6 +158,26 @@ impl IntraLinkCrateLoader<'_, '_> { } } } + + /// When reexports are inlined, they are replaced with item which they refer to, those items + /// may have links in their doc comments, those links are resolved at the item definition site, + /// so we need to know traits in scope at that definition site. + fn process_module_children_or_reexports(&mut self, module_id: DefId) { + if !self.visited_mods.insert(module_id) { + return; // avoid infinite recursion + } + + for child in self.resolver.module_children_or_reexports(module_id) { + if child.vis == Visibility::Public { + if let Some(def_id) = child.res.opt_def_id() { + self.add_traits_in_parent_scope(def_id); + } + if let Res::Def(DefKind::Mod, module_id) = child.res { + self.process_module_children_or_reexports(module_id); + } + } + } + } } impl Visitor<'_> for IntraLinkCrateLoader<'_, '_> { @@ -92,7 +185,13 @@ impl Visitor<'_> for IntraLinkCrateLoader<'_, '_> { if let ItemKind::Mod(..) = item.kind { let old_mod = mem::replace(&mut self.current_mod, self.resolver.local_def_id(item.id)); + // A module written with a outline doc comments will resolve traits relative + // to the parent module. Make sure the parent module's traits-in-scope are + // loaded, even if the module itself has no doc comments. + self.add_traits_in_parent_scope(self.current_mod.to_def_id()); + self.load_links_in_attrs(&item.attrs, item.span); + self.process_module_children_or_reexports(self.current_mod.to_def_id()); visit::walk_item(self, item); self.current_mod = old_mod; diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 66ac612ea37..53280b3df13 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -4,6 +4,7 @@ use super::Pass; use crate::clean::*; use crate::core::DocContext; +use crate::formats::cache::Cache; use crate::visit::DocVisitor; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -57,14 +58,14 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate } }); - let mut cleaner = BadImplStripper { prims, items: crate_items }; + let mut cleaner = BadImplStripper { prims, items: crate_items, cache: &cx.cache }; let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default(); // Follow all `Deref` targets of included items and recursively add them as valid fn add_deref_target( cx: &DocContext<'_>, map: &FxHashMap<DefId, &Type>, - cleaner: &mut BadImplStripper, + cleaner: &mut BadImplStripper<'_>, type_did: DefId, ) { if let Some(target) = map.get(&type_did) { @@ -102,7 +103,7 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate } else if let Some(did) = target.def_id(&cx.cache) { cleaner.items.insert(did.into()); } - if let Some(for_did) = for_.def_id_no_primitives() { + if let Some(for_did) = for_.def_id(&cx.cache) { if type_did_to_deref_target.insert(for_did, target).is_none() { // Since only the `DefId` portion of the `Type` instances is known to be same for both the // `Deref` target type and the impl for type positions, this map of types is keyed by @@ -204,19 +205,20 @@ impl DocVisitor for ItemCollector { } } -struct BadImplStripper { +struct BadImplStripper<'a> { prims: FxHashSet<PrimitiveType>, items: FxHashSet<ItemId>, + cache: &'a Cache, } -impl BadImplStripper { +impl<'a> BadImplStripper<'a> { fn keep_impl(&self, ty: &Type, is_deref: bool) -> bool { if let Generic(_) = ty { // keep impls made on generics true } else if let Some(prim) = ty.primitive_type() { self.prims.contains(&prim) - } else if let Some(did) = ty.def_id_no_primitives() { + } else if let Some(did) = ty.def_id(self.cache) { is_deref || self.keep_impl_with_def_id(did.into()) } else { false diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index e63534659ad..e7a99ee7bfd 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -15,7 +15,7 @@ crate const STRIP_HIDDEN: Pass = Pass { }; /// Strip items marked `#[doc(hidden)]` -crate fn strip_hidden(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Crate { +crate fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate { let mut retained = ItemIdSet::default(); // strip all #[doc(hidden)] items @@ -25,7 +25,7 @@ crate fn strip_hidden(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Cra }; // strip all impls referencing stripped items - let mut stripper = ImplStripper { retained: &retained }; + let mut stripper = ImplStripper { retained: &retained, cache: &cx.cache }; stripper.fold_crate(krate) } diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index c6b5bec4692..ef7e768a511 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -29,6 +29,6 @@ crate fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> clea } // strip all impls referencing private items - let mut stripper = ImplStripper { retained: &retained }; + let mut stripper = ImplStripper { retained: &retained, cache: &cx.cache }; stripper.fold_crate(krate) } diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index 7b07974ae01..717dc078b34 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -5,6 +5,7 @@ use std::mem; use crate::clean::{self, Item, ItemIdSet}; use crate::fold::{strip_item, DocFolder}; +use crate::formats::cache::Cache; crate struct Stripper<'a> { crate retained: &'a mut ItemIdSet, @@ -118,6 +119,7 @@ impl<'a> DocFolder for Stripper<'a> { /// This stripper discards all impls which reference stripped items crate struct ImplStripper<'a> { crate retained: &'a ItemIdSet, + crate cache: &'a Cache, } impl<'a> DocFolder for ImplStripper<'a> { @@ -127,7 +129,7 @@ impl<'a> DocFolder for ImplStripper<'a> { if imp.trait_.is_none() && imp.items.is_empty() { return None; } - if let Some(did) = imp.for_.def_id_no_primitives() { + if let Some(did) = imp.for_.def_id(self.cache) { if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into()) { debug!("ImplStripper: impl item for stripped type; removing"); @@ -142,7 +144,7 @@ impl<'a> DocFolder for ImplStripper<'a> { } if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) { for typaram in generics { - if let Some(did) = typaram.def_id_no_primitives() { + if let Some(did) = typaram.def_id(self.cache) { if did.is_local() && !self.retained.contains(&did.into()) { debug!( "ImplStripper: stripped item in trait's generics; removing impl" diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 47fc666da9a..899c9e4c629 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -292,7 +292,7 @@ crate fn load_call_locations( for path in with_examples { let bytes = fs::read(&path).map_err(|e| format!("{} (for path {})", e, path))?; let mut decoder = Decoder::new(&bytes, 0); - let calls = AllCallLocations::decode(&mut decoder)?; + let calls = AllCallLocations::decode(&mut decoder); for (function, fn_calls) in calls.into_iter() { all_calls.entry(function).or_default().extend(fn_calls.into_iter()); diff --git a/src/llvm-project b/src/llvm-project -Subproject 6b3dbcc81a470e5da84576d63fcfc19e3b1154c +Subproject b6b46f596a7d2523ee1acd1c00e699615849da6 diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 618c8aab86a..600833664be 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -8,6 +8,9 @@ use std::path::PathBuf; use serde::{Deserialize, Serialize}; +/// rustdoc format-version. +pub const FORMAT_VERSION: u32 = 10; + /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow /// tools to find or link to them. @@ -517,8 +520,5 @@ pub struct Static { pub expr: String, } -/// rustdoc format-version. -pub const FORMAT_VERSION: u32 = 9; - #[cfg(test)] mod tests; diff --git a/src/stage0.json b/src/stage0.json index 6c1b95b4145..525902be852 100644 --- a/src/stage0.json +++ b/src/stage0.json @@ -2,347 +2,347 @@ "__comment": "Generated by `./x.py run src/tools/bump-stage0`. Run that command again to update the bootstrap compiler.", "dist_server": "https://static.rust-lang.org", "compiler": { - "date": "2021-11-30", + "date": "2022-01-28", "version": "beta" }, "rustfmt": { - "date": "2021-11-30", + "date": "2022-01-28", "version": "nightly" }, "checksums_sha256": { - "dist/2021-11-30/cargo-beta-aarch64-apple-darwin.tar.gz": "f7dadcadc22aab3ed9ddd737a9c2af05f42ffe48b431bbad5d43128130480279", - "dist/2021-11-30/cargo-beta-aarch64-apple-darwin.tar.xz": "0ee7c052bb1fd3f3655d9ff74b3f38ebb256d3f523750dbde1be9bceb207cda9", - "dist/2021-11-30/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "68d914f773b122bd1ceae13a55d3c8365753d09d4371e3962401b9a48945cf20", - "dist/2021-11-30/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "b0204e516f0c22b956f227555be5665df96c4e0f60281592b00678b4ea8ad4e9", - "dist/2021-11-30/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "77b771198aaf78c039df9c08493a9af5d1eb02e6b88bd4fc3b42269cdbf582d0", - "dist/2021-11-30/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "6f6465db2c726cc3d2db73150377ed17cbe164297f8cbffc51c8194494cb0384", - "dist/2021-11-30/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "76a8001adffd5d7a607459f1726f3d68c95e6eb4925eac9ccb77b213c37d2385", - "dist/2021-11-30/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "07dac7cfe68cb6b0a1872728c1dfb3fde0f9fa27a08933494faaf58a5e35865a", - "dist/2021-11-30/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "d2d6d2b56cbcc8bb5b2139818770fc155146d6b4469678de8a1e8249f15137d7", - "dist/2021-11-30/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "5f97d1449b9c4461be47615ab49ec408d8f1981b7a1bc0d7b7cce606c14cd5ed", - "dist/2021-11-30/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "097d346e828a37ae5be077f0896796ab6238194846f8ae279cd9e2f510645625", - "dist/2021-11-30/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "71a7906aea42e1048fc43828ece3da720eea4f9d4ff59e970e273f0fe9191e12", - "dist/2021-11-30/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "20e49a6995503dd8215dc9f56ffb87dc9f07fe85a1b0d2f409313836dc0dda3f", - "dist/2021-11-30/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "b9388524cec65e789bb5eaf22cfd63ce837b9a98d1b769901597c6f061f1b93d", - "dist/2021-11-30/cargo-beta-i686-pc-windows-gnu.tar.gz": "7b0bf29bc67904a64560402891d60506a29b7cd64007d7c1f4e168a574009a9c", - "dist/2021-11-30/cargo-beta-i686-pc-windows-gnu.tar.xz": "c580c17566e36cbb91945e0fb9e592ac7578d32da948c70aabb90de80000f5c8", - "dist/2021-11-30/cargo-beta-i686-pc-windows-msvc.tar.gz": "e34436449fb69b8ca696b4bcba8e18a612fee189ad8069d765813d39c708ad58", - "dist/2021-11-30/cargo-beta-i686-pc-windows-msvc.tar.xz": "322836c74da2b221426782e4b5e174571d1da1935d478b4b8b948608a28a20e8", - "dist/2021-11-30/cargo-beta-i686-unknown-linux-gnu.tar.gz": "ab2361cb4cbe44331e34a50728dd56a3db220e08f1b29452f781ee075b236c33", - "dist/2021-11-30/cargo-beta-i686-unknown-linux-gnu.tar.xz": "6375ef38e8e6270d6d932d176a7e62014daf153e873667f6d4a5335fa15f8bf3", - "dist/2021-11-30/cargo-beta-mips-unknown-linux-gnu.tar.gz": "3e80c94aef4511090e6a83f64b304b835ae2a8e769d3beec96e3f08c0faca01c", - "dist/2021-11-30/cargo-beta-mips-unknown-linux-gnu.tar.xz": "af954c96c823d711b372c94a2f2bab32536a4e39bcdd0351674252837096f8b4", - "dist/2021-11-30/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "92464fb6d0691a591637cf342842b42b940f8a84525f1e1f51493734f2ad7b1b", - "dist/2021-11-30/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "5ddeb87b53749bc532322ee8435fd442adbfaa5e80f3b614b7153c40f46d63d1", - "dist/2021-11-30/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "1c60eccc658664853232131fb48dc5d2c66340bb95d242084c211c59407fa667", - "dist/2021-11-30/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "257aab89cd0d5d9af408fc346aeccb8d51e1eba5dc0db074db1f4b57a8d4aab2", - "dist/2021-11-30/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "20b1fa2138a547f5f6644acfbca9e73f8d228578a600c7710cb2fc34a20eb058", - "dist/2021-11-30/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "134dde13eb7dedb8fc608acae62d715937c168a9fe5a449262e9ac9b3f042396", - "dist/2021-11-30/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "4ffca03462b91b9cbb02a022546aa0e16118eb1950a8f040929e5bfceee2b9f7", - "dist/2021-11-30/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "14bfd567241f969de712240f78d83d21dab0bd11ac42da38a2b02da7a59a9dc9", - "dist/2021-11-30/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "f44113175429958961148bef66d0ec1b52850c19c035ac83b0d20139e1116d97", - "dist/2021-11-30/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "3e5f05f0f5aa2fb8b2e63eed7b29ce67831158648f64c2892b477b318a86e300", - "dist/2021-11-30/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "76258605464ea434a2c28c2fd05f1947b2165fa10a2810958397d8352e20215d", - "dist/2021-11-30/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "c4f2e0756f8571ed7b1bd82702d91b32cc40af58e0697c2f307feeb5755f93ae", - "dist/2021-11-30/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "c466a280084c164ca4a120b184eab6403c80db962c0d2d1f2cb5b662746ec4da", - "dist/2021-11-30/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "b6f97111eeab0403c67965d57f9bee2ecdf5f39eb44941070d3cd06745f235a3", - "dist/2021-11-30/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "2ab5f013205446852a06f27b326f6454a5b3fb958413a7e00e1d8402413155b5", - "dist/2021-11-30/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "49dd5e7e3b8091546ef932f359fc4260e3f0b7ec851f43dd10f471c6fe50a5cd", - "dist/2021-11-30/cargo-beta-x86_64-apple-darwin.tar.gz": "ac20e50e745914c8431a5c6993b9dbb6bf7b745e4b45283b230207e7be1bb167", - "dist/2021-11-30/cargo-beta-x86_64-apple-darwin.tar.xz": "dec91c3f6eda827d3976b96da8def71ad3cc0b71fbe1b4e5387a464a8bbd85c3", - "dist/2021-11-30/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "e11e26ad4fde6109808f4cd752c2a810c8ca81b890b0c09902be981a72c43723", - "dist/2021-11-30/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "fb49db7bce2376335f4fda11cc454b3d762bd7f95c5dba85596100bd0c1e148a", - "dist/2021-11-30/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "7703eb725703aeffb57d6a2c0c95c44b6e4eed09b4a99b37346ea895a1d51088", - "dist/2021-11-30/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "65e0f34d9b4af3b270d8d4752c94b58e54895d180fddc3f4b535406e16b8a356", - "dist/2021-11-30/cargo-beta-x86_64-unknown-freebsd.tar.gz": "4624bd8e93bc1c36bccd15b44f484059f485df1c0cd1b8bcf21c4855c85b7ea4", - "dist/2021-11-30/cargo-beta-x86_64-unknown-freebsd.tar.xz": "a277a3fccfba30db2942c8303db16e5112d72c7721fe7a777cf24a301b68ad2c", - "dist/2021-11-30/cargo-beta-x86_64-unknown-illumos.tar.gz": "37e034e5c83bab47ac5cd502d4f6385af270040fb7eb59221bc02cdbcf949d0b", - "dist/2021-11-30/cargo-beta-x86_64-unknown-illumos.tar.xz": "d26eda6fd5533defbf3983f2bb9c07c0cba00abf4c346443080059c4810ef1b6", - "dist/2021-11-30/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "909f8bc8dce0276695f1e88994bd21ba2ad4a3ff66b8172e566b7907d9f2531c", - "dist/2021-11-30/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "52807fac650c03c9d398ce6e5987ecfd5e8e30b5c4e94c320ebc2a6fd665740c", - "dist/2021-11-30/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "3158dcde7e05e9871572dd7044b3c8466687d8afadbbffa4021a443f4973a4ac", - "dist/2021-11-30/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "551ef92e71c001fe48804587e8532b5032d419bd139b2f59cbd8c2e308e3c2ae", - "dist/2021-11-30/cargo-beta-x86_64-unknown-netbsd.tar.gz": "9dd630b19f6c9ce26d2ed6a1f46c383d6bc3eecf1efb80f15a651ef4408197c0", - "dist/2021-11-30/cargo-beta-x86_64-unknown-netbsd.tar.xz": "1f128e4e8f9e98839caf64e68fbd163de1d5323abf40f718643a815081f898ac", - "dist/2021-11-30/rust-std-beta-aarch64-apple-darwin.tar.gz": "3aecc61fe4e056326182db5942cd472039f95788d165940df8b53742f70fb051", - "dist/2021-11-30/rust-std-beta-aarch64-apple-darwin.tar.xz": "db3cdaf50925184df6a79914cd1c0df0c9782f96829d23428b1a0ebc814fb468", - "dist/2021-11-30/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "61df5ab32d3e11243bc2b8506c65af9d8a84a2bc93fc1315d046e20eb048c62e", - "dist/2021-11-30/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "42603c786c02ce754b4c756ac0fe4d88574231f5a8d31b6f9a1192680f8eb180", - "dist/2021-11-30/rust-std-beta-aarch64-apple-ios.tar.gz": "49e5d2df9b1019e21c14a1b7f8e69515c16d810dc354ddbe2429857214b3c33e", - "dist/2021-11-30/rust-std-beta-aarch64-apple-ios.tar.xz": "5323762166729cc7c3c5045b484ea2f50ec0dbdca15d8c7e82f0c29e1247f8e2", - "dist/2021-11-30/rust-std-beta-aarch64-fuchsia.tar.gz": "7510b5b538c735362ec6b12beaa9d3c8720c4ea1f686c643fcc40c5dabca5435", - "dist/2021-11-30/rust-std-beta-aarch64-fuchsia.tar.xz": "19b4d188923a820bc8424fed062bab64a56d33f8f00d9ba6792331f06eb0cbc0", - "dist/2021-11-30/rust-std-beta-aarch64-linux-android.tar.gz": "77a5e84c97f83ea8263fd147e5f5781a61bb5bdbf1cc40a3a8a72becc8dd486d", - "dist/2021-11-30/rust-std-beta-aarch64-linux-android.tar.xz": "c17f843d951d9fa72760e3a071557635da83c0dc279887648979277bcef66aff", - "dist/2021-11-30/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "6e86b78826f5e3d18b2f2aa4f274a5d7bacadbde8d7cfc72cc89dbcb0455fec3", - "dist/2021-11-30/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "e1b1e9eb09e851c8125319432b9fb52a6aa815b7f5bc82efbba7e375aab44764", - "dist/2021-11-30/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "a6589e628f03fc7c39345cfa23827be6cf26391848bc576a66c7701f18a01669", - "dist/2021-11-30/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "a0cb9706216575748a953b6e36b59875c6bf9b9410d4a8085974e324c0cbb7e0", - "dist/2021-11-30/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "c803cfd7c803de2b210d5e9800d44f3365a0b4ae581d987b415fdfb990de1a30", - "dist/2021-11-30/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "a93310d2102699602c348901186992c1305a1a20fd0a2e5d8985a4f32e61eb28", - "dist/2021-11-30/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "2ce3460b436c8c44e074ce1cb8c81bb2cd37ec8ea8fde1b766f113b39412d71c", - "dist/2021-11-30/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "5e65f8409d2a8eb366f29fe994469f257b18e70ad0707be2ca9c144a0b6f9a78", - "dist/2021-11-30/rust-std-beta-aarch64-unknown-none.tar.gz": "a4b73dfbf9df497883b2f5ea3053c256838e1e706f312ee02e1b018b9a7f6099", - "dist/2021-11-30/rust-std-beta-aarch64-unknown-none.tar.xz": "a70bd19ae1fa41a3413f0a0b6b2beff569c1b16829cd675967a6d1cd92d8dd54", - "dist/2021-11-30/rust-std-beta-arm-linux-androideabi.tar.gz": "46eabf68836f62fe8dfb39c54ee63e9fe211ab84443ff17c46b5240e0d08e723", - "dist/2021-11-30/rust-std-beta-arm-linux-androideabi.tar.xz": "9a4e53e3e867e9e18959cba32078c4f7d588247b74e156cc68345808d7b7ecc4", - "dist/2021-11-30/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "66d9e4de284d7a221f66a2c615d6ec0805dc8f1a91a184cc96701cf98116be60", - "dist/2021-11-30/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "1af2fd7a16d51e2f4bd6e1840b935e2cdc7a8f3b3b1144d22b42cea52b9bd185", - "dist/2021-11-30/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "cb479e676240ef682d3ad27390bc2498f80a421d321e9423cb923b972ea86675", - "dist/2021-11-30/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "0011ba4db5a8310199011d37818818867703bf6fbbcd7e1a7bead621eda1e5f2", - "dist/2021-11-30/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "8b192e6f0263d925aac1436887f67b24fa02f31c0fc708c30827f0363f032ceb", - "dist/2021-11-30/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "688755d433c1227db1125ee52e7aa643f27f922b21fbe3a5fcaf70467d159a79", - "dist/2021-11-30/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "b336cef0e11136ccf5c41669869426a376d570042d3c99eed6c448cfe165818e", - "dist/2021-11-30/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "1be7d7f0de2ae63b9dd282efc24531f1146fbc7831b84d9c0cd2c8cbdff32fe3", - "dist/2021-11-30/rust-std-beta-armebv7r-none-eabi.tar.gz": "33d49bd069b9fdbae8a6868e2cce6fcea26cfd0248372d3d3c977828b3fc51cd", - "dist/2021-11-30/rust-std-beta-armebv7r-none-eabi.tar.xz": "e204295b8b17388d8b4cfc04de5690b4b6a377da12df7c24f930c064da787200", - "dist/2021-11-30/rust-std-beta-armebv7r-none-eabihf.tar.gz": "07584d1a4f4979ff86aa8b8be820810366c4fdbda4e5dec93c0a5883804a2103", - "dist/2021-11-30/rust-std-beta-armebv7r-none-eabihf.tar.xz": "4f73d8af677409960ac480c254f25547752ffe08b80785dceb6b6f1fdc0b6646", - "dist/2021-11-30/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "fb998ae84f383f1ee93fb946f396545a60d4a58f1f0107653f3dcf97e2cfb4f7", - "dist/2021-11-30/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "8d8fdc9404422d0519328d6a622262833c5465b1cba62a59951a05f59d6cb15a", - "dist/2021-11-30/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "c8abc1c472326419065caed5567bffc4bcfac2af45fafb7f1327b468f26a0112", - "dist/2021-11-30/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "d905b6339363b2538bc39607c0fc58dae2b8023b1c3c1f745654a839ec178988", - "dist/2021-11-30/rust-std-beta-armv7-linux-androideabi.tar.gz": "69dbb3e17dcdfa9e6acc465fae4427a2596e8bfc024cc18d30201f41bcdd1be2", - "dist/2021-11-30/rust-std-beta-armv7-linux-androideabi.tar.xz": "f012832da820d59a791bf39c25e282c2b92bee75377e4fca7e9520162be62b83", - "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "bb742536d0d7b664ac7277bc5e45f40d64001da0ff1f9e088edc5240e1b35dcf", - "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "6d4c050229400ef1f2e384a4a360569309d1a0828ff07f97c73ca294ef114ca1", - "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "c7c354d1bd4071ef69e8d91ee5c020c9aac613ddb2565c9a3a01fa41903e3715", - "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "1bfe9acf4bc7f1e58f1e5a721172df69be65e049894046561bc94ed6ed67c24c", - "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "96fe9952332d7aee42e61445226793af32995d0f21fde7ebfe751ef2f9acfd90", - "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "2f85ea745f03f779306f78ddff9389f4417d826258a90740a76b37bd14b8fca6", - "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "434b6eaffa2a4c798b4a6f00997d65c55d9fad24d176bbc54dc045339e654432", - "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "955fd83cc57de91fea9aea3f563c4cb5a2611e6dd24406845f7e8be5b7f25f3c", - "dist/2021-11-30/rust-std-beta-armv7a-none-eabi.tar.gz": "45a4818cc22f80252264309263994270b2e15ec8db7ced500cef838f09260fa5", - "dist/2021-11-30/rust-std-beta-armv7a-none-eabi.tar.xz": "8748379556a312b31788b5458b74d5d7fb2fa61f29e5528e449d216c21f4e9ed", - "dist/2021-11-30/rust-std-beta-armv7r-none-eabi.tar.gz": "928a6b77d3e6e8030c6ee454d648c5f6eb0b79a8beda3d11fc3578cc4556ac45", - "dist/2021-11-30/rust-std-beta-armv7r-none-eabi.tar.xz": "428526e30a28a9dba01943800a179b7ba144866f36dd69171a4fd1804345b75f", - "dist/2021-11-30/rust-std-beta-armv7r-none-eabihf.tar.gz": "e1e43b61b7826fe4f8063d89896e7b86a13e41ed3a17ef2684d1bded5252b7b6", - "dist/2021-11-30/rust-std-beta-armv7r-none-eabihf.tar.xz": "5f6478a196f1eabd6d4b58ebacf89c3635a9488f4b2f145283e9352cff5da7b8", - "dist/2021-11-30/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "65b23ab952ed313cc9de94eae473a28eb9b7d9ca8aa432f4d3a08c30484e30c7", - "dist/2021-11-30/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "949e3b832f70c3effa2b78363b42caf0720ede57722c360b710773bd7f3e1502", - "dist/2021-11-30/rust-std-beta-i586-pc-windows-msvc.tar.gz": "06667714b168e2e0d6e0f3e81cc3fb68940f77aa3cd3495d91ce9ff15502ab9f", - "dist/2021-11-30/rust-std-beta-i586-pc-windows-msvc.tar.xz": "9794592856633299de53e697579c75bcf6009c6f05c7bfcadf8c63dfa383b3f9", - "dist/2021-11-30/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "ffb8b8ec98f9732602edcf3e4e628327f8ef80712c59ebaab5392503ed04460c", - "dist/2021-11-30/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "7f60c2798023bdf3993b443783d3d6dd350abfa3bbdce58ada3e9b3d3c4391f0", - "dist/2021-11-30/rust-std-beta-i586-unknown-linux-musl.tar.gz": "f086f349faf5f44b0fbd060f3c40b553aa5a6309a02c08e8a45d27cb3a820926", - "dist/2021-11-30/rust-std-beta-i586-unknown-linux-musl.tar.xz": "05ebd51df4b17c22569d69a65d9542b5010beea023e545859a23bb244162b537", - "dist/2021-11-30/rust-std-beta-i686-linux-android.tar.gz": "0f2a192b970209d10f2ffb4f88dcb6637e1ed822e47fef8e0d3daf4ca8b250d9", - "dist/2021-11-30/rust-std-beta-i686-linux-android.tar.xz": "3aee7e88fbcc0290219a8d980efb1c6d8a1642a1576393fe3b5d400a68b17f8b", - "dist/2021-11-30/rust-std-beta-i686-pc-windows-gnu.tar.gz": "251780731ee8c996dc1adb59148d7a0307642e11f3bf767c0caaf5f37b70b395", - "dist/2021-11-30/rust-std-beta-i686-pc-windows-gnu.tar.xz": "76c8cd535a4ab4f9c0ccca19986f483de63e7c6c0708e37de653acb80621bce0", - "dist/2021-11-30/rust-std-beta-i686-pc-windows-msvc.tar.gz": "ce1b7c98f381f207a26ca3fa5937f5e276eb8f91ef6ae2e0e082370e9ca1c21e", - "dist/2021-11-30/rust-std-beta-i686-pc-windows-msvc.tar.xz": "106f655c10d182b6581e87cff881bf081efe9404b52885b6efed4eb0f09a3a04", - "dist/2021-11-30/rust-std-beta-i686-unknown-freebsd.tar.gz": "2cac777f7178954e5c19e266d57927ddf68b74aa5a0161e35e096569d0a6946c", - "dist/2021-11-30/rust-std-beta-i686-unknown-freebsd.tar.xz": "abd915c242fdd2e8f7d53291b2d84d269f9c6f4c4059c725770c3e47e50c4758", - "dist/2021-11-30/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "f680956e937e421c7868a22ec3ac2a6de7bc8203fae17937793914f4a9fd1657", - "dist/2021-11-30/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "15c71b8a2e8604a49240f5d6d0da65c40c8c207f1ebec943cb8c50cd7a51d879", - "dist/2021-11-30/rust-std-beta-i686-unknown-linux-musl.tar.gz": "71c15bbabb5bcadb603513c73e40a96026fc8f6d5c82e9ea9b6569fcc22d5af2", - "dist/2021-11-30/rust-std-beta-i686-unknown-linux-musl.tar.xz": "4a9af011d4a2b63a0357c6367210fbf4b6e116b5388ed3a62b758a4bad1fa77f", - "dist/2021-11-30/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "c44531c5467c1e01739f3796db1f59c4b6d6483f4bb8c398c751dbc30ed550ed", - "dist/2021-11-30/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "0ec54d445e3c24bf7aa8ecdca45f49abfc2e4013c7af682d7134a5e52e752d23", - "dist/2021-11-30/rust-std-beta-mips-unknown-linux-musl.tar.gz": "3ea1a25b04112d83771e7b713ff8d33418bd18a7adcaaf6cce68f537cb27fefb", - "dist/2021-11-30/rust-std-beta-mips-unknown-linux-musl.tar.xz": "c904834d0fa015d24ba0e929e900ad06bfe773bc4a439f9bbcd8862a5065171c", - "dist/2021-11-30/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "498cda7a23e81ed7563650deb320361c8cffdc10de13ce143175e77f720600ed", - "dist/2021-11-30/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "bb0e95d7fad089cc84e826adffc416757df4480ffdfd09547625950b13b9e934", - "dist/2021-11-30/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "87ae1f563963370eeaa3f46d568339d5589e4fd509d21087db43ca2f1d6a1daf", - "dist/2021-11-30/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "da6268585d69c9c71c92dadb658bc7c055b5ce4c87abc52b5451d1111c1675dd", - "dist/2021-11-30/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "93c67427050266f49dc367a1f8e694989424664f740ae3911f78f1cc53faf35c", - "dist/2021-11-30/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "03f9a6e921555954b33fd7f446e9093ad4b631c86d001303e4c47078d0e1d385", - "dist/2021-11-30/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "6c96a53e86f71965f1922585469501504b79c3347d09409033f871b1c9cdc856", - "dist/2021-11-30/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "000e43f7e40abecd402242455f8a3d60692043ddb80bd15dd6f52acd1c5af096", - "dist/2021-11-30/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "7ee55e1f5a63b52d7b87882fa4131fe848d18dba819d46e16ea2435889d84722", - "dist/2021-11-30/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "b8fc28ffd7d97e76913755bedc2f9e7cec7150e036d13fcf7e50dc5a2422d1dd", - "dist/2021-11-30/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "af81aaa9bd624f57168762dfbae39853ada92043809bff953e108e97169e5732", - "dist/2021-11-30/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "37357e40af421ca5b4d2b95f19eca41ce016404ffcce8abea45e08721664f0e3", - "dist/2021-11-30/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "cbbd98fd3ee6bdd3c01e590c2f10367ec38d799e02ddbc1b0e31027684a356f6", - "dist/2021-11-30/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "defda4e2ef2f3baf8c7d2a9159d17ca439004687f0b6714826408b94d4f0aed0", - "dist/2021-11-30/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "201c5bdc1dba11e039bea9257e17ddd2f50b29448b070fc0edb4a7a9f4e45f45", - "dist/2021-11-30/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "0319b07244f443e254e10a04e75633b293faffc5896ade44c05dde0739356f38", - "dist/2021-11-30/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "54e7cb5a1534ecdbd484ef304f608eb48464ae2c2330958b65b8101f81291319", - "dist/2021-11-30/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "aecedf5ca4d91e98ba3c4faba64699d79b3fd4877f880840d492b4872ccb924a", - "dist/2021-11-30/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "a4cf3bde61d46484e36fd41386840250e0c031414ee422bbb3d37f7ac7489ca3", - "dist/2021-11-30/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "d93e2a290aea3075cd61b950ded4c3756611acc6a59ba7efb9ce2e4dbac76c59", - "dist/2021-11-30/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "69c9f09416b788d93f54734a953ed8dead2a31e1dacd6e67a6550529385b338f", - "dist/2021-11-30/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "808a02952a31ae3a171849dc217763f5cd142622e92ae2b383014bbe37e9b551", - "dist/2021-11-30/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "67e6b61d822cfc9f95a2808917601cf3d2560d636b12a19ee29a790cc06e8235", - "dist/2021-11-30/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "7310493bc6f184b401650fb399015be29a8df009e55fa1cbfbcf9d9608fe61e2", - "dist/2021-11-30/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "fd4db925d7eb598f210ab2d96f692cbdb627acbd6a8976259411a4d2356b8728", - "dist/2021-11-30/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "b5b0394ef612188fd094e355892aafe4530758fe38dc8859ba917cb2febe028e", - "dist/2021-11-30/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "3b7c3ad97393bc702dbd71bc819c0e5f6164cf471171c7c48cfffdf5477b35b6", - "dist/2021-11-30/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "21e6f247a6663918c6e38782e43211224d50d4de22a9162be0c5f6d6d0a9afea", - "dist/2021-11-30/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "d0c9bd56dcac12d7174e11f2acdb16fba41ffb3aba71b6b1b4b49ce7fa115f6e", - "dist/2021-11-30/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "c89adc1cbdb7bfa27f5bfdac38b5ff084eafe081b27548dc243bbff378ec7118", - "dist/2021-11-30/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "3e6f8a86901c1350c54bd89e156af029978f4a25f578ea26f49a1f3332da2187", - "dist/2021-11-30/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "43e74dbeb89547be1b3ad1b532bef97b577530a8b19b825342efb72d91d4b0bd", - "dist/2021-11-30/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "c8c7a22e63353e7c7766e254c3fc0b0277bc8265f1123a38705bf319a7d99a19", - "dist/2021-11-30/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "1759ca2de0ff890918a0f634782557ae2b3181e543790878093f303ede45e215", - "dist/2021-11-30/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "a9ac36f2b4e88ce2f2789e9df46ae679879c111594cfe82b538e4067adad2b5e", - "dist/2021-11-30/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "6260f0616828d79898165bf42875881dc5253143d940ac951b7f295553afb8c9", - "dist/2021-11-30/rust-std-beta-sparcv9-sun-solaris.tar.gz": "42d3e5acf2475d732ce5afe3c2ebea6d332c137d061aa256df75b7ce54c16b16", - "dist/2021-11-30/rust-std-beta-sparcv9-sun-solaris.tar.xz": "7f84ff29dc36a224961e87d40cd6e531c9309bdafaec5de2b043aa89af511552", - "dist/2021-11-30/rust-std-beta-thumbv6m-none-eabi.tar.gz": "6bfdf4e59ac3f9dbde2fa46797bd9bb9cbda232c0d507f04bafd937e88945cb7", - "dist/2021-11-30/rust-std-beta-thumbv6m-none-eabi.tar.xz": "d12901a4efc8395df3c1ac137f86c3da07477277fad138edb49d5c4382a3a114", - "dist/2021-11-30/rust-std-beta-thumbv7em-none-eabi.tar.gz": "38718b50fa2acacc0fac98931a5714df38feb8370fccf8d7a955de3b2c117dd0", - "dist/2021-11-30/rust-std-beta-thumbv7em-none-eabi.tar.xz": "9753c00de1117a5fb9bff4ce2a4434ac6d3d06a1b4b3d0cc44ddb590739b9a0b", - "dist/2021-11-30/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "c1eb35c914ad1a762cf550d54b7ec80cb3a8ab6ab39f5c89709f88e04eeba46f", - "dist/2021-11-30/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "3c092ac130633f327a0afc8bdf8ba252f05d9b0050383122d7ba31cc3f5ddfc5", - "dist/2021-11-30/rust-std-beta-thumbv7m-none-eabi.tar.gz": "fb391d1199eab0854228323d08dd8b27709175697532e4b47e9dab6f26f24a8f", - "dist/2021-11-30/rust-std-beta-thumbv7m-none-eabi.tar.xz": "82347d3a0a123c430a526486dbd8c424732181eede038e2f91f1504d510a755b", - "dist/2021-11-30/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "0cb559fff7f8dc35e5279217ef6fe7c2b5fa3d68f5ca82f258b6885f42e8d144", - "dist/2021-11-30/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "ee1fe1dc9fe620743022939cdeac3ab34135e61897f0707c3b1a0a1b7d730360", - "dist/2021-11-30/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "bb8de6fe10aa624fdd63484403e228a5c592b94d4aac95e2b2401cd8b9472f0a", - "dist/2021-11-30/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "1bb7f7ac88e250534d89f0b0dc74f13ca563bad53956be74418d2aef28d250a5", - "dist/2021-11-30/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "0aea9f5cddb136591d105ebd3607a2e1f402f1c707cf33f21fb5cf1d30101ee0", - "dist/2021-11-30/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "f547622b8f052c6290c530d506d8ee314f90c81ace562a0a533b6ad2ba00b987", - "dist/2021-11-30/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "80f8f7c613c7ff2097f5c346b3ac4a5cf750167277f28655e0263b05a231668d", - "dist/2021-11-30/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "a57b4489a1d46ad3fc303a3b2dd478df66407a3e2dfeb9c12860a543ae5210eb", - "dist/2021-11-30/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "6c4264b2bcecc951c39626fc1cf8de36f1eadbda31a552e14274f728978e16a5", - "dist/2021-11-30/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "ec72f8e861eed6b5e2518b46cd8008d3bd2b6f2a7a42784a2dc8a6184d3ecc62", - "dist/2021-11-30/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "0fc209babd43546d04b3fdd27ce77c96d75aa5eb6595f00586a19a17e4530b59", - "dist/2021-11-30/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "ecdb8152992b4a9779aeda2b4cc638163ac24faf45c484f27316a6b3ff0eb297", - "dist/2021-11-30/rust-std-beta-wasm32-unknown-unknown.tar.gz": "52bbea99f2405f35f58d5448c353c605c2a87e7546e95b86d8baa39b4fc7a9a2", - "dist/2021-11-30/rust-std-beta-wasm32-unknown-unknown.tar.xz": "47ea301d79eada8898907af226b39b4c73ac1fe974963139aee78c3567ee53e4", - "dist/2021-11-30/rust-std-beta-wasm32-wasi.tar.gz": "dc9ccfa3e46e4f3b0e11de8a83885695ab154a2211fa89a20670db116d63a4c2", - "dist/2021-11-30/rust-std-beta-wasm32-wasi.tar.xz": "52d890b402c7e7bb7c0f9b34f2e216f0937453ab42e7c4ce205739bd64ba7dc7", - "dist/2021-11-30/rust-std-beta-x86_64-apple-darwin.tar.gz": "0ccbff8a582047cd6d2a6b30387ea73cfce7e0c61eddf516126836b9f9ca86ff", - "dist/2021-11-30/rust-std-beta-x86_64-apple-darwin.tar.xz": "cab55f71575d58aa7213a7dc4cfb0704ca7faec7203c545aeaff178eebe40436", - "dist/2021-11-30/rust-std-beta-x86_64-apple-ios.tar.gz": "6863523669b65464bd52e1a47f6decf868cc93d2111ffc222bb4a032a0095e3f", - "dist/2021-11-30/rust-std-beta-x86_64-apple-ios.tar.xz": "d5c6e65a656621891f387861c8259116dd9a8ab14e13ea10e93b78834e1d334a", - "dist/2021-11-30/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "ec7130bfff74b7226fb5d0f311dd399f7628cb59ce06b4bc9a9f394067855eda", - "dist/2021-11-30/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "0f52f00f03126aed0260cbfdd9790a62f9f4ceb24e2a3a6d80e8a15a1b4a09c2", - "dist/2021-11-30/rust-std-beta-x86_64-fuchsia.tar.gz": "1a3f4c6c1528050820b85e07aa96af6588c7d61935108cb5110d1e0c964142e8", - "dist/2021-11-30/rust-std-beta-x86_64-fuchsia.tar.xz": "fe9488c3476e931440ad487a4cf265fdd3c01e18c9e43b33f51b9eb078821282", - "dist/2021-11-30/rust-std-beta-x86_64-linux-android.tar.gz": "c7205b1cdcdff00d91a3991b1f40674b075c34dc0877de4786da5ab85e3b6cfa", - "dist/2021-11-30/rust-std-beta-x86_64-linux-android.tar.xz": "87a3cfe8992ad615d5522d97ace91dcc86057d060d82b581df206f2802225a0e", - "dist/2021-11-30/rust-std-beta-x86_64-pc-solaris.tar.gz": "cd9eeb26fe909e38d8d8129829d19b4d04d96014496cc7f2f4ae077b94f2aae3", - "dist/2021-11-30/rust-std-beta-x86_64-pc-solaris.tar.xz": "b6e59180ff89f7e460fcbc246802e6441c71600774ae5cb2d9af464365a642cb", - "dist/2021-11-30/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "45e07be14211ec7c9f3c1ad0eb9f7a9b422b10c842d5d0e8b0b498751ab7ae0f", - "dist/2021-11-30/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "593f70209f3b5b4e126d57ece0b1adefb4bc1055cfd168779d854369985b2b2e", - "dist/2021-11-30/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "6e14f3431da08f63d82e5b1e2c56fdf13f93ea7b6660dc64b1c855d00c008257", - "dist/2021-11-30/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "6e6355686d22213d27f5dbec0b7ded38532e79ac904bae978a8eb5fc880916cf", - "dist/2021-11-30/rust-std-beta-x86_64-sun-solaris.tar.gz": "39bdaa250d8f17914602a2185c51014f7fbfb1e30991816a432c3897338b52a1", - "dist/2021-11-30/rust-std-beta-x86_64-sun-solaris.tar.xz": "ebab0e4b13e0b3bdbe0ac858d5a4ca28bb813854aea1d8ec86d8e220c68b3442", - "dist/2021-11-30/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "a700f1736b96c4e7237305dc98a79163b07127f0aac1f436415c233b8495a5af", - "dist/2021-11-30/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "e94ecf7d1c9a5144577fdb14b7232b11dff0ebbfa8aae8cb4884d4ed9c5bae77", - "dist/2021-11-30/rust-std-beta-x86_64-unknown-illumos.tar.gz": "209dc9917790c2be8777c597e19a9f43301aaaaac3c9731e9d0512e6918334b9", - "dist/2021-11-30/rust-std-beta-x86_64-unknown-illumos.tar.xz": "6e4810c7484c231f0edb15ae5acea822ed5d868eaf041438afea4b6ba38be35e", - "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "df952ee1385da9457c4e95dc08ab59ca915f5f211738982f8db3684cf80967fc", - "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "62d7383ee21b0a7d072b15a9877a922f8dbcea42d910c2cb3c4129152b26ea9a", - "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "be28225516fa38edd34e1af5f051d7c8ab5f433cc5814df199bc451285d95e0c", - "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "1a6fdfac24feb34744daced6c6545c844ff13d5e5f14620520d5ed4b85be8742", - "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "c0f098faa0c9de6a8e82b80dfe44bfa9d4482e118259c33452ef025885ceab6e", - "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "1d1ed7cf8fc16efab3faab9ef5abadac9ab98d3b60522fde0612ac0b256de528", - "dist/2021-11-30/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "1ed41e8019480cd151a9ddd0f080afc56ed0afe47cfb7c6b5a6a2473ff6e7e81", - "dist/2021-11-30/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "849c04115660abdf1d4460aef2d87021c6ad52423c83dfed3c2cec8e380ae6fe", - "dist/2021-11-30/rust-std-beta-x86_64-unknown-redox.tar.gz": "e3a35d33b3282fd156482c85e19817f78dcd964de8b712a6e46b965dc60d5204", - "dist/2021-11-30/rust-std-beta-x86_64-unknown-redox.tar.xz": "d5bfbb1415a62547b9e2a24b770a3c6e4d531101cfb2360b7a7de34d0bf18974", - "dist/2021-11-30/rustc-beta-aarch64-apple-darwin.tar.gz": "28beba0ff958b93f85618e49f13f4062cefacc82f6b5911d42f00515f99c5abe", - "dist/2021-11-30/rustc-beta-aarch64-apple-darwin.tar.xz": "07c6a43130112c93745e729c91669243cd28b73fafc7d9b32b4f22650db7bcad", - "dist/2021-11-30/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "9e70dc74c4428438716d14861797380ce7f6617bc93b83c74fc1a6f8aca99392", - "dist/2021-11-30/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "8f61ec8129b7b0bcc6b329337e5e0323054a438e999615687a18fdc42a8d0692", - "dist/2021-11-30/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "bba3cbfdd2842cdf8f2698b709401db6a641227d1742595e3959f1f0ace37c5f", - "dist/2021-11-30/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "fe74ad76a2cffdff0a2fb953f31b73d80a0bce75402bf65f01d250fcae6ff779", - "dist/2021-11-30/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "cde952fb3c38a969c0743d2f9d90e256db8613c463a4b23d6119656570978eb5", - "dist/2021-11-30/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "f2dd88f1b4ec97aaaebb601d20751d50536e85b2cac36740abbc03fa8a4d0d06", - "dist/2021-11-30/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "1a4414987e4da2c8086590fe4ad531f78862443eede3bc9069efb424900746d2", - "dist/2021-11-30/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "1682f8bde2562d4b9183fa512bc1e54d2a821fd9f63208a51489f21deeb7fcfd", - "dist/2021-11-30/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "ca40f3c5e8fd8bd6d89d3c0a3ad4d767353c1b4138e2720371a275c9c52c9117", - "dist/2021-11-30/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "c7afe4eba5cdb02a2e8ae224a0970c8aa36ef429ac298b0f98ff41a0d911aad1", - "dist/2021-11-30/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "6acd677fda38aea2b960f2af6438b30c3b6bd759bb3e56228a1096445ddd100f", - "dist/2021-11-30/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "451a2e139771f39ec09a7cefd48885ec30f732668d50c750d42e6c58c250f8fe", - "dist/2021-11-30/rustc-beta-i686-pc-windows-gnu.tar.gz": "a1df7d105231d4941a55a9f850d39acc201a99dd408d523935799b70fec30c6a", - "dist/2021-11-30/rustc-beta-i686-pc-windows-gnu.tar.xz": "3005718736a2a0fa3a4f1be10239cfb467e9cabe6ce366f9909826bd3c06a990", - "dist/2021-11-30/rustc-beta-i686-pc-windows-msvc.tar.gz": "695039c6737fb3bfd325fbebdab61aeef80ec427ae3d40d8b82e8b317e147fc8", - "dist/2021-11-30/rustc-beta-i686-pc-windows-msvc.tar.xz": "7a5038b7299de71d3677042647fca501984d1f2a52c1d84052956ff7854622b3", - "dist/2021-11-30/rustc-beta-i686-unknown-linux-gnu.tar.gz": "d21dd4c98d38186544aee9b22b439d67d77c0a740357dfad7fea3c4a9b8d1332", - "dist/2021-11-30/rustc-beta-i686-unknown-linux-gnu.tar.xz": "e62a7c9809de668343323eb9fa1a1f6cc302a6e161e64826e9d31bd202f2f472", - "dist/2021-11-30/rustc-beta-mips-unknown-linux-gnu.tar.gz": "b85eb1bff16384b4f6ad268a01bdcec539b9ea412abb6d64618521cb0e63985d", - "dist/2021-11-30/rustc-beta-mips-unknown-linux-gnu.tar.xz": "ce79b36723a65419e03ec77ea14680791d683e5e04332eebdf59550bdaaa164d", - "dist/2021-11-30/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "e778edd911e09c5c3b46aeccbabcd8ead78dd38086206d03406fc8dce52806e7", - "dist/2021-11-30/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "10afe035ca7d3a967b467875b1345dde8bdcd3f8c4af1e917bfa2c676e0fec70", - "dist/2021-11-30/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "6b6c3386ebec138ff07a21d3f5631263219c226ca146bf97fe0a7bb9fee9d0c5", - "dist/2021-11-30/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "5ff6430623d0f3aa14748f371e34072aba126a16429928f8f99172190f369fee", - "dist/2021-11-30/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "369ad16e85e4f2956e400105e6d8374ff64c473c3c3b61ae4d916214d5f922da", - "dist/2021-11-30/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "1c8adfb22f724fa98f30f23378a28729e144f6ab9bba54adf13111ca4648ed78", - "dist/2021-11-30/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "b3e270c6272420c31ee7bed8ed36c113c879a384fa5b85af0deb7d43a355ca2c", - "dist/2021-11-30/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "a21cdd8d182cc64ceaa83e522299860c2710dee780e8f49ff107a73fbd73c3ca", - "dist/2021-11-30/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "1a81076b8e49647b61761a38ed283a9a71b326dc321920f7be453e0e15ae2465", - "dist/2021-11-30/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "3f8ce23f81623a00de63ce7e82e448eec0901a92f908e6aff362807bae14ff84", - "dist/2021-11-30/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "eaa3b365bd91a5770db85e8541ee28c99988635521c0f2dfea05218172f11a55", - "dist/2021-11-30/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "3f856ae24c4737bf1928025a10712b6d856788d988fb5018631c525d13b68e29", - "dist/2021-11-30/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "c672cbf2caef81f7ab923ff7c6a05f1865057278180a686f810ddc71dacc49d0", - "dist/2021-11-30/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "bda5d2234aebdc175c87da3b77d050c56bced21a794c416bb9090c0ae3374be2", - "dist/2021-11-30/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "59e01371664f8d39c7a06c205af0f5ab9aabdb3942be4f493d05ab71047619e8", - "dist/2021-11-30/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "de956b5275e38e0b4223819973e85f5f65c409addd786f7ac2d525a79c3f0c92", - "dist/2021-11-30/rustc-beta-x86_64-apple-darwin.tar.gz": "4f78d90362488a866ea7b1cccbc61f925d94034b46dfa775dea75223e67d755a", - "dist/2021-11-30/rustc-beta-x86_64-apple-darwin.tar.xz": "3520d028e9370087cfa57eb7225dd76c008cb08ffb01c8101aaa86104f427f12", - "dist/2021-11-30/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "f954349daa7dfd819ec0a7335a47b1d3b2ed0138eae31c56288d9c523cdf56b2", - "dist/2021-11-30/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "ca046d8fca5fa48117c61c70a21176d9220a3c62af9fdc9b899c157bb196a5b5", - "dist/2021-11-30/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "61ae4421bdf798a5ca1a8bc8c8521dfb29a707e40d382dbd2e155f134956ac33", - "dist/2021-11-30/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "495076dfc2fa0b8d96613e34f867de9d43483984a8bd6839bf273c2be38039b6", - "dist/2021-11-30/rustc-beta-x86_64-unknown-freebsd.tar.gz": "828526bc23ad8802071bf4f2984faf3549139eb4ce8ebb9ba8711c196d2bf437", - "dist/2021-11-30/rustc-beta-x86_64-unknown-freebsd.tar.xz": "fa2464350b2ac29bec6751c551cc45b7af92c25d2cf1109397e724802d4859cf", - "dist/2021-11-30/rustc-beta-x86_64-unknown-illumos.tar.gz": "a1d9719668ea1887d6202c25b9dd2b7d40bdd240f3f753af77ac93f126c84c38", - "dist/2021-11-30/rustc-beta-x86_64-unknown-illumos.tar.xz": "4b36f5d448bf022f90e284c22a44e0b87ef8518ec93a297ceb703eb612ef80d8", - "dist/2021-11-30/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "63e654f5e8707a0536381025bdbb43d498c70a29a5ada0ecdb12e23844cc9a9f", - "dist/2021-11-30/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "6b5b74abdcb1cae42620cabc142a119b58823e9f2ac0c3151e087a76323c5cae", - "dist/2021-11-30/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "f3aa2d52ce5da066c59de609ebd5df60ac908c7e0db23ac4afe69b927ef2a974", - "dist/2021-11-30/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "6e8858dbaf50a8211516e5afa83e4133d878e0d4b19ba4a3e4c3e51cb80210b7", - "dist/2021-11-30/rustc-beta-x86_64-unknown-netbsd.tar.gz": "9028dd44728092ccaec86f415abdb3733f3ea58ab7c3d736e96e27540cc66a2d", - "dist/2021-11-30/rustc-beta-x86_64-unknown-netbsd.tar.xz": "c6720fd231b54a04e1ba3ed3fe333b1d8ef5b771ce341b4c112169a293bf713a", - "dist/2021-11-30/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "d987783ba5117529b325bcf6f5e7abd9eee42b5ea86ce5109a4fd3f450af8062", - "dist/2021-11-30/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "5d5838733dc64e302991465c1f371fde855ee410d42d1713ddc1c471b469e1a8", - "dist/2021-11-30/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "8593ab35bb800312d6fe4c4a4d151feb26187c6db0d0d5ca5e3e98a007f8a4ff", - "dist/2021-11-30/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "a2ded0420cc1d98df255c7ef93247b9a6d3d9ec22e42c477305dc15ef35fd329", - "dist/2021-11-30/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "652275e77d73f122c12eb952338661562a48fc76164d6549158abc14fb4e4a4a", - "dist/2021-11-30/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "fbb49b56bb11348e07124d8216b8f8b6e26d8697abb05afec0ddb07a456b29e5", - "dist/2021-11-30/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "817c7ed90ab8cdec1dcfc8571391a714002b49fd20da0ae32135f57d233ffbfb", - "dist/2021-11-30/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "cbd8674c65babce944bab6a6f013d44a2c7d6829434a6b97edb1f1e1df1c076f", - "dist/2021-11-30/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "66b13ffad073bc624ebdef219e61f8972fc6be354aaf1f8ede58a3acc01314c3", - "dist/2021-11-30/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "11ecfef218376fd2232ad552526b39173c5269130f02e408a7492762cde87a6a", - "dist/2021-11-30/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "07ad99e019141843f5d6f8c302b9d20c7453ebead79e9711af33c9c8081b9e22", - "dist/2021-11-30/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "6656be84a9b5a63083d63e3a87bc928b424109efff48e3a6770e026c6ea7c2e8", - "dist/2021-11-30/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "155422628d41ce9730f4503bffa12e396b58692c906828acf15f0dd39b3d491e", - "dist/2021-11-30/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "fc75c3836489bda30d340132d0d5ab8ee7f7c67617e4dc66a9eae559bbdb0421", - "dist/2021-11-30/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "181d557c8f73c8f22ed63a8f98e53f6d88871fd694173aea70c53d42c0c55ae2", - "dist/2021-11-30/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "5defc562a2f0ced4539006692cc969cf89756637f5f5c62be0276dfedd6f3db6", - "dist/2021-11-30/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "f28b3fdf5425e7b782d0f78ca95613efd87b2b0d14d44c4490f17d4eb452f183", - "dist/2021-11-30/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "b6cebd5a23bcc504d05c8dd79654baf2ab45b162c59b7b843e24efb7e2344011", - "dist/2021-11-30/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "c59850b28fcfb1608c7e91890b8628ac201b87b4d9af7e9fd019e3e4a137c033", - "dist/2021-11-30/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "ad808569083691ba31b0e10222f9dd01822ade91689bcb060544f28b99f2a299", - "dist/2021-11-30/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "8fca357226b91cc712b888c0a62f9e52b121ab6d9815ea5f53bbfd243b895b69", - "dist/2021-11-30/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "7f5451fe6946c16a7ba404c8bab33816d58d478b1dc0ea1ce6b85befe26ddf77", - "dist/2021-11-30/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "7cc76ce31cf59f1cbeca87a46c996e905f048acfc70d438eae2a32bb67fc60c1", - "dist/2021-11-30/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "429bacebe2a9f1478a00b1573fe4e1b071c6348d800182993c8b5d8ba54d9615", - "dist/2021-11-30/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "701a12b5a4a689e6b2ef260e35ed2d22c00452cde5e18ce0d886ace37e81964f", - "dist/2021-11-30/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "0ef78c91a3220226619f20b28bf67947a56ff31f369d5ea7bfc2aef356060e42", - "dist/2021-11-30/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "0765a3b65315bbb1381927eaf6f65f16fd09dddab41d7398e483bf001ee7bc3e", - "dist/2021-11-30/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "c74b0833f995ffad5c812ba130f423485bd8297eca0c4eae227852a88ece8521", - "dist/2021-11-30/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "3c9d5a35ef1e459ded4dcdcad40bc5e3bcd5b2821cf4f46dbaf2c2c3259fa3ff", - "dist/2021-11-30/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "0aa8975a6dbd103a4764ad643de6094bd6911bd3a90d46e24ad1eafcea2870e7", - "dist/2021-11-30/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "a0ee2ec59ed07ba9c9e48076c954f5c6e4d39809d9e4923337db2627ea279c6f", - "dist/2021-11-30/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "e712fa72a41dedcd50c6531433220904b9627fa78bfa15cdd96d97161981cb77", - "dist/2021-11-30/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "fc7809520a4a41ccb0ffb303c7bbc96443308387890ebdb65a25c3697a5c3eb4", - "dist/2021-11-30/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "84a8fa7468b9e59465f85607f84960e11faf0f37bd766d55b6be985db89d0d17", - "dist/2021-11-30/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "2703dff8cb1c0ca08787f1c7715885c5b09919c040783ba98bd74f8fe3af704d", - "dist/2021-11-30/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "a3e25cc857e990b467c804f41e23bfbe8ef02630b48703fc1c7fae692e16eb80", - "dist/2021-11-30/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "659a9ca0e1296f817cd9f90fed9ccd7d3c7c3e7eea7e9c437bbeb2d951a2669c", - "dist/2021-11-30/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "21e83ac3b148f0f690cb9a39b385fb0d5a82d6eea9ec46d4d4445b5a660c6d7c", - "dist/2021-11-30/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "c8e3300a426cc4a80ba4f1cf0c6822d9b883f24c486b991f2056938be778d43f", - "dist/2021-11-30/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "55f1f7d84828b3cc5d13b10e549a74f2f1df11057ed48e75fbafc0d3538daf03", - "dist/2021-11-30/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "99bf70cee39b2ce73dbe5827fe3d93e45241faea284acb3f8004cf7e700e1704", - "dist/2021-11-30/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "dfc569d57211eae74a2cde5db180d2f2f44bca04f811655ef1f8d8c2154b97ef", - "dist/2021-11-30/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "679d69ba6a4b460f9672f1ec1c2939ac41ee7f911a2a74eaf6db477aa088e6e3", - "dist/2021-11-30/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "3b9a899fcf40db84be8bd14e7c767c572c7d8c7c85f90997b8278fe8726413ae", - "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "19be469ab711dcee7a7243e865efc5addf8b2cdbdf15150a2c367692c45b9f94", - "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "789c7129e235b65860a514fdb38f01ac195af610d4ac6a296d272a6f36d72344", - "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "18657363783d0967d871ee1ed8905b3db0c3b761910fb06ea10980ec6b5ca082", - "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "8b272546a9eb8b23724fbec5577fc0c917a23e994befc38ebfa797957df03b9d", - "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "4e1de312f07fb98845a881b44c2a76ec9abf61e5aba46e8e384de1cd297957a3", - "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "a13ad29e2d06c9df233882d009ba8354d92d2fb29239cadaf858b9abc8b477d9", - "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "aae38bbf1eb7e0da50eb7f226897dc85e88b5e008ef901a93dadb0550f4055ac", - "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "757564eaa1a339d37b59da304bbc7a846bb883a73c62b78df39dacd947606ec9", - "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "5f3a83079cb1fd7d8b9be44d0df7b57c6dc79da8e1762eace67c122cffc2d4ca", - "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "e47ee14a1e679ee5f23936ba7d7de13dcba082c7f32e366be7a990503c91f6ad" + "dist/2022-01-28/cargo-beta-aarch64-apple-darwin.tar.gz": "8c62238c1d0a6ce177f59f5fb92f535433bd4be45d146def6527d0cdadd35422", + "dist/2022-01-28/cargo-beta-aarch64-apple-darwin.tar.xz": "bc6b381296fc6c882af149f39f2a3b9de35fa4c89ce95f41a2ce1aee2fba051c", + "dist/2022-01-28/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "ca2ae341b04e558315d74b62d63ea860aaaec633d5fa604a0af73cf197e540fd", + "dist/2022-01-28/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "f570b2a8902931e49374ca326a2fdb3294d688dcbd053e767e3b01e2fe749dd5", + "dist/2022-01-28/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "d22d886ff0017682c27aed6e43e0a3519864847a36ea7546bc7924340098ebbb", + "dist/2022-01-28/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "cb2221cd5c4e6251bcfb5e1d6ae49bbdb3d6463258866cb3971f86db4e4221de", + "dist/2022-01-28/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "64046c814a93d4771e6c835afe30303afeb4c511282d2fbec1a716334ab1d630", + "dist/2022-01-28/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "1f3ebb839986c3548dfff2da3c716e954bb0eb40abf823e1f1933ba79425b85e", + "dist/2022-01-28/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "50c894bf151d8d8073d667712097c1dbb254c99ac1fcdadd495a7928d21a957a", + "dist/2022-01-28/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "e6a52d5cccf994e65240983924f6b8469669dc710715060730e94e67dbd74877", + "dist/2022-01-28/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "91c47a849fd1ffb764508d8a287bb717627d3a6fb12171df7bd427490e826dda", + "dist/2022-01-28/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "a493a29a384a9573ab29ce9f366dc419907500a01e389e8486a5f5aa57c8394b", + "dist/2022-01-28/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "c55187e202b699570db7ae49a1fbd615696f30008be60a3bd5c9ee708925e4a5", + "dist/2022-01-28/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "288ea72dff7dc1882b51b4d4e73ac8d05f351da44a99d3ad5ee50b231f189f1b", + "dist/2022-01-28/cargo-beta-i686-pc-windows-gnu.tar.gz": "a746316d99b1943cd63c485180c512ddfc7d394fd76a51f9ed56dd2dcadc032a", + "dist/2022-01-28/cargo-beta-i686-pc-windows-gnu.tar.xz": "4395f831aa0a9413b5733902df58c6474913c53f46600ffe6f694c4312dc9d70", + "dist/2022-01-28/cargo-beta-i686-pc-windows-msvc.tar.gz": "d1f3441addc86e7b5bc21fbb2550e6a3e59a818027137ce2bac1b3208168726b", + "dist/2022-01-28/cargo-beta-i686-pc-windows-msvc.tar.xz": "4081e7ab2bb2208d636812f74a9f5b7d3c057f694d40589aa3affe3df35d0981", + "dist/2022-01-28/cargo-beta-i686-unknown-linux-gnu.tar.gz": "ab9bc43f20705cf5899d35381f3bd432a346c85762182a8f3b61adb93149910c", + "dist/2022-01-28/cargo-beta-i686-unknown-linux-gnu.tar.xz": "b50084926003b1e7b8f3a6a60f41a7c1dce764b1ce367567c112293aee16c244", + "dist/2022-01-28/cargo-beta-mips-unknown-linux-gnu.tar.gz": "79bebb05444b1288ad6faabc9ed7365206aa8321195285565130017cba61e3d9", + "dist/2022-01-28/cargo-beta-mips-unknown-linux-gnu.tar.xz": "ee12f3ae5a08329a482aaa0764e4b674337c659fcc10132220d67313ba663634", + "dist/2022-01-28/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "597e2021c3d56d821f91ff26b65ca31c837e6451d7f12d04494208f0b0dac847", + "dist/2022-01-28/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "23976bfa23b9a4d0e211daa4fa50fc34e57af95c05c2cae061782b180c9cb308", + "dist/2022-01-28/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "e9b7393951081be935b6f97a0bb5d974975e555eea291d256913f07c9a8ea21e", + "dist/2022-01-28/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "c12b8d1711078cfe2506dc069bdc6a823b8720f10f5f927d2fe0d8a4dac09fd9", + "dist/2022-01-28/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "dd810231860fa9d925a641a9928b05917a697cb205acd6636e11c5d60cc3badf", + "dist/2022-01-28/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "2d36e70cd07a97a92f23b26984cd8a1310c9762cc61e629c69a66a3deb53884b", + "dist/2022-01-28/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "65187ba25062e668abf1b401364f99553ebf8d61d26a5e4a833a00a3dec38f64", + "dist/2022-01-28/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "d5237004a0d161cbbc99c0c36072b2b4ce1112ce2ac26c8dd1770711c5cad8fa", + "dist/2022-01-28/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "56722110c9436681db0946e6b66883323c077cac33ef666c8f4d79dea3b0f073", + "dist/2022-01-28/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "d3957129b72dce1d1ab4666b8aa826d93ad938ac42ace1fbc055c97148b5f217", + "dist/2022-01-28/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0b8e012c149c64a163cb22bd0a980cbf30cccd260bd4244a67c64e6adb250cc1", + "dist/2022-01-28/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "cfd05fd445176914d90e2f8f6ac4db60b6adaca32551b0290a06dd18dbdfe768", + "dist/2022-01-28/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "ba7b03932cdc6d25b1c85e0ceb35360fb41837904283910aa7452ff41ce7b40b", + "dist/2022-01-28/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "d036966c31e6f89c52a40889094042454f848d51a371167fde5a99a7d37d95b4", + "dist/2022-01-28/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "383957085d629e7a64afc3a560a8cfb9dea25b7deed71b9bb0e172a1218713fb", + "dist/2022-01-28/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "eba3a543082a934403ee72222f397831394633f092fbfe34aba21da2f5a3f6ff", + "dist/2022-01-28/cargo-beta-x86_64-apple-darwin.tar.gz": "fc8f6ce885d9fa29b71ed8be24da9bf718ed581e4738c167952b68667acb8daf", + "dist/2022-01-28/cargo-beta-x86_64-apple-darwin.tar.xz": "47560ce1cefeca1b1b80f4df3a8bc01cda9de6aaa9c46e64c5fb051e1e221e08", + "dist/2022-01-28/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "281c046114664c1df3629bd2001d4785e930d7f86a743acf21d2a2b117b9e857", + "dist/2022-01-28/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "66207bd42c186fd52c1ab4156343842f5e561770142762dc7f553460d689b444", + "dist/2022-01-28/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "949de6cd5b2856d4c70162bb6a5321ec193430fa0120e69bf6af9851f9e0d17d", + "dist/2022-01-28/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "796f3cee5426cf482da4e065351ad1b7208cfe03addb721433594ff7321d0611", + "dist/2022-01-28/cargo-beta-x86_64-unknown-freebsd.tar.gz": "2e587bbe22cfb0a8f62822279611505d31498bcce1e85578fb7ac092ae88007d", + "dist/2022-01-28/cargo-beta-x86_64-unknown-freebsd.tar.xz": "800ac9e61fdff1e046c8bf5708fde53a8ea96ebb9c74d1268dbb15518fa1a2cb", + "dist/2022-01-28/cargo-beta-x86_64-unknown-illumos.tar.gz": "8d543d45cc1770ba6d7591c65aa9fe20ec7d877e227e5d9fd3778b8dfa1fa073", + "dist/2022-01-28/cargo-beta-x86_64-unknown-illumos.tar.xz": "dfb18af670d92c55539bb99df1b48e834dcd3ac080c2a93b66d86785e01d7784", + "dist/2022-01-28/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "21539d224d42f19d6ac44824c13c2a81a33695239d6c9903921ac89ebedf1608", + "dist/2022-01-28/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "a9b81e05c3341d89e14cce58af2334c4a09ecf7e468141aaa74f7d32383b4a41", + "dist/2022-01-28/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "cd0b693001a83b24e31b380f02b02cbd92365b1398884e174bbafc4991470747", + "dist/2022-01-28/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "5755a6a61d233c097e99b5b6597f70e42f79feb3e661daecade9847fbf322019", + "dist/2022-01-28/cargo-beta-x86_64-unknown-netbsd.tar.gz": "807f8fec9df54aab2bc2b70d8fe581922ed9f6210608bb3c06ca919c4ce18c77", + "dist/2022-01-28/cargo-beta-x86_64-unknown-netbsd.tar.xz": "29defeeaa32612bef8b0fc54cf70ce7b472dab9a0bc3bd4516dfbcfad682adec", + "dist/2022-01-28/rust-std-beta-aarch64-apple-darwin.tar.gz": "bf8adfd2906d4fbf2e86700a2d753afb6397a0a8cbb3249977fb5b5c63cb7fea", + "dist/2022-01-28/rust-std-beta-aarch64-apple-darwin.tar.xz": "eb45b62563528fe2eb53e8a4b21bd94f818c6d7e053a6d467854bb4870d97124", + "dist/2022-01-28/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "fc0218862447e94362de8b4c0537ab3e52715dd3becd3a467d2b8b772379eafa", + "dist/2022-01-28/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "290440ff743ad923ab3dadbec37b5f8f32bf0fb71cd52348932045a358a7c79d", + "dist/2022-01-28/rust-std-beta-aarch64-apple-ios.tar.gz": "c2d73f7b0bc523ffbaca6b996d3739d7504d49197a3f43660ef0b60b43e0d372", + "dist/2022-01-28/rust-std-beta-aarch64-apple-ios.tar.xz": "8aedb963e75125eb73f0cfb5fca4c1e687f9c05bda1829faf2feca67644b3f05", + "dist/2022-01-28/rust-std-beta-aarch64-fuchsia.tar.gz": "9a54522ddbb3d013584374123bf9af94529880641b1a06de95f60b003e4cebb8", + "dist/2022-01-28/rust-std-beta-aarch64-fuchsia.tar.xz": "2fa07e359705959879b53d2384ba4b1cdbf5cf9d2d4de09f7e1951a7f762233d", + "dist/2022-01-28/rust-std-beta-aarch64-linux-android.tar.gz": "55e1116809e6b6a2e2284496ab5295687ad5ea78b258425fdfb1408463b5e13a", + "dist/2022-01-28/rust-std-beta-aarch64-linux-android.tar.xz": "a28d4e982f7e9be7d77a56aaa2a2cb56d8d9e973abf53251b17c9304702d0501", + "dist/2022-01-28/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "d764bee67fb0b03649c3d66d969cbc164d0e3044745dd03df9618cb6fadc18c1", + "dist/2022-01-28/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "b955936e318bc72118a28b90049507b515f252b2cb2e7b13ebdfd0b7e26fa160", + "dist/2022-01-28/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "6f73c34ce381c71f9d4b26eb68180fe4095d6093aa3cefd8247bc1752df9180d", + "dist/2022-01-28/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "ca82c0aa61c59b29f02f5dfd4ca6ef2836d145944b39e24f4d257eef4765ef46", + "dist/2022-01-28/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "a369a6f079274e0e8604616bd911dced66e3557a109aef5d8a2495c657d51f30", + "dist/2022-01-28/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "ce8e9ce1c71ecc704830df274df4eab48c1bb431bc0a2260208e80bd7c9f0ce9", + "dist/2022-01-28/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "8a331a2e9e90260ccd31c8868d321badfc499adf875492c6b3fc89cd6bb30108", + "dist/2022-01-28/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "fb17a241fd1b05c1c63ecf0f2318106f5992fb90eab5c4128186e1f7a232fdcc", + "dist/2022-01-28/rust-std-beta-aarch64-unknown-none.tar.gz": "892fc92ff90f729e1cd72db18c9b33a4a534f960e8ccf25b99e098b9c7bd1fe9", + "dist/2022-01-28/rust-std-beta-aarch64-unknown-none.tar.xz": "f781f4f9c7528860c720ac89a8c883bd9ae0ef515a9110a15588d2ea4ceffaa7", + "dist/2022-01-28/rust-std-beta-arm-linux-androideabi.tar.gz": "1767a44aa4999d4cbbb0f99ee79c02f1afe573e93c9fd8326090fe250ff05c4b", + "dist/2022-01-28/rust-std-beta-arm-linux-androideabi.tar.xz": "bfdef77cb3101b83881069b3cf908f119c1611b547c1620a2e9b06b63e18706c", + "dist/2022-01-28/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "8cb857bc6779224fb9ff3fdbdc21b770814a02a93cbad96c19bd155f007efea5", + "dist/2022-01-28/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "5a708abe835aab411885c13a5d47584b279f5955a971729084f869f0e9f05c14", + "dist/2022-01-28/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "c214aa4109e2b2069c3e739524570d5412475f65741a6eeca3e54fa8cd8486c5", + "dist/2022-01-28/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "6c957c577b75d8b2f1b0f7a8e7b0eae8256bec71c93b7cc69a1231754890cff9", + "dist/2022-01-28/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "14ddf068ecc33aba42de9cab00a52498691564c1c83b4e043024a9b093942533", + "dist/2022-01-28/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "2950de6376f7ee9c05145fbd8143c61a7344fb748f540c835d0523cd645176f0", + "dist/2022-01-28/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "94ca02d2b03e71b9a6515a296a958ceeeb2fa0f3b6f14d46ff455e5adfdbd167", + "dist/2022-01-28/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "7b48e5e497dd82144e2e9d2b718855ddcbacb91c5a7544762d57fc18024b2b5d", + "dist/2022-01-28/rust-std-beta-armebv7r-none-eabi.tar.gz": "afd44d9aee954a7f5c1b744862c7e62ebc4812192deffc06052e4c5f23fbb1b4", + "dist/2022-01-28/rust-std-beta-armebv7r-none-eabi.tar.xz": "2cbcd24628de62d41b18fbf2434104dc8815edcf4d4fc895cf0fdbe91d920ea7", + "dist/2022-01-28/rust-std-beta-armebv7r-none-eabihf.tar.gz": "4dd22c4893a31d58dbdda4c60bca249fb261a49f64c0dd33b93916924b301668", + "dist/2022-01-28/rust-std-beta-armebv7r-none-eabihf.tar.xz": "f51031ffcee2cfc0720a5a39a2fc319df099c829eba0bc9d57758dabad2901c6", + "dist/2022-01-28/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "c5fb7b66c2b4f5cae789895a6670548fc14a71626b4962fcf973191b3408b6e7", + "dist/2022-01-28/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "0ce55128a439376a176e36b96615ff6d595fec18acb3f1e72d97a48fba52d9e1", + "dist/2022-01-28/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "e1ce999a808d0c3046b5aac0abc494b37d15256d91acfc0031f7409e03c37cef", + "dist/2022-01-28/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "8c1990aa82d0cb1081918500967669a3026bbdb14cb72114305253a03e38b89e", + "dist/2022-01-28/rust-std-beta-armv7-linux-androideabi.tar.gz": "0d7ca26d9c90df9657eb01829e8536d2d5493a79ce785eb025e5b09c180a0bbd", + "dist/2022-01-28/rust-std-beta-armv7-linux-androideabi.tar.xz": "89a7e989fbac5b272840635f7deb1d0b65079a1b97e5b055c22306ead886b2dd", + "dist/2022-01-28/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "45746a4f15d418902ba608ca5992f207277f3b591c440839f6c89fdabc4c3330", + "dist/2022-01-28/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "625d0dac58197517630362f993712c0e7706e43be5d5ef36159321ce3cc6b20e", + "dist/2022-01-28/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "aca7527de247595d7c7a240f093d66ffb4e2d11282f1df2fde9531096d4fe9b0", + "dist/2022-01-28/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "0c0e620d4fea01054af6fdf28c8b2f15eac40acd41b0ae0a8ed9520b72d2c5ac", + "dist/2022-01-28/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "084b0f9a065821c2996da457c67ddca54219f39788b22f6b24a4be6c4cad07f7", + "dist/2022-01-28/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "eec6022b0123e24c97a453fbf40eb3a9ee606aa5f797a790f2bde9b2eea2bb5d", + "dist/2022-01-28/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "343fea5dcc3e75db9577d2955e6e1c4bf75aa622f741456d64843d927491ed90", + "dist/2022-01-28/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "37d9a42c59374785f05bb478b0af26e80e212a229720a3f2f59db7157d5a028e", + "dist/2022-01-28/rust-std-beta-armv7a-none-eabi.tar.gz": "f35390f75f201567458b43b76affa4bbc677adb3ebf0e3f07513ca707bbd832d", + "dist/2022-01-28/rust-std-beta-armv7a-none-eabi.tar.xz": "38a2776f222485a7381e35ed4f50a9756f0615e83b1143dffa7a6f1aa47e7001", + "dist/2022-01-28/rust-std-beta-armv7r-none-eabi.tar.gz": "2c3730bc1d7cd878cd9f0070697ae0a64f209b74bd2442afb1ea536b11f92da1", + "dist/2022-01-28/rust-std-beta-armv7r-none-eabi.tar.xz": "0bdd8d03334ff042fa693eaa27afddf1afc670aab89293e5baec57ce9e5c6c57", + "dist/2022-01-28/rust-std-beta-armv7r-none-eabihf.tar.gz": "b1f1088d554a06bc30b5c9bfd2043d952c80f8ff972c824760911dd0fa487a2d", + "dist/2022-01-28/rust-std-beta-armv7r-none-eabihf.tar.xz": "0cc2026f2968ce7f4e262e0899251fb6ee0dc84b49d3d9bd496e00795070d842", + "dist/2022-01-28/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "858c4a3660ef76c3fe792881638e67563c2290d9a81c3b0f49963b252e1e493a", + "dist/2022-01-28/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "10fcf8c290e936a4ff78163d5e0fb9827176a9860578f9352094026e85a81c14", + "dist/2022-01-28/rust-std-beta-i586-pc-windows-msvc.tar.gz": "7d5e5fe1c399e58a889c861864278d2d4641a888be548ae55d3b6734b6490c15", + "dist/2022-01-28/rust-std-beta-i586-pc-windows-msvc.tar.xz": "f53c2713dbeb793e8564fc222c4ec90263eb2a908c938e4e9ca06aff40e24a84", + "dist/2022-01-28/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "0519f54f0f3829e7d0a26dabe0450de23189fd771a33720d71e17ef7017d27e7", + "dist/2022-01-28/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "ab2d89d1be4b2c5076a4d83108ac5785178e2726362a8f76d4d4eabffc016ba7", + "dist/2022-01-28/rust-std-beta-i586-unknown-linux-musl.tar.gz": "873a4c495f57514224fa25a67e4c714b5d37cf760c18aae38bea6b7b8c8f089f", + "dist/2022-01-28/rust-std-beta-i586-unknown-linux-musl.tar.xz": "01bb0327a8f63fe2a42a6af07a743253974fcbfecab3bdd739be58e96e0d0c0c", + "dist/2022-01-28/rust-std-beta-i686-linux-android.tar.gz": "630d53d2eb46c63cd183f5d130af45e2641313d1b1c607c41f7a4a507fca16e4", + "dist/2022-01-28/rust-std-beta-i686-linux-android.tar.xz": "323660e7d58d468ddc33dbbd0fa37621fe78713091ba2ef178d4a8fe01bf81e1", + "dist/2022-01-28/rust-std-beta-i686-pc-windows-gnu.tar.gz": "0d687096fcf757434d07db355f96eddd8e07a90d952d123f2af30a0f63dffaf4", + "dist/2022-01-28/rust-std-beta-i686-pc-windows-gnu.tar.xz": "22fb93f31abf9f7d9e4cdfd5a7ddd03705ecc48db22d7a4ebd58e421891fb998", + "dist/2022-01-28/rust-std-beta-i686-pc-windows-msvc.tar.gz": "1c644591da0698df4a40977c9db8a00a002c1a34cb828a4038c5c17d1a3aae58", + "dist/2022-01-28/rust-std-beta-i686-pc-windows-msvc.tar.xz": "e0220fd4ee5f36b29f605f9a8bcdea1bd7721c40787b59e1fb63915e5da0668f", + "dist/2022-01-28/rust-std-beta-i686-unknown-freebsd.tar.gz": "eb9faa1d7492d92cffec3495937c7682e3c578d9c6ac5d9074efea0d1097d63b", + "dist/2022-01-28/rust-std-beta-i686-unknown-freebsd.tar.xz": "10732369b289fc92ea0566cbf8494fa267ac551e682921f1824d76b70170d73c", + "dist/2022-01-28/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "355c6c1178d34e687a071081dddd093a1d6edd3e93cd73aac46f425797c6c541", + "dist/2022-01-28/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "4904406365f855ed10cf113f04cbeaaf29842789afb91d84396ba3953125d873", + "dist/2022-01-28/rust-std-beta-i686-unknown-linux-musl.tar.gz": "832737bfc8c70f07a8463d1db39f260829de67dc8c588cf11170f2dcb2b0dc28", + "dist/2022-01-28/rust-std-beta-i686-unknown-linux-musl.tar.xz": "8220b586c8cbe913db4d00699f7821fdf40ca8da85faf4fbfc84ae56916460e9", + "dist/2022-01-28/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "82939695d5bfe904481e3858e2d203d56f0877683ebfb33326ab9d0699ff2c5f", + "dist/2022-01-28/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "f337c7caee2e964926801811a282e4f18f4e196521ddfa81417ff6dca46927c4", + "dist/2022-01-28/rust-std-beta-mips-unknown-linux-musl.tar.gz": "e7256b993f54fc5b7aa68c8aa5e5f1294d82681f0b8b38c7f7ed6e1d57064af4", + "dist/2022-01-28/rust-std-beta-mips-unknown-linux-musl.tar.xz": "00bf1b30ac924ca221569fb2febf34593ca435540163d12ec4e433a7406c2819", + "dist/2022-01-28/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "6d2c2d9b82d95d808a23e99e0f9b828d9087fe82efeabce200ea7634636857da", + "dist/2022-01-28/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "e504cbcda58085ad283dcccf4aa5160a117aeef01f4017ffb4350a6e3b18113f", + "dist/2022-01-28/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "c382edfa08997d2c5d400ca9c93eee9457fdabf157da2306187af68a11cd3705", + "dist/2022-01-28/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "616d4daf1ed58c7718a204da636d96597d184ecdc71b414a9b20e5fef710c078", + "dist/2022-01-28/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "5d24d7be185cb8fb8bdb1a89a63be323491284d2e9bb191104ef59a547e3899e", + "dist/2022-01-28/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "c055f2f3d77354a9d03276f7af8221e3c8a337b11198143a31b6b654e8bc4f28", + "dist/2022-01-28/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "ae730a78c7382af9c16f0b4bc157f339bf8befced1748b955e29e0db751cd5cb", + "dist/2022-01-28/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "18f02642733d06bfad35e6d383e6634a22c79dfc56f6b6f1976a5bf71ca36478", + "dist/2022-01-28/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "cf162ecf50f6edddff265f5e051719f8c15c730f3826cecff3477d5c63f3f28b", + "dist/2022-01-28/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "f82bf7eac361cfd2b255c3eb1f2ba4e6349fe5f88d6e6e9edee0aa7e9ae4e721", + "dist/2022-01-28/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "30e48dc0b5c8cfb1d3fd18e06ca19f7136aae366cc9e2b142999d8a0430e3513", + "dist/2022-01-28/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "7db67dfd175d398f4e922be87002cee22e7badc661ab3ee4aba7c7e9673ecf0e", + "dist/2022-01-28/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "d72d9066354bf5f2daddd8ca00f2221c897142e68b7e8343c6c965e5537ccb10", + "dist/2022-01-28/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "eb5f848052e0ab07de8aec5f767d6d4413da0c135ce02e766d125da5850a585f", + "dist/2022-01-28/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "6cf15da4eee99e1b89f2306ffebebce537543f08ef36f3a8aad38b0202bf1378", + "dist/2022-01-28/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "b35d2296994172b05ffd0bb3bb59cddc007ad93cc089aeb1f8b4a2d7a1d716d4", + "dist/2022-01-28/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "819327e4a040bea527712ac2d935b2db9539262a9e552450144b9829038db48f", + "dist/2022-01-28/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "68cd8c861a62931feae04eef5a3ecbb9bdd97433d082cae060e005f1da6523f5", + "dist/2022-01-28/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "fc1459aa99a44895a0631a35cadd7c8683b7570fe0a743e0bdc7f397936a377a", + "dist/2022-01-28/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "702b008b7390df74ed639b99133abbc5c0441c002d4d99594c9c56f46e13e518", + "dist/2022-01-28/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "45dea87501465e6ec421f7a9a6a364fb4bbe7f6e6c00aef16bd66b58a204ed18", + "dist/2022-01-28/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "f7d5178e5b2514e52336dd3d4dd7ebe7f452e6427ff578d19f955d611625c2ac", + "dist/2022-01-28/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "9c7b727799288d289f7569823b4f75c691d42a2c25066f742e74efcb1e9e7c31", + "dist/2022-01-28/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "536397a308e268b30a6bd1a2a869ade61e0d048aba76b9787b130c5d8ede7d12", + "dist/2022-01-28/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "21397afe74f4a3611e91c4e9efede79d3cf982a13d1b864c878be7d3436e3129", + "dist/2022-01-28/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "3c61d50eb15c56087ab9f9cfe765586a2fbcdff93d60740a75bb435dcd18619f", + "dist/2022-01-28/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "7f654430af17b09cd974e35f6c99b1ff88fad706e659fe9d48ed9cb765722278", + "dist/2022-01-28/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "9d7ee3d8dd1e93c754e2991f656acc2a03e88b9ee2deaa865c83fabe05aa5618", + "dist/2022-01-28/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "47ea53de8215c251bb206f81ff6e8ad2d632e9f74e793d36db00d8329e7f4dea", + "dist/2022-01-28/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "56c033b71340b5379a59dfc0219bb5350a3e95aa22983c0bbfe1cad6b347718c", + "dist/2022-01-28/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "3902efc5f212d815a77d39211a7ad662c2826857bde89ec7c0f6411745531e6a", + "dist/2022-01-28/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "f9631edc7899d7f71230483caff7215a423b4ced12a963e41dc0e268301c4565", + "dist/2022-01-28/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "e1006abf94a35dc9eed587cde1eef3bf35ce0e685f4040176c2460df4ef71f69", + "dist/2022-01-28/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "34f5901fef0845b5da92f3a49a20d533b6bcdb77cbfd9d8432eac8aa47b28675", + "dist/2022-01-28/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "d3a63e5ba55d291045562d95d27cfaa6f116ecc72ebba39ff97ee8e960030de1", + "dist/2022-01-28/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "f9b7b16aa77ac7ca1e8384d74c5cfcb66626cc57eede7aff1da4cdb7ac13942d", + "dist/2022-01-28/rust-std-beta-sparcv9-sun-solaris.tar.gz": "9af8b18ab6089bb2e06ea33a17a44ee98cd0ac3c54b688f5848d4cd141ff2389", + "dist/2022-01-28/rust-std-beta-sparcv9-sun-solaris.tar.xz": "1809d88ac573ea265f3d21d4142d0176ba9ab51e789911825a9d72ca917ddfd1", + "dist/2022-01-28/rust-std-beta-thumbv6m-none-eabi.tar.gz": "5a1aeb44ca3b92a37eced85edf374d2ffe17ba6f6da748580baaf3af1c3a8a36", + "dist/2022-01-28/rust-std-beta-thumbv6m-none-eabi.tar.xz": "7d3cdc3b7b3d9d47aa0d1d6de4fc5f520ee99c52b4678fc3987823efe4e1ca98", + "dist/2022-01-28/rust-std-beta-thumbv7em-none-eabi.tar.gz": "a950ffaf7228864eb2fd9570bb86a5544f89f8293a3e96f794d36eaa7e9f8825", + "dist/2022-01-28/rust-std-beta-thumbv7em-none-eabi.tar.xz": "527be16c3474ab25c3ac56aab6278a3d4f1b535bee0c226dbf63e52f5ea2acf7", + "dist/2022-01-28/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "fc864b408f7d8688733b260b7ca2f476f148a0c04cef15b4b99348fb59627ce9", + "dist/2022-01-28/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "3a966b6343c75933d00ead88f54e797aa81abc1b521902d15c22d44791b33e71", + "dist/2022-01-28/rust-std-beta-thumbv7m-none-eabi.tar.gz": "4ab03955b4b787f5d2b1096e03aa4b0948a2a53562107ef6f9cf0ae122668b86", + "dist/2022-01-28/rust-std-beta-thumbv7m-none-eabi.tar.xz": "2c0e443dcda563ff4cad6285ea648797bca6ce828bfed66f3b868fa386a0a693", + "dist/2022-01-28/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "831e7af7924d20ba5289a67d6f0d55942f624ad1abb997a90e05fe303c442870", + "dist/2022-01-28/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "e99648317cc93eb4e3e807dc85b28bc6336136750caa9ae000a8041e93d1a9e1", + "dist/2022-01-28/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "37db1b82732ee477e4bd8f1d430ca0f7b50f9699285188cc4c55efc024c760f3", + "dist/2022-01-28/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "5dfd285234f1f9da127b7ae7f823facac9f6f281713b5502268ff75668ae8a6e", + "dist/2022-01-28/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "22c21d88398dcc6dff166270e455e6a4be8bc06b1932f4138ce8c931e3a900f6", + "dist/2022-01-28/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "2eb7e4dbd9984ca60746af13c631871c3d872b95239c422d135de2bda203707a", + "dist/2022-01-28/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "97e6b0834227d725660d6f9729b198ddb70ba238640f2a43de4568230ac7bf5d", + "dist/2022-01-28/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "e9b06591f4769bed69b6be6647deded3991125c0a5bec5486126e6572707fd7c", + "dist/2022-01-28/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "6afa229d0a1159f853a13f0ea36c4dcb8bf964bd699ecafc57539a1391861591", + "dist/2022-01-28/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "5811a551c8c19b09f6928aeaa655c69f32657775b9149e4fa37a5003be15faec", + "dist/2022-01-28/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "522e98515cbedd4b75cd2a3151d16517d71d8078005c3a1133e6e222dad163a1", + "dist/2022-01-28/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "2654caa437d1f1871db5400652287597bec88eb366e099b03d7cca70367d3722", + "dist/2022-01-28/rust-std-beta-wasm32-unknown-unknown.tar.gz": "c18dfcedf25851f446271979b868bcd8dbdad2ca2a4762f3594385d65811d449", + "dist/2022-01-28/rust-std-beta-wasm32-unknown-unknown.tar.xz": "0dc5da1073e3df2899909045c33c4aceb9b159faf7a20c2e32affca7e7587554", + "dist/2022-01-28/rust-std-beta-wasm32-wasi.tar.gz": "e6e03121c99326cb56bb3a6f6eb352cadfcc487b20f5a7e1b95c5c7f1c97feb0", + "dist/2022-01-28/rust-std-beta-wasm32-wasi.tar.xz": "8cf642cc54d22908a3db701a1beb13aa43143857596f4965261cdfa35812cfeb", + "dist/2022-01-28/rust-std-beta-x86_64-apple-darwin.tar.gz": "e3065e70fcea7f03ce4ae41742bc6540ee2e0df50501d8ed81215d0ca4c63f9d", + "dist/2022-01-28/rust-std-beta-x86_64-apple-darwin.tar.xz": "e5e683cc14760ab0f94c4f02b721e3cb2c0c780ab68e63c971de70355c30d2cb", + "dist/2022-01-28/rust-std-beta-x86_64-apple-ios.tar.gz": "b31791d217e4868caf88fa4c96c3476a4c65bb8ab59e8846f7e2f4f003be7cc9", + "dist/2022-01-28/rust-std-beta-x86_64-apple-ios.tar.xz": "24dd9d59c9ecfd0c7a56143a9e0368b077d61ac7d9c56cb940e8b195fb5ccde8", + "dist/2022-01-28/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "15bad901b51a039c70dda2379eb1cbfb7098ed00415924ad19fb9318f176d34f", + "dist/2022-01-28/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "6fd144e0d7cf510f5df11798d9e8f2faeee52d9dd5134fdfb90fac2adb9c1d21", + "dist/2022-01-28/rust-std-beta-x86_64-fuchsia.tar.gz": "f22276c2c07074dd8f3634f95eb4422ca1a2ddb89e22e05450c77e59676445f9", + "dist/2022-01-28/rust-std-beta-x86_64-fuchsia.tar.xz": "fa745d421e36d9255da6e69ae4adf968910200f99394a8ca88aa2917b0931758", + "dist/2022-01-28/rust-std-beta-x86_64-linux-android.tar.gz": "b6924656e61295d96c5c792cd482435248867a846000d232f8895b983f2fd68a", + "dist/2022-01-28/rust-std-beta-x86_64-linux-android.tar.xz": "58b981335322b7f5f11ecf71411b9b7fe045d160fb99b1f8a452d0d833926461", + "dist/2022-01-28/rust-std-beta-x86_64-pc-solaris.tar.gz": "559721b2bf60bbd7688b8aeeccdd3d6c92eee2eaf29082f42ec53689f2fddb92", + "dist/2022-01-28/rust-std-beta-x86_64-pc-solaris.tar.xz": "c6341953f2a9d11159e3bf398b90cf9e76af4b6af7cd6d828b22661bc4f3fc5c", + "dist/2022-01-28/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "59b91baee1eeee88c78b55ac3a32ce1cdf59107715a3db7c3476843ea981b70c", + "dist/2022-01-28/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "2f7bd143bb9f40a06e69b5f9908ab14e364db254918dd1c984c272a853a56f0b", + "dist/2022-01-28/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "1258d1207468450556a0a265342e5155474a7f87e8c33b5233c72a959b13421c", + "dist/2022-01-28/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "907d14ff6bb742f2bf12f4b51054c8c6bb128cdaee957918e4fdeda61ac18c53", + "dist/2022-01-28/rust-std-beta-x86_64-sun-solaris.tar.gz": "ca0cef7d3497ae9714537bbdd2469b48afb20ba1dfecf03d680e801871a3ec97", + "dist/2022-01-28/rust-std-beta-x86_64-sun-solaris.tar.xz": "73eaceff8046cdb76ccb7a6739f01dfff5b740ffdf5366067e92814be5ff97a0", + "dist/2022-01-28/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "bb8671bf78ee0c8840d453af9ca0d337c167d69c293e4710d6aac2d19c3a044b", + "dist/2022-01-28/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "87cdacf1caa7fb3656be04fb3b37f21541b2e8eed214bb5822c0723fe9f23067", + "dist/2022-01-28/rust-std-beta-x86_64-unknown-illumos.tar.gz": "7dd006b93c449864bc3c6e024e0f0903db1c422b6bccb1bd1ee8187fcbb4e3d4", + "dist/2022-01-28/rust-std-beta-x86_64-unknown-illumos.tar.xz": "7d77712a5d07578e2f9947ef11ced00a84b22d3075f747781b6c0e0483bd7fc8", + "dist/2022-01-28/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "5f6fb2124a40f0a7ed2631b59f67762d701c9fd8ede051dc922d99ac6fe29c97", + "dist/2022-01-28/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "e00f0da85fb8378dac3ae76f235f54cca568680d4208fed065143e1ecde1b87d", + "dist/2022-01-28/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "d2d0222ba528a42d8804423c15cac59a5c37e36b76248605dfcf9d732cceb1de", + "dist/2022-01-28/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "d2c8cf8510369513fd79107bd450df429a97f5bfbc59ef8a7fea5fbd75462a65", + "dist/2022-01-28/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "a7934e15342434f242ea7eb9c9c853a984f70befaf1cf2266cc5a198233a2337", + "dist/2022-01-28/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "bc5de5c3df04aa3aaf4866e432b3b50dafaf790345587eaf066334f7f52ff34a", + "dist/2022-01-28/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "9827751229decaf827c8bbbbeebe868c86d7002a82d776f0ecf310d539eb285b", + "dist/2022-01-28/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "88d41e6fa0d290fd39470f824045abdf3557e0028ae877c9c4081231531dc8cd", + "dist/2022-01-28/rust-std-beta-x86_64-unknown-redox.tar.gz": "5b1c8bed24c4bee0cfffbf54029e39673545a314102be2281018f8bbd05a9d17", + "dist/2022-01-28/rust-std-beta-x86_64-unknown-redox.tar.xz": "3bc2a98b43bda5080734ba0ad1235e72a3e12e3bbb5c603193aae3a18feeee1c", + "dist/2022-01-28/rustc-beta-aarch64-apple-darwin.tar.gz": "be36422d10d4dcbc618eec2dc33ebd62c16e366a0bcf8a4a3b9ddf5bfe236bf2", + "dist/2022-01-28/rustc-beta-aarch64-apple-darwin.tar.xz": "cf6e5b5475733dc71f68c8d8b08556d410c3f2bc87813565cb9a69d0984fdf48", + "dist/2022-01-28/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "c2eff28806e697087a39da7922ede30b937110d1e492ab839644c695c02ea467", + "dist/2022-01-28/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "ea9fda833ade80ef87afcf3cfdc0ace851c01b66b00701d70722ba9aab1c9d0f", + "dist/2022-01-28/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "e9e37df47dfb3bcbae3110e0b372ae661aff82d5e6a6837deff78978a85dd2f3", + "dist/2022-01-28/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "f11adc9a47432ab4ecd0e95c8fbde21c493dcac730ac9bcc924e096eacce6b94", + "dist/2022-01-28/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "6279fd872148c28c0684d7dbfd6e96838fff8acbec83c45e235e85f3d68802de", + "dist/2022-01-28/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "c969e5c760dda90fe23cf8df764601c38ada25a2d7bed0d497f31701c7bcc62d", + "dist/2022-01-28/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "d4025f62b09f94d5c464fa6bb614186e9968c6b34f5a12544ee35323426eae19", + "dist/2022-01-28/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "992d055af2f888d2c61e5aa1670ef40a8bf7ac761cf6ecf76d7a8d13b3eb9a0c", + "dist/2022-01-28/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "ab153065e0db468cdcab3a3a251d0f80a7d94940f3455db419b3a3ae5bffb651", + "dist/2022-01-28/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "2501ad4358112e7acc736f9820d6f822bd985acd577e56c124573082a8e26cec", + "dist/2022-01-28/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "3e145f4111fc7835949b6ba34d0ed7a58605166cfcde22d96d2e8dad3f8c65ff", + "dist/2022-01-28/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "948f13b6f988072c707cf8c730abf970d6b47d4fb6044d4f6b615b48c21369c1", + "dist/2022-01-28/rustc-beta-i686-pc-windows-gnu.tar.gz": "997ba934c0bc912df01906b547f240f4cf7036300cd34ff341e72b69502b1cab", + "dist/2022-01-28/rustc-beta-i686-pc-windows-gnu.tar.xz": "c0ef12248f08da0f88629e55ab805b637289e7a29a92bdec5cdbf138df272baf", + "dist/2022-01-28/rustc-beta-i686-pc-windows-msvc.tar.gz": "94e6df381784d4f7bd9c8cbff39fe3066d636c64257093563f84a59ee84b686b", + "dist/2022-01-28/rustc-beta-i686-pc-windows-msvc.tar.xz": "ce392e7c1942f3267b029faa1f06a4162c3a21316ad819fa218a0ddbd9993b79", + "dist/2022-01-28/rustc-beta-i686-unknown-linux-gnu.tar.gz": "0809b22fc64166ed66a32090c3af49bf3b1515d9aa37958d1bf4d8edeef67bac", + "dist/2022-01-28/rustc-beta-i686-unknown-linux-gnu.tar.xz": "6a24a429d45b5558ebf069b0ea730a8b2c0f8cb8e8247d3e50739b5c6a06f45c", + "dist/2022-01-28/rustc-beta-mips-unknown-linux-gnu.tar.gz": "af3ff96546ae18359f529f35430c4faec41e411357a74e420b5eb6e939e56f9d", + "dist/2022-01-28/rustc-beta-mips-unknown-linux-gnu.tar.xz": "40e578de34500ac7bfd1513187894787b9a2a13e1cffbfb4a3fc04779e8f564e", + "dist/2022-01-28/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "9b4eeabf21940541791b768db2995c2fcd0f3aa4077f741df941892e65c03e1a", + "dist/2022-01-28/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "15940aaeb1da2bd7c3a5f4a3a76c90018a5d38bb933fa516b9833d3b5c9bc465", + "dist/2022-01-28/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "e2d93d8ab7f3a43be6bed773a5afc1ce0b43c15ddb6390a34facb920dcac6980", + "dist/2022-01-28/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "1ce438ec11c7d5912a348bd08fd9a81cd77e7ae9b221ded4473dd203fa5507e7", + "dist/2022-01-28/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "537928c967794a4b0b6fb3c6df138aafec1c26a5bc608089cba5b2ee2fb3679c", + "dist/2022-01-28/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "1ac3144f0ed01c686adb813e5f59ba9f07522161269928d852abf886f8beaa8f", + "dist/2022-01-28/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "23d6bddd60b9615b9b2dcc711587eb73022905f4f84db0b85433fb018db9fa90", + "dist/2022-01-28/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "172bf1d122830c06caae2879b0f175829938a6a043c39fba39ae2684632cec8f", + "dist/2022-01-28/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "df0f58797083a0fb07072237932d6ef30035df227f347976e766dfba0b4d16c7", + "dist/2022-01-28/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "951a378b2bd9e8dd60cc5813664c6a7b020e256b5efe88dc9ffc776c9bb9aa5f", + "dist/2022-01-28/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "93fb7cd91ff9e530d6eae0496d6456aa48cb6a7e81dc118d40fa5db84324e0ef", + "dist/2022-01-28/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "e0facee99193bcc891feb961a2eded35b4bd40f80b5fff977fcc48f7e7b26b84", + "dist/2022-01-28/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "d6c9a1014fe73d03ba7fe5248e84fba7abe46b96f61cc45a8972d0c85f577cc4", + "dist/2022-01-28/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "1f9f65bd07e075d4c7065d860ffa09441210a220abc4f6c0302de1cba4b56ebc", + "dist/2022-01-28/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "0f73fe2bda02e6b9e0f17b8907571d11c622df6b9349ecb60b8d28fab0090f45", + "dist/2022-01-28/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "8b1b8cb25ab0a00213b4272390175d91b486cb08e45425f52a8ee1104bc11efe", + "dist/2022-01-28/rustc-beta-x86_64-apple-darwin.tar.gz": "a6fa895d1debcbce04c68c64fac8ddf875f6c4e8d7298ec4e46e79cb702e103a", + "dist/2022-01-28/rustc-beta-x86_64-apple-darwin.tar.xz": "a0dc92f6a544b215f1b8cf71dc21fb26423883baa24c551c96c250bf05b21c99", + "dist/2022-01-28/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "867038c72a56f889420bba6f1946ea560a328a79dd54b70caa8d7ae83712ad54", + "dist/2022-01-28/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "a59d3409f4ca6f534608f5fe709ec6442e253f8d9400b9169814c5273765bb72", + "dist/2022-01-28/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "e07ee24da341ae8fb8fe55f895ca5fdbedfc392454906396c61d79f1f5cac631", + "dist/2022-01-28/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "668aa9303bf8a90c90167b6ca4a9a8a885d5ba21bcbacc379c3ce9b5c1a2f7d7", + "dist/2022-01-28/rustc-beta-x86_64-unknown-freebsd.tar.gz": "5e9b6a14feaf665839070f20a795ce2ed1c11824a56264fb35de5e894f7e2c13", + "dist/2022-01-28/rustc-beta-x86_64-unknown-freebsd.tar.xz": "3506fc1b57f8da75e93f48d00c49f4d0cdf61b459955449a87d1a7fc051c40dd", + "dist/2022-01-28/rustc-beta-x86_64-unknown-illumos.tar.gz": "b30f734100da20382605a98a70d3b6c34febdb11e105fc1a1639ab7b1338545f", + "dist/2022-01-28/rustc-beta-x86_64-unknown-illumos.tar.xz": "0b1ca988d1e25423d49f92acb123e8f91ca6772418d2bf4411e4fc1387410c5b", + "dist/2022-01-28/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "9320b51f221d9f875a98455fee8494d09318aa0aa90946e1fc03b73173738bb8", + "dist/2022-01-28/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "374ba55f3b7d1c6dfaa3385e7b033612335eaf01fa0d06eaeab95cc00503617b", + "dist/2022-01-28/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "556428fed3c5b92e001fa9b762915583004e0e3384d1eb17d08bdbb07eff1a91", + "dist/2022-01-28/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "5122a66d96e89e7f31e04604792cd26f7cf687d007d839732ad8ec3c32546014", + "dist/2022-01-28/rustc-beta-x86_64-unknown-netbsd.tar.gz": "689e0892a575b507032bf4948319fb0706f3d58da7ac55c40560edfb85fb617b", + "dist/2022-01-28/rustc-beta-x86_64-unknown-netbsd.tar.xz": "8b1fda9cb3779af899b6988225a4d89a4b3b5f5ab696c0178c82ea5730f4503d", + "dist/2022-01-28/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "d10e91d44175ed8841bfaa0ac36641e5b5fd9f562a69634e1dc8e74937f6b910", + "dist/2022-01-28/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "26ddf37786bf057527b1ef72580b09f5ab2954046699e5ea8d773ff833d938c8", + "dist/2022-01-28/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "59482a7e368c63812aec689c9b9575c267273c1e2096bcc5a1bb0e4fe87f9703", + "dist/2022-01-28/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "b7aae7502c13cff81125b8960b06eb808b1ad51fecc311f7cfb02b5aeed8a0d9", + "dist/2022-01-28/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "28dcc5231402b7c71d0a741878ff0c64fcd37537889f0a0ab5e04fdb2001c3c5", + "dist/2022-01-28/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "24d0e5ef0a8b5c7359243a0ed06801281782ba2fe4ee315ebcc53ce78e84d338", + "dist/2022-01-28/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "4f7ed5c1e05a7e903bcbcdccae8da1f296ec182f56c4bd29c38cdee2c022b20a", + "dist/2022-01-28/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "c5bbefb41d4ca4f376431d64fb15e250d5dedb8d4ff220f19532fbf7c24fb627", + "dist/2022-01-28/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "ccb65098e45ead43ef62b4b0b10dd552d4cf23786b9639ac665612d458c4eea1", + "dist/2022-01-28/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "5674d7e984b0fbb51e927d991296411cf0da46465eaaf86a58b2ba81d801cc92", + "dist/2022-01-28/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "a6f868aa17cf4c8734f800451f33bc55d38bf6fe4d658714f469416b86fdf911", + "dist/2022-01-28/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "acf5681ce5f75bd807aeb23964958d77b5c77a3cabe51d102aeab22c99bd1d24", + "dist/2022-01-28/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "e973affc0149d03981875496ae8aea5d7eb5b5a8fcf42380589a3c5f49e7f9f3", + "dist/2022-01-28/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "7a00e48bae6d388c0514537429d17b31a316ffddc1bd3d2c6651babec8d2787d", + "dist/2022-01-28/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "e3169c339cd6cd1a9355c4f55281f32ab78e60ccad46129b1848135cdbab1f25", + "dist/2022-01-28/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "0ae17e2d2ad1a03de08f8462c462888e6c72e36d9d7e4737e85ad9890eff3a4e", + "dist/2022-01-28/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "c884249be750942fb19da009dabc296438be4e25c872b548c7cd501135367030", + "dist/2022-01-28/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "8b92f8cf72c3289d4be864dd44ce230ff3098f52b16215464f34451dd16f4b9e", + "dist/2022-01-28/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "31e97a0e6b1078a2bd78ac92c5861ad5a6dd91c4f819c69e2c07e3941ab893d7", + "dist/2022-01-28/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "d36fbd52792645198dd0d2b8fd7b5389931e101313ed0c3793370120a58f5ff6", + "dist/2022-01-28/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "b3384f0e386aa2b77def7cb36906a3fdbc4ada92fab50deb923561cf6043b98a", + "dist/2022-01-28/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "f728634605fd782ca173c6be41c4ab9eac5b036419e2d33513d1cae197367834", + "dist/2022-01-28/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "07404280a97ac98597ced7de15856dc05b855123058984aac3f0b2ab896bccf7", + "dist/2022-01-28/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "02de9fa0ee4334af980cd25a4bd467ffbc275ee0871224b84f9549c23f922bc1", + "dist/2022-01-28/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "81bfb88af8c591d32508986d7ff96261b0d84eacb8303f614fcae9095a25fbdb", + "dist/2022-01-28/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "e7bff69f544d999c4b2c27071c049dc092df47431e658a9a8f07c7e2cc08c8d4", + "dist/2022-01-28/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "d1d7081173f89fdd287f6b5010ab5787198c504cba5de4bf54f8473777e20bfa", + "dist/2022-01-28/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "d77625ec03a2e0101fcb743c440dd8e21fdafbd04bb652ee4db6c365e0e0ad49", + "dist/2022-01-28/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "80143957513b49c7d3f4e113e86a9181cda78f2b928f765b3f4060fbd9bf44f7", + "dist/2022-01-28/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "7d9ad14154b99fe9e82e6fd59884b9bc1c3d379c16c376f990dda859d3b86fdf", + "dist/2022-01-28/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "897629dc734984e2ff984fd911f6b02fb8d3d9e4ac70bb209981226d27800392", + "dist/2022-01-28/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "9bf72e0f71a81f2afb66ecb5bc242b349d92e8b9f51249f52de172e12281fcfd", + "dist/2022-01-28/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "89893ed9bd3c2ec611d54d44aac79379db78dd1c4994747e5a6e55cb779a1d1e", + "dist/2022-01-28/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "f7b8ca2f4afcabc178f166161c0c006fe0b8eb16455fa8a2fe7d8429718d65b3", + "dist/2022-01-28/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "90aafc241355240df41729288bcd61aeb61c792528570f643f5e9fe34a33ccc6", + "dist/2022-01-28/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "7018db141ad7b1960640245034efc233a267b05cc412a7969ccb26d87b46c49d", + "dist/2022-01-28/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "b986c3ecf6d5e6683f44efbc24ccb1486e42514c695e3401082c396caf26a69d", + "dist/2022-01-28/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "8c4d895c603bb875f24fadef68f0b19b5c390640ee170dcf41bdba07d79a4f03", + "dist/2022-01-28/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "7c95e4d7c161eea4af6f59f6ff69829eba791dae1fe18cd2a18a5b2c1fb1190d", + "dist/2022-01-28/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "51f32b5abbaefb3590cc174c909ea2b80cb15fc1c2cd6c60e749035d9899c5dc", + "dist/2022-01-28/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "aaff3042d48acefad9fd012a7c44148e6503dce61c2eedbd06d025d35d086ff6", + "dist/2022-01-28/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "8811d63c78d7b3bd6ee4b7b735fbce58cb13783d1d12b16c6cd584f518934a4b", + "dist/2022-01-28/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "7d526137c7437d9d2bdfa8e87790b038b053805e9528a8b8b9c6827d5d0ce64e", + "dist/2022-01-28/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "84c8c33267286b65acbb8c1a692d410ee49ebfec708cd3cf35013b76c87ec292", + "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "4e52381a3c7acd8435bfcdd45de3a238916985dc7c746615847381b7c2f3fab0", + "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "4979e2ca9e1bb42635b0d633b26dcd9d9265698bbe10320daf464243a803d100", + "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "aea87359d72f23a27bee9763074301d4e4c85c5e91cc1c18c16c8477b52ff9c2", + "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "6bcf6b03d018964d63c20782d01f8fa832f5f22a8eb719d59c93fc18510804a5", + "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "651db4ab2e12f46771ca41f1344d145d8163d5fa02b974b0ad07fe011219040c", + "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "d774f9b51f5a25b32b37b933c898eaa420d51a7ccf0277d1b980ba69a128db59", + "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "39c5c15b939ca8d41af51945e4c9aea6a8011564bfac8e71dee7141a237e7499", + "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "3fd188964c03825728fd6691210a44c715651010305436056977b15a03989b75", + "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "835877a13df7d811f5cf6f5d983a43be03a7cf831a0135900e484c1c6cb2da33", + "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "616f16ce1e5c4b50a7bc19550886cab1b861d0b925a7fab4b4d73a37e40552ed" } } diff --git a/src/test/assembly/asm/msp430-types.rs b/src/test/assembly/asm/msp430-types.rs new file mode 100644 index 00000000000..6cfb86e276e --- /dev/null +++ b/src/test/assembly/asm/msp430-types.rs @@ -0,0 +1,158 @@ +// min-llvm-version: 13.0 +// assembly-output: emit-asm +// compile-flags: --target msp430-none-elf +// needs-llvm-components: msp430 + +#![feature(no_core, lang_items, rustc_attrs, asm_sym, asm_experimental_arch, asm_const)] +#![crate_type = "rlib"] +#![no_core] +#![allow(non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const i16; + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for i64 {} +impl Copy for ptr {} + +macro_rules! check { + ($func:ident $ty:ident $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!("mov {}, {}", lateout($class) y, in($class) x); + y + } + }; +} + +macro_rules! checkb { + ($func:ident $ty:ident $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!("mov.b {}, {}", lateout($class) y, in($class) x); + y + } + }; +} + +macro_rules! check_reg { + ($func:ident $ty:ident $reg:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!("mov ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +macro_rules! check_regb { + ($func:ident $ty:ident $reg:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!("mov.b ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +extern "C" { + fn extern_func(); + static extern_static: i8; +} + +// CHECK-LABEL: sym_fn +// CHECK: ;APP +// CHECK: call extern_func +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("call {}", sym extern_func); +} + +// CHECK-LABEL: sym_static +// CHECK: ;APP +// CHECK: mov.b extern_static, r{{[0-9]+}} +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn sym_static() -> i8 { + let y; + asm!("mov.b {1}, {0}", lateout(reg) y, sym extern_static); + y +} + +// CHECK-LABEL: add_const: +// CHECK: ;APP +// CHECK: add.b #5, r{{[0-9]+}} +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn add_const() -> i8 { + let y; + asm!("add.b #{number}, {}", out(reg) y, number = const 5); + y +} + +// CHECK-LABEL: mov_postincrement: +// CHECK: ;APP +// CHECK: mov @r5+, r{{[0-9]+}} +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn mov_postincrement(mut x: *const i16) -> (i16, *const i16) { + let y; + asm!("mov @r5+, {0}", out(reg) y, inlateout("r5") x); + (y, x) +} + +// CHECK-LABEL: reg_i8: +// CHECK: ;APP +// CHECK: mov r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: ;NO_APP +check!(reg_i8 i8 reg); + +// CHECK-LABEL: reg_i16: +// CHECK: ;APP +// CHECK: mov r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: ;NO_APP +check!(reg_i16 i16 reg); + +// CHECK-LABEL: reg_i8b: +// CHECK: ;APP +// CHECK: mov.b r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: ;NO_APP +checkb!(reg_i8b i8 reg); + +// CHECK-LABEL: r5_i8: +// CHECK: ;APP +// CHECK: mov r5, r5 +// CHECK: ;NO_APP +check_reg!(r5_i8 i8 "r5"); + +// CHECK-LABEL: r5_i16: +// CHECK: ;APP +// CHECK: mov r5, r5 +// CHECK: ;NO_APP +check_reg!(r5_i16 i16 "r5"); + +// CHECK-LABEL: r5_i8b: +// CHECK: ;APP +// CHECK: mov.b r5, r5 +// CHECK: ;NO_APP +check_regb!(r5_i8b i8 "r5"); diff --git a/src/test/codegen/naked-functions.rs b/src/test/codegen/naked-functions.rs index c8cd6923282..51c7a0c615d 100644 --- a/src/test/codegen/naked-functions.rs +++ b/src/test/codegen/naked-functions.rs @@ -1,42 +1,32 @@ // compile-flags: -C no-prepopulate-passes +// needs-asm-support +// only-x86_64 #![crate_type = "lib"] #![feature(naked_functions)] +use std::arch::asm; // CHECK: Function Attrs: naked // CHECK-NEXT: define{{.*}}void @naked_empty() #[no_mangle] #[naked] -pub fn naked_empty() { +pub unsafe extern "C" fn naked_empty() { // CHECK-NEXT: {{.+}}: - // CHECK-NEXT: ret void + // CHECK-NEXT: call void asm + // CHECK-NEXT: unreachable + asm!("ret", + options(noreturn)); } // CHECK: Function Attrs: naked +// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_args_and_return(i64 %a, i64 %b) #[no_mangle] #[naked] -// CHECK-NEXT: define{{.*}}void @naked_with_args(i{{[0-9]+( %a)?}}) -pub fn naked_with_args(a: isize) { +pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { // CHECK-NEXT: {{.+}}: - // CHECK: ret void -} - -// CHECK: Function Attrs: naked -// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_return() -#[no_mangle] -#[naked] -pub fn naked_with_return() -> isize { - // CHECK-NEXT: {{.+}}: - // CHECK-NEXT: ret i{{[0-9]+}} 0 - 0 -} - -// CHECK: Function Attrs: naked -// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+( %a)?}}) -#[no_mangle] -#[naked] -pub fn naked_with_args_and_return(a: isize) -> isize { - // CHECK-NEXT: {{.+}}: - // CHECK: ret i{{[0-9]+}} 0 - 0 + // CHECK-NEXT: call void asm + // CHECK-NEXT: unreachable + asm!("lea rax, [rdi + rsi]", + "ret", + options(noreturn)); } diff --git a/src/test/codegen/naked-noinline.rs b/src/test/codegen/naked-noinline.rs index e34ccf5c5fe..13bc139ecd0 100644 --- a/src/test/codegen/naked-noinline.rs +++ b/src/test/codegen/naked-noinline.rs @@ -7,7 +7,6 @@ use std::arch::asm; -#[inline(always)] #[naked] #[no_mangle] pub unsafe extern "C" fn f() { diff --git a/src/test/codegen/unwind-and-panic-abort.rs b/src/test/codegen/unwind-and-panic-abort.rs index 05d97f3256a..f238741e599 100644 --- a/src/test/codegen/unwind-and-panic-abort.rs +++ b/src/test/codegen/unwind-and-panic-abort.rs @@ -9,7 +9,7 @@ extern "C-unwind" { // CHECK: Function Attrs:{{.*}}nounwind // CHECK-NEXT: define{{.*}}void @foo -// CHECK: call void @llvm.trap() +// CHECK: call void @_ZN4core9panicking15panic_no_unwind #[no_mangle] pub unsafe extern "C" fn foo() { bar(); diff --git a/src/test/debuginfo/function-names.rs b/src/test/debuginfo/function-names.rs index ac9a02cce04..61d5fc93cd2 100644 --- a/src/test/debuginfo/function-names.rs +++ b/src/test/debuginfo/function-names.rs @@ -37,7 +37,7 @@ // Const generic parameter // gdb-command:info functions -q function_names::const_generic_fn.* // gdb-check:[...]static fn function_names::const_generic_fn_bool<false>(); -// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#3fcd7c34c1555be6}>(); +// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#fe3cfa0214ac55c7}>(); // gdb-check:[...]static fn function_names::const_generic_fn_signed_int<-7>(); // gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int<14>(); @@ -76,7 +76,7 @@ // Const generic parameter // cdb-command:x a!function_names::const_generic_fn* // cdb-check:[...] a!function_names::const_generic_fn_bool<false> (void) -// cdb-check:[...] a!function_names::const_generic_fn_non_int<CONST$3fcd7c34c1555be6> (void) +// cdb-check:[...] a!function_names::const_generic_fn_non_int<CONST$fe3cfa0214ac55c7> (void) // cdb-check:[...] a!function_names::const_generic_fn_unsigned_int<14> (void) // cdb-check:[...] a!function_names::const_generic_fn_signed_int<-7> (void) diff --git a/src/test/debuginfo/unsized.rs b/src/test/debuginfo/unsized.rs index c27fe61dc8b..ebd40f9dda2 100644 --- a/src/test/debuginfo/unsized.rs +++ b/src/test/debuginfo/unsized.rs @@ -4,32 +4,56 @@ // gdb-command:run -// gdb-command:print *a -// gdbg-check:$1 = {value = [...] "abc"} -// gdbr-check:$1 = unsized::Foo<[u8]> {value: [...]} +// gdb-command:print a +// gdbg-check:$1 = {data_ptr = [...], length = 4} +// gdbr-check:$1 = &unsized::Foo<[u8]> {data_ptr: [...], length: 4} -// gdb-command:print *b -// gdbg-check:$2 = {value = {value = [...] "abc"}} -// gdbr-check:$2 = unsized::Foo<unsized::Foo<[u8]>> {value: unsized::Foo<[u8]> {value: [...]}} +// gdb-command:print b +// gdbg-check:$2 = {data_ptr = [...], length = 4} +// gdbr-check:$2 = &unsized::Foo<unsized::Foo<[u8]>> {data_ptr: [...], length: 4} +// gdb-command:print c +// gdbg-check:$3 = {pointer = [...], vtable = [...]} +// gdbr-check:$3 = &unsized::Foo<dyn core::fmt::Debug> {pointer: [...], vtable: [...]} + +// === CDB TESTS =================================================================================== + +// cdb-command: g +// cdb-command:dx a +// cdb-check:a [Type: ref$<unsized::Foo<slice$<u8> > >] +// cdb-check: [+0x000] data_ptr : 0x[...] [Type: unsized::Foo<slice$<u8> > *] +// cdb-check: [...] length : 0x4 [Type: unsigned [...]int[...] + +// cdb-command:dx b +// cdb-check:b [Type: ref$<unsized::Foo<unsized::Foo<slice$<u8> > > >] +// cdb-check: [+0x000] data_ptr : 0x[...] [Type: unsized::Foo<unsized::Foo<slice$<u8> > > *] +// cdb-check: [...] length : 0x4 [Type: unsigned [...]int[...] + +// cdb-command:dx c +// cdb-check:c [Type: ref$<unsized::Foo<dyn$<core::fmt::Debug> > >] +// cdb-check: [+0x000] pointer : 0x[...] [Type: unsized::Foo<dyn$<core::fmt::Debug> > *] +// cdb-check: [...] vtable : 0x[...] [Type: unsigned [...]int[...] (*)[3]] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] struct Foo<T: ?Sized> { - value: T + value: T, } fn main() { - let foo: Foo<Foo<[u8; 4]>> = Foo { - value: Foo { - value: *b"abc\0" - } - }; + let foo: Foo<Foo<[u8; 4]>> = Foo { value: Foo { value: *b"abc\0" } }; + + // We expect `a`, `b`, and `c` to all be fat pointers. + // `a` and `b` should be slice-like and thus have a `data_ptr` and `length` field. + // `c` should be trait-object-like and thus have a `pointer` and `vtable` field. let a: &Foo<[u8]> = &foo.value; let b: &Foo<Foo<[u8]>> = &foo; + let c: &Foo<dyn std::fmt::Debug> = &Foo { value: 7i32 }; zzz(); // #break } -fn zzz() { () } +fn zzz() { + () +} diff --git a/src/test/debuginfo/vec-slices.rs b/src/test/debuginfo/vec-slices.rs index e109b1bf2ae..7d88e45caf2 100644 --- a/src/test/debuginfo/vec-slices.rs +++ b/src/test/debuginfo/vec-slices.rs @@ -1,5 +1,4 @@ // ignore-windows -// ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155 // min-lldb-version: 310 // compile-flags:-g @@ -13,21 +12,21 @@ // gdb-command:print singleton.length // gdb-check:$2 = 1 // gdbg-command:print *((i64[1]*)(singleton.data_ptr)) -// gdbr-command:print *(singleton.data_ptr as &[i64; 1]) +// gdbr-command:print *(singleton.data_ptr as *const [i64; 1]) // gdbg-check:$3 = {1} // gdbr-check:$3 = [1] // gdb-command:print multiple.length // gdb-check:$4 = 4 // gdbg-command:print *((i64[4]*)(multiple.data_ptr)) -// gdbr-command:print *(multiple.data_ptr as &[i64; 4]) +// gdbr-command:print *(multiple.data_ptr as *const [i64; 4]) // gdbg-check:$5 = {2, 3, 4, 5} // gdbr-check:$5 = [2, 3, 4, 5] // gdb-command:print slice_of_slice.length // gdb-check:$6 = 2 // gdbg-command:print *((i64[2]*)(slice_of_slice.data_ptr)) -// gdbr-command:print *(slice_of_slice.data_ptr as &[i64; 2]) +// gdbr-command:print *(slice_of_slice.data_ptr as *const [i64; 2]) // gdbg-check:$7 = {3, 4} // gdbr-check:$7 = [3, 4] @@ -49,21 +48,24 @@ // gdbg-check:$13 = {x = 13, y = 14, z = 15} // gdbr-check:$13 = vec_slices::AStruct {x: 13, y: 14, z: 15} -// gdbg-command:print 'vec_slices::MUT_VECT_SLICE'.length -// gdbr-command:print MUT_VECT_SLICE.length -// gdb-check:$14 = 2 -// gdbg-command:print *((i64[2]*)('vec_slices::MUT_VECT_SLICE'.data_ptr)) -// gdbr-command:print *(MUT_VECT_SLICE.data_ptr as &[i64; 2]) -// gdbg-check:$15 = {64, 65} -// gdbr-check:$15 = [64, 65] +// gdb-command:print mut_slice.length +// gdb-check:$14 = 5 +// gdbg-command:print *((i64[5]*)(mut_slice.data_ptr)) +// gdbr-command:print *(mut_slice.data_ptr as *const [i64; 5]) +// gdbg-check:$15 = {1, 2, 3, 4, 5} +// gdbr-check:$15 = [1, 2, 3, 4, 5] -//gdb-command:print mut_slice.length -//gdb-check:$16 = 5 -//gdbg-command:print *((i64[5]*)(mut_slice.data_ptr)) -//gdbr-command:print *(mut_slice.data_ptr as &[i64; 5]) -//gdbg-check:$17 = {1, 2, 3, 4, 5} -//gdbr-check:$17 = [1, 2, 3, 4, 5] +// Some lines below are marked with [ignored] because old GDB versions seem to have trouble +// accessing globals. +// [ignored] gdbg-command:print 'vec_slices::MUT_VECT_SLICE'.length +// gdbr-command:print MUT_VECT_SLICE.length +// [ignored] gdbg-check:$16 = 2 +// gdbr-check:$16 = 2 +// [ignored] gdbg-command:print *((i64[2]*)('vec_slices::MUT_VECT_SLICE'.data_ptr)) +// gdbr-command:print *(MUT_VECT_SLICE.data_ptr as *const [i64; 2]) +// [ignored] gdbg-check:$17 = {64, 65} +// gdbr-check:$17 = [64, 65] // === LLDB TESTS ================================================================================== @@ -100,7 +102,7 @@ struct AStruct { x: i16, y: i32, - z: i16 + z: i16, } static VECT_SLICE: &'static [i64] = &[64, 65]; @@ -114,10 +116,8 @@ fn main() { let padded_tuple: &[(i32, i16)] = &[(6, 7), (8, 9)]; - let padded_struct: &[AStruct] = &[ - AStruct { x: 10, y: 11, z: 12 }, - AStruct { x: 13, y: 14, z: 15 } - ]; + let padded_struct: &[AStruct] = + &[AStruct { x: 10, y: 11, z: 12 }, AStruct { x: 13, y: 14, z: 15 }]; unsafe { MUT_VECT_SLICE = VECT_SLICE; @@ -128,4 +128,6 @@ fn main() { zzz(); // #break } -fn zzz() {()} +fn zzz() { + () +} diff --git a/src/test/incremental/hashes/extern_mods.rs b/src/test/incremental/hashes/extern_mods.rs index 4bc98fd7cd0..142780bbc85 100644 --- a/src/test/incremental/hashes/extern_mods.rs +++ b/src/test/incremental/hashes/extern_mods.rs @@ -27,9 +27,9 @@ extern "C" { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner,hir_owner_nodes")] #[rustc_clean(cfg = "cfail6")] extern "C" { pub fn change_function_name2(c: i64) -> i32; @@ -132,9 +132,9 @@ extern "C" { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner,hir_owner_nodes")] #[rustc_clean(cfg = "cfail6")] extern "rust-call" { pub fn change_calling_convention(c: i32); @@ -162,9 +162,9 @@ extern "C" { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2", except = "hir_owner")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "hir_owner")] +#[rustc_clean(cfg = "cfail5", except = "hir_owner,hir_owner_nodes")] #[rustc_clean(cfg = "cfail6")] extern "C" { pub fn add_function1(c: i32); diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs index 3a59377e819..22508e41bf8 100644 --- a/src/test/incremental/hashes/inherent_impls.rs +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -29,9 +29,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,associated_item_def_ids")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,associated_item_def_ids")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,associated_item_def_ids")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,associated_item_def_ids")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail3")] @@ -54,9 +54,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,promoted_mir,typeck")] @@ -91,9 +91,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean( @@ -153,9 +153,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean( @@ -182,9 +182,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir")] @@ -203,9 +203,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,associated_item_def_ids")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,associated_item_def_ids")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,associated_item_def_ids")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,associated_item_def_ids")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2")] @@ -232,9 +232,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir")] @@ -257,9 +257,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] @@ -282,9 +282,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,optimized_mir,typeck")] @@ -308,9 +308,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2")] @@ -334,9 +334,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")] @@ -359,9 +359,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir")] @@ -384,9 +384,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck")] @@ -409,9 +409,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck")] @@ -443,9 +443,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { // Warning: Note that `typeck` are coming up clean here. @@ -492,9 +492,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { // Warning: Note that `typeck` are coming up clean here. @@ -538,9 +538,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean( @@ -584,9 +584,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { // Warning: Note that `typeck` are coming up clean here. @@ -633,9 +633,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { // Warning: Note that `typeck` are coming up clean here. @@ -668,9 +668,9 @@ impl Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { #[rustc_clean(cfg="cfail2")] @@ -719,9 +719,9 @@ impl Bar<u32> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail6")] impl Bar<u64> { #[rustc_clean(cfg="cfail2", except="fn_sig,optimized_mir,typeck")] diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs index 14d6fc87198..279449fce5e 100644 --- a/src/test/incremental/hashes/trait_defs.rs +++ b/src/test/incremental/hashes/trait_defs.rs @@ -31,9 +31,9 @@ trait TraitVisibility { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub trait TraitVisibility { } @@ -44,9 +44,9 @@ pub trait TraitVisibility { } trait TraitUnsafety { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] unsafe trait TraitUnsafety { } @@ -58,9 +58,9 @@ trait TraitAddMethod { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub trait TraitAddMethod { fn method(); @@ -75,9 +75,9 @@ trait TraitChangeMethodName { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeMethodName { fn methodChanged(); @@ -88,9 +88,9 @@ trait TraitChangeMethodName { // Add return type to method #[cfg(any(cfail1,cfail4))] trait TraitAddReturnType { - //----------------------------------------------------- + //--------------------------------------------------------------------- //-------------------------- - //----------------------------------------------------- + //--------------------------------------------------------------------- //-------------------------- fn method() ; } @@ -101,9 +101,9 @@ trait TraitAddReturnType { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddReturnType { - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method() -> u32; } @@ -138,9 +138,9 @@ trait TraitChangeReturnType { // Add parameter to method #[cfg(any(cfail1,cfail4))] trait TraitAddParameterToMethod { - // ---------------------------------------------------- + // -------------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------- + // -------------------------------------------------------------------- // ------------------------- fn method( ); } @@ -151,9 +151,9 @@ trait TraitAddParameterToMethod { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddParameterToMethod { - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(a: u32); } @@ -164,9 +164,9 @@ trait TraitAddParameterToMethod { #[cfg(any(cfail1,cfail4))] trait TraitChangeMethodParameterName { //------------------------------------------------------ - //---------------------------------------------- + //-------------------------------------------------------------- //-------------------------- - //---------------------------------------------- + //-------------------------------------------------------------- //-------------------------- fn method(a: u32); @@ -184,9 +184,9 @@ trait TraitChangeMethodParameterName { #[rustc_clean(cfg="cfail6")] trait TraitChangeMethodParameterName { // FIXME(#38501) This should preferably always be clean. - #[rustc_clean(except="hir_owner", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(b: u32); @@ -202,9 +202,9 @@ trait TraitChangeMethodParameterName { // Change type of method parameter (i32 => i64) #[cfg(any(cfail1,cfail4))] trait TraitChangeMethodParameterType { - // ---------------------------------------------------- + // -------------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------- + // -------------------------------------------------------------------- // ------------------------- fn method(a: i32); } @@ -215,9 +215,9 @@ trait TraitChangeMethodParameterType { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeMethodParameterType { - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(a: i64); } @@ -227,9 +227,9 @@ trait TraitChangeMethodParameterType { // Change type of method parameter (&i32 => &mut i32) #[cfg(any(cfail1,cfail4))] trait TraitChangeMethodParameterTypeRef { - // ---------------------------------------------------- + // -------------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------- + // -------------------------------------------------------------------- // ------------------------- fn method(a: & i32); } @@ -240,9 +240,9 @@ trait TraitChangeMethodParameterTypeRef { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeMethodParameterTypeRef { - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(a: &mut i32); } @@ -252,9 +252,9 @@ trait TraitChangeMethodParameterTypeRef { // Change order of method parameters #[cfg(any(cfail1,cfail4))] trait TraitChangeMethodParametersOrder { - // ---------------------------------------------------- + // -------------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------- + // -------------------------------------------------------------------- // ------------------------- fn method(a: i32, b: i64); } @@ -265,9 +265,9 @@ trait TraitChangeMethodParametersOrder { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeMethodParametersOrder { - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(b: i64, a: i32); } @@ -277,20 +277,24 @@ trait TraitChangeMethodParametersOrder { // Add default implementation to method #[cfg(any(cfail1,cfail4))] trait TraitAddMethodAutoImplementation { - fn method(); + // ----------------------------------------------------------------------------- + // ------------------------- + // ----------------------------------------------------------------------------- + // ------------------------- + fn method() ; } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddMethodAutoImplementation { - #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,associated_item", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] - fn method() { } + fn method() {} } @@ -303,9 +307,9 @@ trait TraitChangeOrderOfMethods { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeOrderOfMethods { fn method1(); @@ -317,9 +321,9 @@ trait TraitChangeOrderOfMethods { // Change mode of self parameter #[cfg(any(cfail1,cfail4))] trait TraitChangeModeSelfRefToMut { - // ---------------------------------------------------- + // -------------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------- + // -------------------------------------------------------------------- // ------------------------- fn method(& self); } @@ -330,9 +334,9 @@ trait TraitChangeModeSelfRefToMut { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeModeSelfRefToMut { - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(&mut self); } @@ -365,9 +369,9 @@ trait TraitChangeModeSelfOwnToMut: Sized { #[cfg(any(cfail1,cfail4))] trait TraitChangeModeSelfOwnToRef { - // ---------------------------------------------------------------- + // -------------------------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------------------- + // -------------------------------------------------------------------------------- // ------------------------- fn method( self); } @@ -378,9 +382,9 @@ trait TraitChangeModeSelfOwnToRef { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeModeSelfOwnToRef { - #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,generics_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,generics_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method(&self); } @@ -390,9 +394,9 @@ trait TraitChangeModeSelfOwnToRef { // Add unsafe modifier to method #[cfg(any(cfail1,cfail4))] trait TraitAddUnsafeModifier { - // ---------------------------------------------------- + // -------------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------- + // -------------------------------------------------------------------- // ------------------------- fn method() ; } @@ -403,9 +407,9 @@ trait TraitAddUnsafeModifier { #[rustc_clean(except="hir_owner", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddUnsafeModifier { - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] unsafe fn method(); } @@ -415,9 +419,9 @@ trait TraitAddUnsafeModifier { // Add extern modifier to method #[cfg(any(cfail1,cfail4))] trait TraitAddExternModifier { - // ---------------------------------------------------- + // -------------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------- + // -------------------------------------------------------------------- // ------------------------- fn method() ; } @@ -428,9 +432,9 @@ trait TraitAddExternModifier { #[rustc_clean(except="hir_owner", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddExternModifier { - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] extern "C" fn method(); } @@ -440,9 +444,9 @@ trait TraitAddExternModifier { // Change extern "C" to extern "stdcall" #[cfg(any(cfail1,cfail4))] trait TraitChangeExternCToRustIntrinsic { - // ---------------------------------------------------- + // -------------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------- + // -------------------------------------------------------------------- // ------------------------- extern "C" fn method(); } @@ -453,9 +457,9 @@ trait TraitChangeExternCToRustIntrinsic { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeExternCToRustIntrinsic { - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] extern "stdcall" fn method(); } @@ -465,9 +469,11 @@ trait TraitChangeExternCToRustIntrinsic { // Add type parameter to method #[cfg(any(cfail1,cfail4))] trait TraitAddTypeParameterToMethod { - // ------------------------------------------------------------------------------- + // -------------------------------------------------------------------------------- + // --------------- // ------------------------- - // ------------------------------------------------------------------------------- + // -------------------------------------------------------------------------------- + // --------------- // ------------------------- fn method (); } @@ -478,9 +484,11 @@ trait TraitAddTypeParameterToMethod { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTypeParameterToMethod { - #[rustc_clean(except="hir_owner,generics_of,predicates_of,type_of", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of", + cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,generics_of,predicates_of,type_of", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of", + cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method<T>(); } @@ -490,9 +498,9 @@ trait TraitAddTypeParameterToMethod { // Add lifetime parameter to method #[cfg(any(cfail1,cfail4))] trait TraitAddLifetimeParameterToMethod { - // ---------------------------------------------------------------- + // -------------------------------------------------------------------------------- // ------------------------- - // ---------------------------------------------------------------- + // -------------------------------------------------------------------------------- // ------------------------- fn method (); } @@ -503,9 +511,9 @@ trait TraitAddLifetimeParameterToMethod { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeParameterToMethod { - #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,generics_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,generics_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method<'a>(); } @@ -705,9 +713,9 @@ trait TraitAddAssociatedType { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddAssociatedType { #[rustc_clean(cfg="cfail3")] @@ -726,9 +734,9 @@ trait TraitAddAssociatedType { // Add trait bound to associated type #[cfg(any(cfail1,cfail4))] trait TraitAddTraitBoundToAssociatedType { - // --------------------------------------------- + // ------------------------------------------------------------- // ------------------------- - // --------------------------------------------- + // ------------------------------------------------------------- // ------------------------- type Associated ; @@ -744,9 +752,9 @@ trait TraitAddTraitBoundToAssociatedType { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTraitBoundToAssociatedType { - #[rustc_clean(except="hir_owner", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] type Associated: ReferencedTrait0; @@ -758,9 +766,9 @@ trait TraitAddTraitBoundToAssociatedType { // Add lifetime bound to associated type #[cfg(any(cfail1,cfail4))] trait TraitAddLifetimeBoundToAssociatedType<'a> { - // --------------------------------------------- + // ------------------------------------------------------------- // ------------------------- - // --------------------------------------------- + // ------------------------------------------------------------- // ------------------------- type Associated ; @@ -773,9 +781,9 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToAssociatedType<'a> { - #[rustc_clean(except="hir_owner", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] type Associated: 'a; @@ -793,14 +801,14 @@ trait TraitAddDefaultToAssociatedType { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddDefaultToAssociatedType { - #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,associated_item", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] type Associated = ReferenceType0; @@ -816,9 +824,9 @@ trait TraitAddAssociatedConstant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddAssociatedConstant { const Value: u32; @@ -837,14 +845,14 @@ trait TraitAddInitializerToAssociatedConstant { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddInitializerToAssociatedConstant { - #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,associated_item", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] const Value: u32 = 1; @@ -860,9 +868,9 @@ trait TraitAddInitializerToAssociatedConstant { // Change type of associated constant #[cfg(any(cfail1,cfail4))] trait TraitChangeTypeOfAssociatedConstant { - // ----------------------------------------------------- + // --------------------------------------------------------------------- // ------------------------- - // ----------------------------------------------------- + // --------------------------------------------------------------------- // ------------------------- const Value: u32; @@ -879,9 +887,9 @@ trait TraitChangeTypeOfAssociatedConstant { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitChangeTypeOfAssociatedConstant { - #[rustc_clean(except="hir_owner,type_of", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,type_of", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] const Value: f64; @@ -899,9 +907,9 @@ trait TraitChangeTypeOfAssociatedConstant { trait TraitAddSuperTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSuperTrait : ReferencedTrait0 { } @@ -912,9 +920,9 @@ trait TraitAddSuperTrait : ReferencedTrait0 { } trait TraitAddBuiltiBound { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddBuiltiBound : Send { } @@ -925,9 +933,9 @@ trait TraitAddBuiltiBound : Send { } trait TraitAddStaticLifetimeBound { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddStaticLifetimeBound : 'static { } @@ -938,9 +946,9 @@ trait TraitAddStaticLifetimeBound : 'static { } trait TraitAddTraitAsSecondBound : ReferencedTrait0 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTraitAsSecondBound : ReferencedTrait0 + ReferencedTrait1 { } @@ -948,9 +956,9 @@ trait TraitAddTraitAsSecondBound : ReferencedTrait0 + ReferencedTrait1 { } trait TraitAddTraitAsSecondBoundFromBuiltin : Send { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { } @@ -961,9 +969,9 @@ trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { } trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 + Send { } @@ -971,9 +979,9 @@ trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 + Send { } trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin : Send { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { } @@ -984,9 +992,9 @@ trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { } trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 + 'static { } @@ -994,9 +1002,9 @@ trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 + 'static { } trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { } @@ -1007,9 +1015,9 @@ trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { } trait TraitAddTypeParameterToTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddTypeParameterToTrait<T> { } @@ -1020,9 +1028,9 @@ trait TraitAddTypeParameterToTrait<T> { } trait TraitAddLifetimeParameterToTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeParameterToTrait<'a> { } @@ -1298,9 +1306,13 @@ mod change_method_parameter_type_indirectly_by_use { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] trait TraitChangeArgType { - #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method(a: ArgType); } } @@ -1316,9 +1328,13 @@ mod change_method_parameter_type_bound_indirectly_by_use { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] trait TraitChangeBoundOfMethodTypeParameter { #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] fn method<T: Bound>(a: T); } } @@ -1357,6 +1373,8 @@ mod change_method_type_parameter_bound_indirectly { #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] + #[rustc_clean(cfg="cfail6")] trait TraitChangeTraitBound<T: Bound> { fn method(a: T); } diff --git a/src/test/incremental/hashes/trait_impls.rs b/src/test/incremental/hashes/trait_impls.rs index d623810115e..75c93b73f85 100644 --- a/src/test/incremental/hashes/trait_impls.rs +++ b/src/test/incremental/hashes/trait_impls.rs @@ -35,9 +35,9 @@ impl ChangeMethodNameTrait for Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub trait ChangeMethodNameTrait { #[rustc_clean(cfg="cfail3")] @@ -46,9 +46,9 @@ pub trait ChangeMethodNameTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeMethodNameTrait for Foo { #[rustc_clean(cfg="cfail3")] @@ -144,9 +144,9 @@ pub trait ChangeMethodSelfnessTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeMethodSelfnessTrait for Foo { #[rustc_clean( @@ -182,9 +182,9 @@ pub trait RemoveMethodSelfnessTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl RemoveMethodSelfnessTrait for Foo { #[rustc_clean( @@ -252,9 +252,9 @@ pub trait ChangeItemKindTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeItemKindTrait for Foo { type name = (); @@ -280,9 +280,9 @@ pub trait RemoveItemTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl RemoveItemTrait for Foo { type TypeName = (); @@ -307,9 +307,9 @@ pub trait AddItemTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl AddItemTrait for Foo { type TypeName = (); @@ -329,14 +329,14 @@ impl ChangeHasValueTrait for Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] pub trait ChangeHasValueTrait { - #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(except="hir_owner,associated_item", cfg="cfail5")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] fn method_name() { } } @@ -364,9 +364,9 @@ impl AddDefaultTrait for Foo { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl AddDefaultTrait for Foo { #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")] @@ -459,9 +459,9 @@ impl AddTypeParameterToImpl<u32> for Bar<u32> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,generics_of,impl_trait_ref", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,impl_trait_ref", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,generics_of,impl_trait_ref", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,impl_trait_ref", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl<TTT> AddTypeParameterToImpl<TTT> for Bar<TTT> { #[rustc_clean( @@ -490,9 +490,9 @@ impl ChangeSelfTypeOfImpl for u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,impl_trait_ref", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,impl_trait_ref", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,impl_trait_ref", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,impl_trait_ref", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeSelfTypeOfImpl for u64 { #[rustc_clean(except="fn_sig,typeck,optimized_mir", cfg="cfail2")] diff --git a/src/test/incremental/hashes/type_defs.rs b/src/test/incremental/hashes/type_defs.rs index 70c199bc3be..1d278c4efa9 100644 --- a/src/test/incremental/hashes/type_defs.rs +++ b/src/test/incremental/hashes/type_defs.rs @@ -24,7 +24,7 @@ type ChangePrimitiveType = i32; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangePrimitiveType = i64; @@ -35,7 +35,7 @@ type ChangePrimitiveType = i64; type ChangeMutability = &'static i32; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeMutability = &'static mut i32; @@ -60,7 +60,7 @@ struct Struct2; type ChangeTypeStruct = Struct1; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeTypeStruct = Struct2; @@ -71,7 +71,7 @@ type ChangeTypeStruct = Struct2; type ChangeTypeTuple = (u32, u64); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeTypeTuple = (u32, i64); @@ -91,7 +91,7 @@ enum Enum2 { type ChangeTypeEnum = Enum1; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeTypeEnum = Enum2; @@ -102,7 +102,7 @@ type ChangeTypeEnum = Enum2; type AddTupleField = (i32, i64); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type AddTupleField = (i32, i64, i16); @@ -113,7 +113,7 @@ type AddTupleField = (i32, i64, i16); type ChangeNestedTupleField = (i32, (i64, i16)); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] type ChangeNestedTupleField = (i32, (i64, i8)); diff --git a/src/test/incremental/issue-92987-provisional-dep-node.rs b/src/test/incremental/issue-92987-provisional-dep-node.rs new file mode 100644 index 00000000000..a48a8373c2b --- /dev/null +++ b/src/test/incremental/issue-92987-provisional-dep-node.rs @@ -0,0 +1,24 @@ +// revisions: rpass1 rpass2 + +// Regression test for issue #92987 +// Tests that we properly manage `DepNode`s during trait evaluation +// involing an auto-trait cycle. + +#[cfg(rpass1)] +struct CycleOne(Box<CycleTwo>); + +#[cfg(rpass2)] +enum CycleOne { + Variant(Box<CycleTwo>) +} + +struct CycleTwo(CycleOne); + +fn assert_send<T: Send>() {} + +fn bar() { + assert_send::<CycleOne>(); + assert_send::<CycleTwo>(); +} + +fn main() {} diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff index 1e531365638..b480b257825 100644 --- a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff @@ -30,7 +30,7 @@ - _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 + // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:44 -+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[HASH]::BAR), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } ++ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[e01c]::BAR), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 - StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35 diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff index a012285c7ec..ed48f5dc9dc 100644 --- a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff @@ -32,7 +32,7 @@ - _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 + // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:55 -+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[HASH]::FOO), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } ++ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[e01c]::FOO), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 - StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46 diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff index 7627ed54623..553011f1aaa 100644 --- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff @@ -31,7 +31,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 - // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[fbcf]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff index 7627ed54623..553011f1aaa 100644 --- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff @@ -31,7 +31,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 - // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[fbcf]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff index e6220176778..44273b763be 100644 --- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff @@ -22,7 +22,7 @@ // + val: Unevaluated(FOO, [], None) // mir::Constant // + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[HASH]::main::FOO), const_param_did: None }, substs: [], promoted: None }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[809a]::main::FOO), const_param_did: None }, substs: [], promoted: None }) } _2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 _1 = move _2 as usize (Misc); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39 StorageDead(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39 diff --git a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff index d602e12a370..2864e01d9dc 100644 --- a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff @@ -17,7 +17,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/ref_deref.rs:5:6: 5:10 - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[d561]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _2 = _4; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 - _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 + _1 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 diff --git a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff index 35916d90e56..5a678616f63 100644 --- a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff +++ b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff @@ -20,7 +20,7 @@ + // + val: Unevaluated(main, [], Some(promoted[0])) + // mir::Constant + // + span: $DIR/ref_deref.rs:5:6: 5:10 -+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } ++ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[d561]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 - StorageDead(_3); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11 diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff index 39651884e77..53f9daa09da 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff @@ -17,7 +17,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/ref_deref_project.rs:5:6: 5:17 - // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[d1f7]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff index 501d7205679..d5235a1d025 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff @@ -20,7 +20,7 @@ + // + val: Unevaluated(main, [], Some(promoted[0])) + // mir::Constant + // + span: $DIR/ref_deref_project.rs:5:6: 5:17 -+ // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } ++ // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[d1f7]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 - StorageDead(_3); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff index 6a580278d5f..339c3d13b8d 100644 --- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff @@ -25,7 +25,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/slice_len.rs:5:6: 5:19 - // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[7261]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 StorageLive(_10); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff index 6a580278d5f..339c3d13b8d 100644 --- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff @@ -25,7 +25,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/slice_len.rs:5:6: 5:19 - // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[7261]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 StorageLive(_10); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 diff --git a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff index c1591e5d729..3fe23633852 100644 --- a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff @@ -12,8 +12,8 @@ let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 let _8: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 let _9: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:5:24: 5:25 -+ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 -+ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 ++ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 ++ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 scope 1 { debug a => _8; // in scope 1 at $DIR/early_otherwise_branch.rs:5:15: 5:16 debug b => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:5:24: 5:25 @@ -34,7 +34,7 @@ + StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 + _10 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 -+ _11 = Ne(_10, _7); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 ++ _11 = Ne(_7, move _10); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 + StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 + switchInt(move _11) -> [false: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 } @@ -70,8 +70,8 @@ + } + + bb4: { -+ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 -+ switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 ++ switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 } } diff --git a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff index b949d307e20..6d149b89edb 100644 --- a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff @@ -13,8 +13,8 @@ let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 let _9: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 let _10: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:13:24: 13:25 -+ let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 -+ let mut _12: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 ++ let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 ++ let mut _12: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 scope 1 { debug a => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:13:15: 13:16 debug b => _10; // in scope 1 at $DIR/early_otherwise_branch.rs:13:24: 13:25 @@ -35,7 +35,7 @@ + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 + _11 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 -+ _12 = Ne(_11, _8); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 ++ _12 = Ne(_8, move _11); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 + switchInt(move _12) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 } @@ -84,8 +84,8 @@ + } + + bb5: { -+ StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 -+ switchInt(_8) -> [0_isize: bb3, 1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 ++ StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 ++ switchInt(_8) -> [0_isize: bb3, 1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 } } diff --git a/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff new file mode 100644 index 00000000000..2aa22737bde --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff @@ -0,0 +1,77 @@ +- // MIR for `opt3` before EarlyOtherwiseBranch ++ // MIR for `opt3` after EarlyOtherwiseBranch + + fn opt3(_1: Option<u32>, _2: Option<bool>) -> u32 { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:21:9: 21:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:21:25: 21:26 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch.rs:21:45: 21:48 + let mut _3: (std::option::Option<u32>, std::option::Option<bool>); // in scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 + let mut _4: std::option::Option<u32>; // in scope 0 at $DIR/early_otherwise_branch.rs:22:12: 22:13 + let mut _5: std::option::Option<bool>; // in scope 0 at $DIR/early_otherwise_branch.rs:22:15: 22:16 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:23:19: 23:26 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:23:10: 23:17 + let _8: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:23:15: 23:16 + let _9: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:23:24: 23:25 ++ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 ++ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 + scope 1 { + debug a => _8; // in scope 1 at $DIR/early_otherwise_branch.rs:23:15: 23:16 + debug b => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:23:24: 23:25 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:22:12: 22:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:22:12: 22:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:22:15: 22:16 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:22:15: 22:16 + (_3.0: std::option::Option<u32>) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 + (_3.1: std::option::Option<bool>) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:22:16: 22:17 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:22:16: 22:17 + _7 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 +- switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 ++ StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 ++ _10 = discriminant((_3.1: std::option::Option<bool>)); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 ++ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 ++ _11 = Ne(_7, move _10); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 ++ StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 ++ switchInt(move _11) -> [false: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 + } + + bb1: { ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:24:14: 24:15 + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:24:14: 24:15 +- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:24:14: 24:15 ++ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:24:14: 24:15 + } + + bb2: { +- _6 = discriminant((_3.1: std::option::Option<bool>)); // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 +- switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 +- } +- +- bb3: { + StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch.rs:23:15: 23:16 + _8 = (((_3.0: std::option::Option<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:23:15: 23:16 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:23:24: 23:25 + _9 = (((_3.1: std::option::Option<bool>) as Some).0: bool); // scope 0 at $DIR/early_otherwise_branch.rs:23:24: 23:25 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch.rs:23:31: 23:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:23:31: 23:32 + StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch.rs:23:31: 23:32 +- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:23:31: 23:32 ++ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:23:31: 23:32 + } + +- bb4: { ++ bb3: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:26:1: 26:2 + return; // scope 0 at $DIR/early_otherwise_branch.rs:26:2: 26:2 ++ } ++ ++ bb4: { ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 ++ switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch.rs b/src/test/mir-opt/early_otherwise_branch.rs index b2caf7d7b8f..e0ebcfeebfc 100644 --- a/src/test/mir-opt/early_otherwise_branch.rs +++ b/src/test/mir-opt/early_otherwise_branch.rs @@ -16,7 +16,17 @@ fn opt2(x: Option<u32>, y: Option<u32>) -> u32 { } } +// optimize despite different types +// EMIT_MIR early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff +fn opt3(x: Option<u32>, y: Option<bool>) -> u32 { + match (x, y) { + (Some(a), Some(b)) => 0, + _ => 1, + } +} + fn main() { opt1(None, Some(0)); opt2(None, Some(0)); + opt3(None, Some(false)); } diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff index 5b9ec1e53d9..8b78f3ce202 100644 --- a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff @@ -16,10 +16,10 @@ let _11: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 let _12: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 let _13: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34 -+ let mut _14: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 -+ let mut _15: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 -+ let mut _16: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 -+ let mut _17: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 ++ let mut _14: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ let mut _15: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ let mut _16: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ let mut _17: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 scope 1 { debug a => _11; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 debug b => _12; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 @@ -45,7 +45,7 @@ + StorageLive(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 + _14 = discriminant((_4.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 + StorageLive(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 -+ _15 = Ne(_14, _10); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ _15 = Ne(_10, move _14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 + StorageDead(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 + switchInt(move _15) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 } @@ -92,8 +92,8 @@ + } + + bb5: { -+ StorageDead(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 -+ switchInt(_10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 ++ StorageDead(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ switchInt(_10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 } } diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff index 44294030439..fc2dcb25109 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff @@ -36,8 +36,8 @@ let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:14: 26:28 let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27 -+ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30 -+ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30 ++ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 ++ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 scope 1 { - debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 - debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 @@ -85,7 +85,7 @@ + StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 -+ _35 = Ne(_34, _11); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 ++ _35 = Ne(_11, move _34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + switchInt(move _35) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 } @@ -293,8 +293,8 @@ - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2 - return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2 -+ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30 -+ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30 ++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 ++ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 } } diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff index af32d4d2d14..28c650d72dc 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff @@ -36,8 +36,8 @@ let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:14: 26:28 let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27 -+ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30 -+ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30 ++ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 ++ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 scope 1 { debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 @@ -71,7 +71,7 @@ + StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 -+ _35 = Ne(_34, _11); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 ++ _35 = Ne(_11, move _34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + switchInt(move _35) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 } @@ -209,8 +209,8 @@ + } + + bb7: { -+ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30 -+ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30 ++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 ++ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 } } diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff deleted file mode 100644 index 66ea828bf68..00000000000 --- a/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff +++ /dev/null @@ -1,60 +0,0 @@ -- // MIR for `noopt2` before EarlyOtherwiseBranch -+ // MIR for `noopt2` after EarlyOtherwiseBranch - - fn noopt2(_1: Option<u32>, _2: Option<bool>) -> u32 { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:18:11: 18:12 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:18:27: 18:28 - let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:18:47: 18:50 - let mut _3: (std::option::Option<u32>, std::option::Option<bool>); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 - let mut _4: std::option::Option<u32>; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:12: 19:13 - let mut _5: std::option::Option<bool>; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:15: 19:16 - let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:19: 20:26 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:10: 20:17 - let _8: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 - let _9: bool; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 - scope 1 { - debug a => _8; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 - debug b => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 - } - - bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:12: 19:13 - _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:12: 19:13 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:15: 19:16 - _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:15: 19:16 - (_3.0: std::option::Option<u32>) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 - (_3.1: std::option::Option<bool>) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:16: 19:17 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:16: 19:17 - _7 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 - switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:5: 19:17 - } - - bb1: { - _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:14: 21:15 - goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:14: 21:15 - } - - bb2: { - _6 = discriminant((_3.1: std::option::Option<bool>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 - switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:5: 19:17 - } - - bb3: { - StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 - _8 = (((_3.0: std::option::Option<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 - StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 - _9 = (((_3.1: std::option::Option<bool>) as Some).0: bool); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 - _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32 - StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32 - StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32 - goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32 - } - - bb4: { - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:23:1: 23:2 - return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:23:2: 23:2 - } - } - diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.rs b/src/test/mir-opt/early_otherwise_branch_noopt.rs index d04e2a0429d..1f8c59df35f 100644 --- a/src/test/mir-opt/early_otherwise_branch_noopt.rs +++ b/src/test/mir-opt/early_otherwise_branch_noopt.rs @@ -13,16 +13,6 @@ fn noopt1(x: Option<u32>, y: Option<u32>) -> u32 { } } -// must not optimize as the types being matched on are not identical -// EMIT_MIR early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff -fn noopt2(x: Option<u32>, y: Option<bool>) -> u32 { - match (x, y) { - (Some(a), Some(b)) => 0, - _ => 1, - } -} - fn main() { noopt1(None, Some(0)); - noopt2(None, Some(true)); } diff --git a/src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff new file mode 100644 index 00000000000..a2722660662 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff @@ -0,0 +1,43 @@ +- // MIR for `no_deref_ptr` before EarlyOtherwiseBranch ++ // MIR for `no_deref_ptr` after EarlyOtherwiseBranch + + fn no_deref_ptr(_1: Option<i32>, _2: *const Option<i32>) -> i32 { + debug a => _1; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:18:24: 18:25 + debug b => _2; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:18:40: 18:41 + let mut _0: i32; // return place in scope 0 at $DIR/early_otherwise_branch_soundness.rs:18:66: 18:69 + let mut _3: isize; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:21:9: 21:16 + let mut _4: isize; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:13: 22:20 + let _5: i32; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19 + scope 1 { + debug v => _5; // in scope 1 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19 + } + + bb0: { + _3 = discriminant(_1); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:19:11: 19:12 + switchInt(move _3) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:19:5: 19:12 + } + + bb1: { + _0 = const 0_i32; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:25:14: 25:15 + return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:25:14: 25:15 + } + + bb2: { + _4 = discriminant((*_2)); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:21:26: 21:28 + switchInt(move _4) -> [1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:21:20: 21:28 + } + + bb3: { + _0 = const 0_i32; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:23:18: 23:19 + return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:23:18: 23:19 + } + + bb4: { + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19 + _5 = (((*_2) as Some).0: i32); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19 + _0 = _5; // scope 1 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25 + return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff new file mode 100644 index 00000000000..56b7c9a2db4 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff @@ -0,0 +1,30 @@ +- // MIR for `no_downcast` before EarlyOtherwiseBranch ++ // MIR for `no_downcast` after EarlyOtherwiseBranch + + fn no_downcast(_1: &E) -> u32 { + debug e => _1; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:12:16: 12:17 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_soundness.rs:12:26: 12:29 + let mut _2: isize; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:20: 13:30 + let mut _3: isize; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 + + bb0: { + _3 = discriminant((*_1)); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 + switchInt(move _3) -> [1_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 + } + + bb1: { + _2 = discriminant((*(((*_1) as Some).0: &E))); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 + switchInt(move _2) -> [1_isize: bb2, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 + } + + bb2: { + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:38: 13:39 + return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52 + } + + bb3: { + _0 = const 2_u32; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:49: 13:50 + return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_soundness.rs b/src/test/mir-opt/early_otherwise_branch_soundness.rs new file mode 100644 index 00000000000..d2513213d79 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_soundness.rs @@ -0,0 +1,32 @@ +// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts + +// Tests various cases that the `early_otherwise_branch` opt should *not* optimize + +// From #78496 +enum E<'a> { + Empty, + Some(&'a E<'a>), +} + +// EMIT_MIR early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff +fn no_downcast(e: &E) -> u32 { + if let E::Some(E::Some(_)) = e { 1 } else { 2 } +} + +// SAFETY: if `a` is `Some`, `b` must point to a valid, initialized value +// EMIT_MIR early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff +unsafe fn no_deref_ptr(a: Option<i32>, b: *const Option<i32>) -> i32 { + match a { + // `*b` being correct depends on `a == Some(_)` + Some(_) => match *b { + Some(v) => v, + _ => 0, + }, + _ => 0, + } +} + +fn main() { + no_downcast(&E::Empty); + unsafe { no_deref_ptr(None, std::ptr::null()) }; +} diff --git a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir index 486fc7541c3..5e3ec0889e9 100644 --- a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir @@ -38,7 +38,7 @@ fn bar() -> bool { // + val: Unevaluated(bar, [], Some(promoted[1])) // mir::Constant // + span: $DIR/inline-retag.rs:12:7: 12:9 - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[HASH]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[1]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[86d7]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[1]) }) } Retag(_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 _4 = &(*_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 Retag(_4); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 @@ -52,7 +52,7 @@ fn bar() -> bool { // + val: Unevaluated(bar, [], Some(promoted[0])) // mir::Constant // + span: $DIR/inline-retag.rs:12:11: 12:14 - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[HASH]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[86d7]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } Retag(_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 _7 = &(*_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 Retag(_7); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff index 7938c0a23e8..016e0cb5901 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff @@ -66,7 +66,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[9565]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _8 = _20; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_6.0: &i32) = move _7; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_6.1: &i32) = move _8; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff index 7938c0a23e8..016e0cb5901 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff @@ -66,7 +66,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[9565]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _8 = _20; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_6.0: &i32) = move _7; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_6.1: &i32) = move _8; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff index 20771bf4231..59daeb1e997 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff @@ -87,7 +87,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[9565]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _11 = _28; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff index 20771bf4231..59daeb1e997 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff @@ -87,7 +87,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[9565]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _11 = _28; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL diff --git a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff index 75d0e75f5b1..644a5593a9d 100644 --- a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff @@ -50,7 +50,7 @@ // + val: Unevaluated(discriminant, [T], Some(promoted[2])) // mir::Constant // + span: $DIR/lower_intrinsics.rs:75:42: 75:44 - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[HASH]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[2]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[49eb]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[2]) }) } _7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44 _6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44 - _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45 @@ -74,7 +74,7 @@ // + val: Unevaluated(discriminant, [T], Some(promoted[1])) // mir::Constant // + span: $DIR/lower_intrinsics.rs:76:42: 76:45 - // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[HASH]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[1]) }) } + // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[49eb]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[1]) }) } _11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45 _10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45 - _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46 @@ -98,7 +98,7 @@ // + val: Unevaluated(discriminant, [T], Some(promoted[0])) // mir::Constant // + span: $DIR/lower_intrinsics.rs:77:42: 77:47 - // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[HASH]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[49eb]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[0]) }) } _15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47 _14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47 - _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48 diff --git a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir index 51425af4bdf..b3a9365396c 100644 --- a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir +++ b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir @@ -57,7 +57,7 @@ fn full_tested_match() -> () { // + val: Unevaluated(full_tested_match, [], Some(promoted[0])) // mir::Constant // + span: $DIR/match_false_edges.rs:16:14: 16:15 - // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ match_false_edges[HASH]::full_tested_match), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ match_false_edges[5411]::full_tested_match), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _6 = &(((*_11) as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15 _4 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27 StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27 diff --git a/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir b/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir index bfc85e98786..975e2ffbf01 100644 --- a/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir +++ b/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir @@ -2,8 +2,8 @@ | Free Region Mapping | '_#0r | Global | ['_#2r, '_#1r, '_#0r, '_#4r, '_#3r] -| '_#1r | External | ['_#1r, '_#4r] -| '_#2r | External | ['_#2r, '_#1r, '_#4r] +| '_#1r | Local | ['_#1r, '_#4r] +| '_#2r | Local | ['_#2r, '_#1r, '_#4r] | '_#3r | Local | ['_#4r, '_#3r] | '_#4r | Local | ['_#4r] | diff --git a/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir index 1db36c352ff..54d836ba609 100644 --- a/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir @@ -127,7 +127,7 @@ fn array_casts() -> () { // + val: Unevaluated(array_casts, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &usize, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:15 ~ retag[HASH]::array_casts), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &usize, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:15 ~ retag[4622]::array_casts), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } Retag(_35); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _18 = &(*_35); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL Retag(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL diff --git a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir index cffe7238987..29a72feed7d 100644 --- a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir @@ -113,7 +113,7 @@ fn main() -> () { StorageLive(_14); // scope 1 at $DIR/retag.rs:40:31: 43:6 _14 = [closure@main::{closure#0}]; // scope 1 at $DIR/retag.rs:40:31: 43:6 // closure - // + def_id: DefId(0:14 ~ retag[HASH]::main::{closure#0}) + // + def_id: DefId(0:14 ~ retag[4622]::main::{closure#0}) // + substs: [ // i8, // for<'r> extern "rust-call" fn((&'r i32,)) -> &'r i32, @@ -153,7 +153,7 @@ fn main() -> () { // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/retag.rs:47:21: 47:23 - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:13 ~ retag[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:13 ~ retag[4622]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } Retag(_28); // scope 7 at $DIR/retag.rs:47:21: 47:23 _23 = &(*_28); // scope 7 at $DIR/retag.rs:47:21: 47:23 Retag(_23); // scope 7 at $DIR/retag.rs:47:21: 47:23 diff --git a/src/test/pretty/ast-stmt-expr-attr.rs b/src/test/pretty/ast-stmt-expr-attr.rs index e32f5ca24ea..2404b321942 100644 --- a/src/test/pretty/ast-stmt-expr-attr.rs +++ b/src/test/pretty/ast-stmt-expr-attr.rs @@ -28,67 +28,67 @@ fn syntax() { let _ = #[attr] (x as Y); let _ = #[attr] while true { - #![attr] - }; + #![attr] + }; let _ = #[attr] while let Some(false) = true { - #![attr] - }; + #![attr] + }; let _ = #[attr] for x in y { - #![attr] - }; + #![attr] + }; let _ = #[attr] loop { - #![attr] - }; + #![attr] + }; let _ = #[attr] match true { - #![attr] - #[attr] - _ => false, - }; + #![attr] + #[attr] + _ => false, + }; let _ = #[attr] || #[attr] foo; let _ = #[attr] move || #[attr] foo; let _ = #[attr] || - #[attr] { - #![attr] - foo - }; + #[attr] { + #![attr] + foo + }; let _ = #[attr] move || - #[attr] { - #![attr] - foo - }; + #[attr] { + #![attr] + foo + }; let _ = #[attr] || - { - #![attr] - foo - }; + { + #![attr] + foo + }; let _ = #[attr] move || - { - #![attr] - foo - }; + { + #![attr] + foo + }; let _ = #[attr] { - #![attr] - }; + #![attr] + }; let _ = #[attr] { - #![attr] - let _ = (); - }; + #![attr] + let _ = (); + }; let _ = #[attr] { - #![attr] - let _ = (); - foo - }; + #![attr] + let _ = (); + foo + }; let _ = #[attr] x = y; let _ = #[attr] (x = y); let _ = #[attr] x += y; diff --git a/src/test/pretty/block-comment-wchar.pp b/src/test/pretty/block-comment-wchar.pp index 385afa4f33e..8c8580b07c2 100644 --- a/src/test/pretty/block-comment-wchar.pp +++ b/src/test/pretty/block-comment-wchar.pp @@ -93,9 +93,9 @@ fn main() { // Taken from https://www.unicode.org/Public/UNIDATA/PropList.txt let chars = ['\x0A', '\x0B', '\x0C', '\x0D', '\x20', '\u{85}', '\u{A0}', - '\u{1680}', '\u{2000}', '\u{2001}', '\u{2002}', '\u{2003}', - '\u{2004}', '\u{2005}', '\u{2006}', '\u{2007}', '\u{2008}', - '\u{2009}', '\u{200A}', '\u{2028}', '\u{2029}', '\u{202F}', - '\u{205F}', '\u{3000}']; + '\u{1680}', '\u{2000}', '\u{2001}', '\u{2002}', '\u{2003}', + '\u{2004}', '\u{2005}', '\u{2006}', '\u{2007}', '\u{2008}', + '\u{2009}', '\u{200A}', '\u{2028}', '\u{2029}', '\u{202F}', + '\u{205F}', '\u{3000}']; for c in &chars { let ws = c.is_whitespace(); println!("{} {}", c, ws); } } diff --git a/src/test/pretty/delimited-token-groups.rs b/src/test/pretty/delimited-token-groups.rs index 1137d804564..c7c9277faf6 100644 --- a/src/test/pretty/delimited-token-groups.rs +++ b/src/test/pretty/delimited-token-groups.rs @@ -17,9 +17,9 @@ mac! { mac! { a(aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa - aaaaaaaa aaaaaaaa) a + aaaaaaaa aaaaaaaa) a [aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa - aaaaaaaa aaaaaaaa] a + aaaaaaaa aaaaaaaa] a { aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa @@ -27,22 +27,22 @@ mac! { } mac!(aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa - aaaaaaaa aaaaaaaa); +aaaaaaaa aaaaaaaa); mac![aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa - aaaaaaaa aaaaaaaa]; +aaaaaaaa aaaaaaaa]; mac! { aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa } #[rustc_dummy(aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa - aaaaaaaa aaaaaaaa aaaaaaaa)] +aaaaaaaa aaaaaaaa aaaaaaaa)] #[rustc_dummy[aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa - aaaaaaaa aaaaaaaa aaaaaaaa]] +aaaaaaaa aaaaaaaa aaaaaaaa]] #[rustc_dummy { - aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa - aaaaaaaa aaaaaaaa - }] + aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa + aaaaaaaa aaaaaaaa +}] #[rustc_dummy = - "aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa"] +"aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa"] fn main() {} diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 93967e720c1..3830c3aa6c9 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -11,15 +11,15 @@ extern crate std; pub fn foo(_: [i32; (3 as usize)]) ({ } as ()) pub fn bar() ({ - const FOO: usize = ((5 as usize) - (4 as usize) as usize); - let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]); + const FOO: usize = ((5 as usize) - (4 as usize) as usize); + let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]); - let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]); + let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]); - let _ = - (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) - as &[i32; 3]) as *const _ as *const [i32; 3]) as - *const [i32; (3 as usize)] as *const [i32; 3]); + let _ = + (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) as + &[i32; 3]) as *const _ as *const [i32; 3]) as + *const [i32; (3 as usize)] as *const [i32; 3]); @@ -29,29 +29,19 @@ pub fn bar() ({ - ({ - let res = - ((::alloc::fmt::format as - for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1 - as - fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test" - as - &str)] - as - [&str; 1]) - as - &[&str; 1]), - (&([] - as - [ArgumentV1; 0]) - as - &[ArgumentV1; 0])) - as - Arguments)) - as String); - (res as String) - } as String); - } as ()) + ({ + let res = + ((::alloc::fmt::format as + for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1 + as + fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test" + as &str)] as [&str; 1]) as + &[&str; 1]), + (&([] as [ArgumentV1; 0]) as &[ArgumentV1; 0])) as + Arguments)) as String); + (res as String) + } as String); + } as ()) pub type Foo = [i32; (3 as usize)]; pub struct Bar { pub x: [i32; (3 as usize)], @@ -60,19 +50,9 @@ pub struct TupleBar([i32; (4 as usize)]); pub enum Baz { BazVariant([i32; (5 as usize)]), } pub fn id<T>(x: T) -> T ({ (x as T) } as T) pub fn use_id() ({ - let _ = - ((id::<[i32; (3 as usize)]> as - fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 - as - i32), - (2 - as - i32), - (3 - as - i32)] - as - [i32; 3])) - as [i32; 3]); - } as ()) + let _ = + ((id::<[i32; (3 as usize)]> as + fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 as i32), + (2 as i32), (3 as i32)] as [i32; 3])) as [i32; 3]); + } as ()) fn main() ({ } as ()) diff --git a/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs b/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs index ed7879001d5..87f525a6178 100644 --- a/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs +++ b/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs @@ -9,8 +9,8 @@ struct C { #[allow()] const C: C = C{ - #[cfg(debug_assertions)] - field: 0, + #[cfg(debug_assertions)] + field: 0, - #[cfg(not(debug_assertions))] - field: 1,}; + #[cfg(not(debug_assertions))] + field: 1,}; diff --git a/src/test/pretty/macro_rules.rs b/src/test/pretty/macro_rules.rs index fb66e4a7758..01adb14133b 100644 --- a/src/test/pretty/macro_rules.rs +++ b/src/test/pretty/macro_rules.rs @@ -12,8 +12,8 @@ macro_rules! matcher_brackets { macro_rules! all_fragments { ($b : block, $e : expr, $i : ident, $it : item, $l : lifetime, $lit : - literal, $m : meta, $p : pat, $pth : path, $s : stmt, $tt : tt, $ty : ty, - $vis : vis) => {} ; + literal, $m : meta, $p : pat, $pth : path, $s : stmt, $tt : tt, $ty : ty, + $vis : vis) => {} ; } fn main() {} diff --git a/src/test/pretty/match-naked-expr-medium.rs b/src/test/pretty/match-naked-expr-medium.rs index a124fdff390..836af99002d 100644 --- a/src/test/pretty/match-naked-expr-medium.rs +++ b/src/test/pretty/match-naked-expr-medium.rs @@ -5,10 +5,10 @@ fn main() { let _y = match x { Some(_) => - ["some(_)".to_string(), "not".to_string(), "SO".to_string(), - "long".to_string(), "string".to_string()], + ["some(_)".to_string(), "not".to_string(), "SO".to_string(), + "long".to_string(), "string".to_string()], None => - ["none".to_string(), "a".to_string(), "a".to_string(), - "a".to_string(), "a".to_string()], + ["none".to_string(), "a".to_string(), "a".to_string(), + "a".to_string(), "a".to_string()], }; } diff --git a/src/test/pretty/stmt_expr_attributes.rs b/src/test/pretty/stmt_expr_attributes.rs index 01533cd8107..96bde96200a 100644 --- a/src/test/pretty/stmt_expr_attributes.rs +++ b/src/test/pretty/stmt_expr_attributes.rs @@ -48,9 +48,9 @@ fn _4() { let _ = #[rustc_dummy] match () { - #![rustc_dummy] - () => (), - }; + #![rustc_dummy] + () => (), + }; } fn _5() { @@ -156,56 +156,56 @@ fn _11() { let _ = #[rustc_dummy] 0 as usize; let _ = #[rustc_dummy] while false { - #![rustc_dummy] - }; + #![rustc_dummy] + }; let _ = #[rustc_dummy] while let None = Some(()) { - #![rustc_dummy] - }; + #![rustc_dummy] + }; let _ = #[rustc_dummy] for _ in 0..0 { - #![rustc_dummy] - }; + #![rustc_dummy] + }; let _ = #[rustc_dummy] loop { - #![rustc_dummy] - }; + #![rustc_dummy] + }; let _ = #[rustc_dummy] match false { - #![rustc_dummy] - _ => (), - }; + #![rustc_dummy] + _ => (), + }; let _ = #[rustc_dummy] || #[rustc_dummy] (); let _ = #[rustc_dummy] move || #[rustc_dummy] (); let _ = #[rustc_dummy] || - { - #![rustc_dummy] - #[rustc_dummy] - () - }; + { + #![rustc_dummy] + #[rustc_dummy] + () + }; let _ = #[rustc_dummy] move || - { - #![rustc_dummy] - #[rustc_dummy] - () - }; + { + #![rustc_dummy] + #[rustc_dummy] + () + }; let _ = #[rustc_dummy] { - #![rustc_dummy] - }; + #![rustc_dummy] + }; let _ = #[rustc_dummy] { - #![rustc_dummy] - let _ = (); - }; + #![rustc_dummy] + let _ = (); + }; let _ = #[rustc_dummy] { - #![rustc_dummy] - let _ = (); - () - }; + #![rustc_dummy] + let _ = (); + () + }; let mut x = 0; let _ = #[rustc_dummy] x = 15; let _ = #[rustc_dummy] x += 15; diff --git a/src/test/pretty/vec-comments.pp b/src/test/pretty/vec-comments.pp index a150cf0b8ea..f2f807c59de 100644 --- a/src/test/pretty/vec-comments.pp +++ b/src/test/pretty/vec-comments.pp @@ -4,26 +4,26 @@ fn main() { let _v1 = [ - // Comment - 0, - // Comment - 1, - // Comment - 2]; + // Comment + 0, + // Comment + 1, + // Comment + 2]; let _v2 = [0, // Comment - 1, // Comment - 2]; // Comment + 1, // Comment + 2]; // Comment let _v3 = [ - /* Comment */ - 0, - /* Comment */ - 1, - /* Comment */ - 2]; + /* Comment */ + 0, + /* Comment */ + 1, + /* Comment */ + 2]; let _v4 = [0, /* Comment */ - 1, /* Comment */ - 2]; /* Comment */ + 1, /* Comment */ + 2]; /* Comment */ } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt index 7eb393bb448..e463099a5ee 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt @@ -29,8 +29,8 @@ 29| 1| some_string = Some(String::from("the string content")); 30| 1| let 31| 1| a - 32| | = - 33| | || + 32| 1| = + 33| 1| || 34| 0| { 35| 0| let mut countdown = 0; 36| 0| if is_false { @@ -116,8 +116,8 @@ 116| 1| 117| 1| let 118| 1| _unused_closure - 119| 1| = - 120| 1| | + 119| | = + 120| | | 121| | mut countdown 122| | | 123| 0| { diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-93054.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-93054.txt new file mode 100644 index 00000000000..a1655adedd4 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-93054.txt @@ -0,0 +1,29 @@ + 1| |// Regression test for #93054: Functions using uninhabited types often only have a single, + 2| |// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail. + 3| |// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them. + 4| | + 5| |// compile-flags: --edition=2021 + 6| | + 7| |enum Never { } + 8| | + 9| |impl Never { + 10| | fn foo(self) { + 11| | match self { } + 12| | make().map(|never| match never { }); + 13| | } + 14| | + 15| | fn bar(&self) { + 16| | match *self { } + 17| | } + 18| |} + 19| | + 20| 0|async fn foo2(never: Never) { + 21| | match never { } + 22| |} + 23| | + 24| 0|fn make() -> Option<Never> { + 25| 0| None + 26| 0|} + 27| | + 28| 1|fn main() { } + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt index 768dcb2f608..c2d5143a618 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -19,12 +19,12 @@ 18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); 19| 2|} ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>: + | used_crate::used_only_from_bin_crate_generic_function::<&str>: | 17| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) { | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 19| 1|} ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&str>: + | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>: | 17| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) { | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 19| 1|} @@ -36,12 +36,12 @@ 22| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); 23| 2|} ------------------ - | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>: + | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: | 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) { | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 23| 1|} ------------------ - | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: + | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>: | 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) { | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 23| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt index 89636294035..dab31cbf4ac 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt @@ -42,12 +42,12 @@ 40| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); 41| 2|} ------------------ - | used_inline_crate::used_only_from_bin_crate_generic_function::<&str>: + | used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>: | 39| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) { | 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 41| 1|} ------------------ - | used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>: + | used_inline_crate::used_only_from_bin_crate_generic_function::<&str>: | 39| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) { | 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 41| 1|} @@ -61,12 +61,12 @@ 46| 4| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); 47| 4|} ------------------ - | used_inline_crate::used_only_from_this_lib_crate_generic_function::<&str>: + | used_inline_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>: | 45| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) { | 46| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 47| 2|} ------------------ - | used_inline_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>: + | used_inline_crate::used_only_from_this_lib_crate_generic_function::<&str>: | 45| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) { | 46| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 47| 2|} diff --git a/src/test/run-make-fulldeps/coverage/issue-93054.rs b/src/test/run-make-fulldeps/coverage/issue-93054.rs new file mode 100644 index 00000000000..c160b3db03f --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/issue-93054.rs @@ -0,0 +1,28 @@ +// Regression test for #93054: Functions using uninhabited types often only have a single, +// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail. +// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them. + +// compile-flags: --edition=2021 + +enum Never { } + +impl Never { + fn foo(self) { + match self { } + make().map(|never| match never { }); + } + + fn bar(&self) { + match *self { } + } +} + +async fn foo2(never: Never) { + match never { } +} + +fn make() -> Option<Never> { + None +} + +fn main() { } diff --git a/src/test/run-make/const_fn_mir/dump.mir b/src/test/run-make/const_fn_mir/dump.mir index 724b2630083..f02bccc4b2d 100644 --- a/src/test/run-make/const_fn_mir/dump.mir +++ b/src/test/run-make/const_fn_mir/dump.mir @@ -1,21 +1,5 @@ // WARNING: This output format is intended for human consumers only // and is subject to change without notice. Knock yourself out. -fn main() -> () { - let mut _0: (); // return place in scope 0 at main.rs:8:11: 8:11 - let _1: i32; // in scope 0 at main.rs:9:5: 9:10 - - bb0: { - _1 = foo() -> bb1; // scope 0 at main.rs:9:5: 9:10 - // mir::Constant - // + span: main.rs:9:5: 9:8 - // + literal: Const { ty: fn() -> i32 {foo}, val: Value(Scalar(<ZST>)) } - } - - bb1: { - return; // scope 0 at main.rs:10:2: 10:2 - } -} - fn foo() -> i32 { let mut _0: i32; // return place in scope 0 at main.rs:4:19: 4:22 @@ -40,3 +24,19 @@ fn foo() -> i32 { return; // scope 0 at main.rs:6:2: 6:2 } } + +fn main() -> () { + let mut _0: (); // return place in scope 0 at main.rs:8:11: 8:11 + let _1: i32; // in scope 0 at main.rs:9:5: 9:10 + + bb0: { + _1 = foo() -> bb1; // scope 0 at main.rs:9:5: 9:10 + // mir::Constant + // + span: main.rs:9:5: 9:8 + // + literal: Const { ty: fn() -> i32 {foo}, val: Value(Scalar(<ZST>)) } + } + + bb1: { + return; // scope 0 at main.rs:10:2: 10:2 + } +} diff --git a/src/test/rustdoc-gui/anchors.goml b/src/test/rustdoc-gui/anchors.goml index 2d48d21dc1b..26e4503a5d0 100644 --- a/src/test/rustdoc-gui/anchors.goml +++ b/src/test/rustdoc-gui/anchors.goml @@ -20,7 +20,7 @@ assert-css: (".srclink", {"text-decoration": "underline solid rgb(56, 115, 173)" assert-css: ("#top-doc-prose-title", {"color": "rgb(0, 0, 0)"}) -assert-css: (".sidebar a", {"color": "rgb(56, 115, 173)"}) +assert-css: (".sidebar a", {"color": "rgb(53, 109, 164)"}) assert-css: (".in-band a", {"color": "rgb(0, 0, 0)"}) // We move the cursor over the "Implementations" title so the anchor is displayed. diff --git a/src/test/rustdoc-gui/check_info_sign_position.goml b/src/test/rustdoc-gui/check_info_sign_position.goml index 94e3fe79c94..3bed7a0a03e 100644 --- a/src/test/rustdoc-gui/check_info_sign_position.goml +++ b/src/test/rustdoc-gui/check_info_sign_position.goml @@ -1,3 +1,5 @@ +// This test checks the position of the information on the code blocks (like +// `compile_fail` or `ignore`). goto: file://|DOC_PATH|/test_docs/index.html goto: ./fn.check_list_code_block.html // If the codeblock is the first element of the docblock, the information tooltip must have diff --git a/src/test/rustdoc-gui/code-sidebar-toggle.goml b/src/test/rustdoc-gui/code-sidebar-toggle.goml index 6fb92e19660..1818f0dbcdf 100644 --- a/src/test/rustdoc-gui/code-sidebar-toggle.goml +++ b/src/test/rustdoc-gui/code-sidebar-toggle.goml @@ -1,3 +1,4 @@ +// This test checks that the source code pages sidebar toggle is working as expected. goto: file://|DOC_PATH|/test_docs/index.html click: ".srclink" wait-for: "#sidebar-toggle" diff --git a/src/test/rustdoc-gui/escape-key.goml b/src/test/rustdoc-gui/escape-key.goml index 712920b16a9..9cff12f3e41 100644 --- a/src/test/rustdoc-gui/escape-key.goml +++ b/src/test/rustdoc-gui/escape-key.goml @@ -1,3 +1,5 @@ +// This test ensures that the "Escape" shortcut is handled correctly based on the +// current content displayed. goto: file://|DOC_PATH|/test_docs/index.html // First, we check that the search results are hidden when the Escape key is pressed. write: (".search-input", "test") diff --git a/src/test/rustdoc-gui/font-weight.goml b/src/test/rustdoc-gui/font-weight.goml index a64ac8b422f..5f29fde6689 100644 --- a/src/test/rustdoc-gui/font-weight.goml +++ b/src/test/rustdoc-gui/font-weight.goml @@ -1,5 +1,5 @@ -goto: file://|DOC_PATH|/lib2/struct.Foo.html // This test checks that the font weight is correctly applied. +goto: file://|DOC_PATH|/lib2/struct.Foo.html assert-css: ("//*[@class='docblock item-decl']//a[text()='Alias']", {"font-weight": "400"}) assert-css: ( "//*[@class='structfield small-section-header']//a[text()='Alias']", diff --git a/src/test/rustdoc-gui/huge-collection-of-constants.goml b/src/test/rustdoc-gui/huge-collection-of-constants.goml index 4f7fe7a212c..4f75b5841ee 100644 --- a/src/test/rustdoc-gui/huge-collection-of-constants.goml +++ b/src/test/rustdoc-gui/huge-collection-of-constants.goml @@ -1,7 +1,7 @@ -goto: file://|DOC_PATH|/test_docs/huge_amount_of_consts/index.html - // Make sure that the last two entries are more than 12 pixels apart and not stacked on each other. +goto: file://|DOC_PATH|/test_docs/huge_amount_of_consts/index.html + compare-elements-position-near-false: ( "//*[@class='item-table']//div[last()-1]", "//*[@class='item-table']//div[last()-3]", diff --git a/src/test/rustdoc-gui/list_code_block.goml b/src/test/rustdoc-gui/list_code_block.goml index 7d3490e9d94..eba1a662b9f 100644 --- a/src/test/rustdoc-gui/list_code_block.goml +++ b/src/test/rustdoc-gui/list_code_block.goml @@ -1,3 +1,4 @@ +// This test checks that code blocks in list are supported. goto: file://|DOC_PATH|/test_docs/index.html goto: ./fn.check_list_code_block.html assert: ("pre.rust.fn") diff --git a/src/test/rustdoc-gui/mobile.goml b/src/test/rustdoc-gui/mobile.goml index acde1123925..8f9c9248f5f 100644 --- a/src/test/rustdoc-gui/mobile.goml +++ b/src/test/rustdoc-gui/mobile.goml @@ -2,6 +2,8 @@ goto: file://|DOC_PATH|/staged_api/struct.Foo.html size: (400, 600) +font-size: 18 + // The out-of-band info (source, stable version, collapse) should be below the // h1 when the screen gets narrow enough. assert-css: (".main-heading", { @@ -9,6 +11,8 @@ assert-css: (".main-heading", { "flex-direction": "column" }) +assert-property: (".mobile-topbar h2.location", {"offsetHeight": 45}) + // Note: We can't use assert-text here because the 'Since' is set by CSS and // is therefore not part of the DOM. assert-css: (".content .out-of-band .since::before", { "content": "\"Since \"" }) diff --git a/src/test/rustdoc-gui/search-filter.goml b/src/test/rustdoc-gui/search-filter.goml index e5cdf3ea7a1..98ca40512ee 100644 --- a/src/test/rustdoc-gui/search-filter.goml +++ b/src/test/rustdoc-gui/search-filter.goml @@ -1,3 +1,4 @@ +// Checks that the crate search filtering is handled correctly and changes the results. goto: file://|DOC_PATH|/test_docs/index.html show-text: true write: (".search-input", "test") diff --git a/src/test/rustdoc-gui/search-result-colors.goml b/src/test/rustdoc-gui/search-result-colors.goml index b4eb896af1c..872df5fc3f9 100644 --- a/src/test/rustdoc-gui/search-result-colors.goml +++ b/src/test/rustdoc-gui/search-result-colors.goml @@ -1,3 +1,4 @@ +// Checks that the result colors are as expected. goto: file://|DOC_PATH|/test_docs/index.html // We set the theme so we're sure that the correct values will be used, whatever the computer // this test is running on. diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml index 3162a067d21..823ea67b1b0 100644 --- a/src/test/rustdoc-gui/search-result-display.goml +++ b/src/test/rustdoc-gui/search-result-display.goml @@ -1,3 +1,4 @@ +// Checks that the search results have the expected width. goto: file://|DOC_PATH|/test_docs/index.html size: (900, 1000) write: (".search-input", "test") diff --git a/src/test/rustdoc-gui/search-result-keyword.goml b/src/test/rustdoc-gui/search-result-keyword.goml index 5342d431d99..8b50c5c5e1a 100644 --- a/src/test/rustdoc-gui/search-result-keyword.goml +++ b/src/test/rustdoc-gui/search-result-keyword.goml @@ -1,3 +1,4 @@ +// Checks that the "keyword" results have the expected text alongside them. goto: file://|DOC_PATH|/test_docs/index.html write: (".search-input", "CookieMonster") // Waiting for the search results to appear... diff --git a/src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml b/src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml index a61ec672ae6..52b3ceae7b1 100644 --- a/src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml +++ b/src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml @@ -1,3 +1,5 @@ +// Checks that the first non-empty search result tab is selected if the default/currently selected +// one is empty. goto: file://|DOC_PATH|/test_docs/index.html write: (".search-input", "Foo") // Waiting for the search results to appear... diff --git a/src/test/rustdoc-gui/sidebar-mobile.goml b/src/test/rustdoc-gui/sidebar-mobile.goml index 680822b6ecb..60bcffe120b 100644 --- a/src/test/rustdoc-gui/sidebar-mobile.goml +++ b/src/test/rustdoc-gui/sidebar-mobile.goml @@ -35,3 +35,8 @@ assert-property: (".mobile-topbar", {"clientHeight": "45"}) click: ".sidebar-menu-toggle" click: ".sidebar-links a" assert-position: ("#method\.must_use", {"y": 45}) + +// Check that the bottom-most item on the sidebar menu can be scrolled fully into view. +click: ".sidebar-menu-toggle" +scroll-to: ".block.keyword li:nth-child(1)" +assert-position: (".block.keyword li:nth-child(1)", {"y": 542.96875}) diff --git a/src/test/rustdoc-gui/sidebar.goml b/src/test/rustdoc-gui/sidebar.goml index a1175525858..ef3a92ad7a6 100644 --- a/src/test/rustdoc-gui/sidebar.goml +++ b/src/test/rustdoc-gui/sidebar.goml @@ -1,3 +1,4 @@ +// Checks multiple things on the sidebar display (width of its elements, colors, etc). goto: file://|DOC_PATH|/test_docs/index.html show-text: true local-storage: {"rustdoc-theme": "light"} @@ -8,7 +9,7 @@ assert-text: (".sidebar > .location", "Crate test_docs") // In modules, we only have one "location" element. assert-count: (".sidebar .location", 1) assert-text: ("#all-types", "All Items") -assert-css: ("#all-types", {"color": "rgb(56, 115, 173)"}) +assert-css: ("#all-types", {"color": "rgb(53, 109, 164)"}) // We check that we have the crates list and that the "current" on is "test_docs". assert-text: (".sidebar-elems .crate > ul > li > a.current", "test_docs") // And we're also supposed to have the list of items in the current module. @@ -37,7 +38,7 @@ assert-property: ("html", {"scrollTop": "0"}) // We now go back to the crate page to click on the "lib2" crate link. goto: file://|DOC_PATH|/test_docs/index.html -assert-css: (".sidebar-elems .crate > ul > li:first-child > a", {"color": "rgb(56, 115, 173)"}) +assert-css: (".sidebar-elems .crate > ul > li:first-child > a", {"color": "rgb(53, 109, 164)"}) click: ".sidebar-elems .crate > ul > li:first-child > a" // PAGE: lib2/index.html @@ -73,3 +74,7 @@ assert-text: (".sidebar > .location", "Module sub_sub_module") assert-false: ".sidebar-elems .crate" assert-text: (".sidebar-elems .items > ul > li:nth-child(1)", "Functions") assert-text: ("#functions + .item-table .item-left > a", "foo") + +// Links to trait implementations in the sidebar should not wrap even if they are long. +goto: file://|DOC_PATH|/lib2/struct.HasALongTraitWithParams.html +assert-property: (".sidebar-links a", {"offsetHeight": 29}) diff --git a/src/test/rustdoc-gui/source-code-page.goml b/src/test/rustdoc-gui/source-code-page.goml index f3682f59d21..375ff4878e5 100644 --- a/src/test/rustdoc-gui/source-code-page.goml +++ b/src/test/rustdoc-gui/source-code-page.goml @@ -1,3 +1,4 @@ +// Checks that the interactions with the source code pages are workined as expected. goto: file://|DOC_PATH|/src/test_docs/lib.rs.html // Check that we can click on the line number. click: ".line-numbers > span:nth-child(4)" // This is the span for line 4. diff --git a/src/test/rustdoc-gui/src/lib2/lib.rs b/src/test/rustdoc-gui/src/lib2/lib.rs index 79354ec8745..5b6d236e8e0 100644 --- a/src/test/rustdoc-gui/src/lib2/lib.rs +++ b/src/test/rustdoc-gui/src/lib2/lib.rs @@ -39,7 +39,6 @@ impl Trait for Foo { const Y: u32 = 0; } - impl implementors::Whatever for Foo { type Foo = u32; } @@ -58,8 +57,10 @@ pub mod sub_mod { pub mod long_trait { use std::ops::DerefMut; - pub trait ALongNameBecauseItHelpsTestingTheCurrentProblem: DerefMut<Target = u32> - + From<u128> + Send + Sync + AsRef<str> + 'static {} + pub trait ALongNameBecauseItHelpsTestingTheCurrentProblem: + DerefMut<Target = u32> + From<u128> + Send + Sync + AsRef<str> + 'static + { + } } pub mod long_table { @@ -88,18 +89,34 @@ pub mod summary_table { } pub mod too_long { -pub type ReallyLongTypeNameLongLongLong = Option<unsafe extern "C" fn(a: *const u8, b: *const u8) -> *const u8>; - -pub const ReallyLongTypeNameLongLongLongConstBecauseWhyNotAConstRightGigaGigaSupraLong: u32 = 0; - -pub struct SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName { - pub a: u32, -} + pub type ReallyLongTypeNameLongLongLong = + Option<unsafe extern "C" fn(a: *const u8, b: *const u8) -> *const u8>; + + pub const ReallyLongTypeNameLongLongLongConstBecauseWhyNotAConstRightGigaGigaSupraLong: u32 = 0; + + /// This also has a really long doccomment. Lorem ipsum dolor sit amet, + /// consectetur adipiscing elit. Suspendisse id nibh malesuada, hendrerit + /// massa vel, tincidunt est. Nulla interdum, sem ac efficitur ornare, arcu + /// nunc dignissim nibh, at rutrum diam augue ac mauris. Fusce tincidunt et + /// ligula sed viverra. Aenean sed facilisis dui, non volutpat felis. In + /// vitae est dui. Donec felis nibh, blandit at nibh eu, tempor suscipit + /// nisl. Vestibulum ornare porta libero, eu faucibus purus iaculis ut. Ut + /// quis tincidunt nunc, in mollis purus. Nulla sed interdum quam. Nunc + /// vitae cursus ex. + pub struct SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName { + pub a: u32, + } -impl SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName { - /// ``` - /// let x = SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName { a: 0 }; - /// ``` + impl SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName { + /// ``` + /// let x = SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName { a: 0 }; + /// ``` pub fn foo(&self) {} } } + +pub struct HasALongTraitWithParams {} + +pub trait LongTraitWithParamsBananaBananaBanana<T> {} + +impl LongTraitWithParamsBananaBananaBanana<usize> for HasALongTraitWithParams {} diff --git a/src/test/rustdoc-gui/theme-change.goml b/src/test/rustdoc-gui/theme-change.goml index 5221cda2f1f..73edee64e43 100644 --- a/src/test/rustdoc-gui/theme-change.goml +++ b/src/test/rustdoc-gui/theme-change.goml @@ -1,3 +1,4 @@ +// Ensures that the theme change is working as expected. goto: file://|DOC_PATH|/test_docs/index.html click: "#theme-picker" click: "#theme-choices > button:first-child" @@ -8,3 +9,19 @@ click: "#theme-choices > button:last-child" wait-for: 500 // should be the light theme so let's check the color assert-css: ("body", { "background-color": "rgb(255, 255, 255)" }) + +goto: file://|DOC_PATH|/settings.html +click: "#theme-light" +wait-for: 500 +assert-css: ("body", { "background-color": "rgb(255, 255, 255)" }) +assert-local-storage: { "rustdoc-theme": "light" } + +click: "#theme-dark" +wait-for: 500 +assert-css: ("body", { "background-color": "rgb(53, 53, 53)" }) +assert-local-storage: { "rustdoc-theme": "dark" } + +click: "#theme-ayu" +wait-for: 500 +assert-css: ("body", { "background-color": "rgb(15, 20, 25)" }) +assert-local-storage: { "rustdoc-theme": "ayu" } diff --git a/src/test/rustdoc-gui/theme-in-history.goml b/src/test/rustdoc-gui/theme-in-history.goml new file mode 100644 index 00000000000..b53799188ef --- /dev/null +++ b/src/test/rustdoc-gui/theme-in-history.goml @@ -0,0 +1,25 @@ +// Ensures that the theme is working when going back in history. +goto: file://|DOC_PATH|/test_docs/index.html +// Set the theme to dark. +local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"} +// We reload the page so the local storage settings are being used. +reload: +assert-css: ("body", { "background-color": "rgb(53, 53, 53)" }) +assert-local-storage: { "rustdoc-theme": "dark" } + +// Now we go to the settings page. +click: "#settings-menu" +wait-for: ".settings" +// We change the theme to "light". +click: "#theme-light" +wait-for: 250 +assert-css: ("body", { "background-color": "rgb(255, 255, 255)" }) +assert-local-storage: { "rustdoc-theme": "light" } + +// We go back in history. +history-go-back: +// Confirm that we're not on the settings page. +assert-false: ".settings" +// Check that the current theme is still "light". +assert-css: ("body", { "background-color": "rgb(255, 255, 255)" }) +assert-local-storage: { "rustdoc-theme": "light" } diff --git a/src/test/rustdoc-gui/toggle-docs-mobile.goml b/src/test/rustdoc-gui/toggle-docs-mobile.goml index e7a75b43c5a..b5026923001 100644 --- a/src/test/rustdoc-gui/toggle-docs-mobile.goml +++ b/src/test/rustdoc-gui/toggle-docs-mobile.goml @@ -1,3 +1,5 @@ +// Checks that the documentation toggles on mobile have the correct position, style and work +// as expected. goto: file://|DOC_PATH|/test_docs/struct.Foo.html size: (433, 600) assert-attribute: (".top-doc", {"open": ""}) diff --git a/src/test/rustdoc-gui/toggle-docs.goml b/src/test/rustdoc-gui/toggle-docs.goml index e11aae21e3f..480d6242ac6 100644 --- a/src/test/rustdoc-gui/toggle-docs.goml +++ b/src/test/rustdoc-gui/toggle-docs.goml @@ -1,3 +1,4 @@ +// Checks that the documentation toggles have the correct position, style and work as expected. goto: file://|DOC_PATH|/test_docs/index.html assert-attribute: ("#main-content > details.top-doc", {"open": ""}) assert-text: ("#toggle-all-docs", "[−]") diff --git a/src/test/rustdoc-gui/trait-sidebar-item-order.goml b/src/test/rustdoc-gui/trait-sidebar-item-order.goml index 739745792c2..38942baa0b5 100644 --- a/src/test/rustdoc-gui/trait-sidebar-item-order.goml +++ b/src/test/rustdoc-gui/trait-sidebar-item-order.goml @@ -1,3 +1,4 @@ +// Checks that the elements in the sidebar are alphabetically sorted. goto: file://|DOC_PATH|/test_docs/trait.AnotherOne.html assert-text: (".sidebar-links a:nth-of-type(1)", "another") assert-text: (".sidebar-links a:nth-of-type(2)", "func1") diff --git a/src/test/rustdoc-gui/type-declation-overflow.goml b/src/test/rustdoc-gui/type-declation-overflow.goml index 21874f786f1..229c6d6ba6b 100644 --- a/src/test/rustdoc-gui/type-declation-overflow.goml +++ b/src/test/rustdoc-gui/type-declation-overflow.goml @@ -7,6 +7,10 @@ assert-property: ("body", {"scrollWidth": "1100"}) // However, since there is overflow in the type declaration, its scroll width is bigger. assert-property: (".item-decl pre", {"scrollWidth": "1324"}) +// In the table-ish view on the module index, the name should not be wrapped more than necessary. +goto: file://|DOC_PATH|/lib2/too_long/index.html +assert-property: (".item-table .struct", {"offsetWidth": "684"}) + // We now make the same check on type declaration... goto: file://|DOC_PATH|/lib2/too_long/type.ReallyLongTypeNameLongLongLong.html assert-property: ("body", {"scrollWidth": "1100"}) @@ -27,6 +31,6 @@ assert-property: (".item-decl pre", {"scrollWidth": "950"}) // On mobile: size: (600, 600) goto: file://|DOC_PATH|/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html -assert-property: (".mobile-topbar .location", {"scrollWidth": "504"}) +assert-property: (".mobile-topbar .location", {"scrollWidth": "986"}) assert-property: (".mobile-topbar .location", {"clientWidth": "504"}) assert-css: (".mobile-topbar .location", {"overflow-x": "hidden"}) diff --git a/src/test/rustdoc-js/generics-multi-trait.js b/src/test/rustdoc-js/generics-multi-trait.js new file mode 100644 index 00000000000..e7fcea876c8 --- /dev/null +++ b/src/test/rustdoc-js/generics-multi-trait.js @@ -0,0 +1,32 @@ +// exact-check + +const QUERY = [ + 'Result<SomeTrait>', + 'Zzzzzzzzzzzzzzzzzz', + 'Nonononononononono', +]; + +const EXPECTED = [ + // check one of the generic items + { + 'in_args': [ + { 'path': 'generics_multi_trait', 'name': 'beta' }, + ], + 'returned': [ + { 'path': 'generics_multi_trait', 'name': 'bet' }, + ], + }, + { + 'in_args': [ + { 'path': 'generics_multi_trait', 'name': 'beta' }, + ], + 'returned': [ + { 'path': 'generics_multi_trait', 'name': 'bet' }, + ], + }, + // ignore the name of the generic itself + { + 'in_args': [], + 'returned': [], + }, +]; diff --git a/src/test/rustdoc-js/generics-multi-trait.rs b/src/test/rustdoc-js/generics-multi-trait.rs new file mode 100644 index 00000000000..e6fd06d254c --- /dev/null +++ b/src/test/rustdoc-js/generics-multi-trait.rs @@ -0,0 +1,12 @@ +pub trait SomeTrait {} +pub trait Zzzzzzzzzzzzzzzzzz {} + +pub fn bet<Nonononononononono: SomeTrait + Zzzzzzzzzzzzzzzzzz>() -> Result<Nonononononononono, ()> { + loop {} +} + +pub fn beta<Nonononononononono: SomeTrait + Zzzzzzzzzzzzzzzzzz>( + _param: Result<Nonononononononono, ()>, +) { + loop {} +} diff --git a/src/test/rustdoc-json/impls/blanket_with_local.rs b/src/test/rustdoc-json/impls/blanket_with_local.rs index 963ea2fe5ae..a3d55b35f00 100644 --- a/src/test/rustdoc-json/impls/blanket_with_local.rs +++ b/src/test/rustdoc-json/impls/blanket_with_local.rs @@ -3,11 +3,15 @@ // @has blanket_with_local.json "$.index[*][?(@.name=='Load')]" pub trait Load { + // @has - "$.index[*][?(@.name=='load')]" fn load() {} + // @has - "$.index[*][?(@.name=='write')]" + fn write(self) {} } impl<P> Load for P { fn load() {} + fn write(self) {} } // @has - "$.index[*][?(@.name=='Wrapper')]" diff --git a/src/test/rustdoc/intra-doc/crate-relative.rs b/src/test/rustdoc/intra-doc/crate-relative.rs new file mode 100644 index 00000000000..bacbcabfc60 --- /dev/null +++ b/src/test/rustdoc/intra-doc/crate-relative.rs @@ -0,0 +1,13 @@ +pub struct Test<'a> { + data: &'a (), +} + +impl<'a> Test<'a> { + pub fn do_test(&self) {} +} + +// @has crate_relative/demo/index.html +// @has - '//a/@href' '../struct.Test.html#method.do_test' +pub mod demo { + //! [`crate::Test::do_test`] +} diff --git a/src/test/rustdoc/intra-doc/mod-relative.rs b/src/test/rustdoc/intra-doc/mod-relative.rs new file mode 100644 index 00000000000..49d3399b972 --- /dev/null +++ b/src/test/rustdoc/intra-doc/mod-relative.rs @@ -0,0 +1,17 @@ +pub mod wrapper { + + pub struct Test<'a> { + data: &'a (), + } + + impl<'a> Test<'a> { + pub fn do_test(&self) {} + } + + // @has mod_relative/wrapper/demo/index.html + // @has - '//a/@href' '../struct.Test.html#method.do_test' + /// [`Test::do_test`] + pub mod demo { + } + +} diff --git a/src/test/rustdoc/macro-generated-macro.macro_linebreak_pre.html b/src/test/rustdoc/macro-generated-macro.macro_linebreak_pre.html new file mode 100644 index 00000000000..ce5d3a8461b --- /dev/null +++ b/src/test/rustdoc/macro-generated-macro.macro_linebreak_pre.html @@ -0,0 +1,6 @@ +macro_rules! linebreak { + ( + <= 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 + 26 27 28 => + ) => { ... }; +} \ No newline at end of file diff --git a/src/test/rustdoc/macro-generated-macro.macro_morestuff_pre.html b/src/test/rustdoc/macro-generated-macro.macro_morestuff_pre.html new file mode 100644 index 00000000000..28f15522a82 --- /dev/null +++ b/src/test/rustdoc/macro-generated-macro.macro_morestuff_pre.html @@ -0,0 +1,15 @@ +macro_rules! morestuff { + ( + <= "space between most kinds of tokens" : 1 $x + @ :: >>= 'static + "no space inside paren or bracket" : (2 a) [2 a] $(2 $a:tt)* + "space inside curly brace" : { 2 a } + "no space inside empty delimiters" : () [] {} + "no space before comma or semicolon" : a, (a), { a }, a; [T; 0]; + "the three repetition specifiers" : $(@)*, $(@)+, $(@)? + "repetition separators" : $(@)|*, $(@)|+, $(@)==*, $(@)static* + "plus or star cannot be a repetition separator" : $(@)+ * $(@)* + + "no space between ident and paren" : let _ = f(0) + f[0] + Struct {}; + "space between keyword and paren" : return (a,) & for x in (..) + "some special case keywords" : pub(crate), fn() -> u8, Self(0, 0) => + ) => { ... }; +} \ No newline at end of file diff --git a/src/test/rustdoc/macro-generated-macro.rs b/src/test/rustdoc/macro-generated-macro.rs index 25d8bc3ec62..1a423cac1b5 100644 --- a/src/test/rustdoc/macro-generated-macro.rs +++ b/src/test/rustdoc/macro-generated-macro.rs @@ -1,14 +1,39 @@ -macro_rules! outer { - ($($matcher:tt)*) => { +macro_rules! make_macro { + ($macro_name:ident $($matcher:tt)*) => { #[macro_export] - macro_rules! inner { + macro_rules! $macro_name { (<= $($matcher)* =>) => {}; } } } -// @has macro_generated_macro/macro.inner.html //pre 'macro_rules! inner {' -// @has - //pre '(<= type $($i : ident) :: * + $e : expr =>) => { ... };' -outer!(type $($i:ident)::* + $e:expr); +// @has macro_generated_macro/macro.interpolations.html //pre 'macro_rules! interpolations {' +// @has - //pre '(<= type $($i:ident)::* + $e:expr =>) => { ... };' +make_macro!(interpolations type $($i:ident)::* + $e:expr); +interpolations!(<= type foo::bar + x.sort() =>); -inner!(<= type foo::bar + x.sort() =>); +// @has macro_generated_macro/macro.attributes.html //pre 'macro_rules! attributes {' +// @has - //pre '(<= #![no_std] #[cfg(feature = "alloc")] =>) => { ... };' +make_macro!(attributes #![no_std] #[cfg(feature = "alloc")]); + +// @has macro_generated_macro/macro.groups.html //pre 'macro_rules! groups {' +// @has - //pre '(<= fn {} () { foo[0] } =>) => { ... };' +make_macro!(groups fn {}() {foo[0]}); + +// @snapshot macro_linebreak_pre macro_generated_macro/macro.linebreak.html //pre/text() +make_macro!(linebreak 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28); + +// @snapshot macro_morestuff_pre macro_generated_macro/macro.morestuff.html //pre/text() +make_macro!(morestuff + "space between most kinds of tokens": 1 $x + @ :: >>= 'static + "no space inside paren or bracket": (2 a) [2 a] $(2 $a:tt)* + "space inside curly brace": { 2 a } + "no space inside empty delimiters": () [] {} + "no space before comma or semicolon": a, (a), { a }, a; [T; 0]; + "the three repetition specifiers": $(@)*, $(@)+, $(@)? + "repetition separators": $(@)|*, $(@)|+, $(@)==*, $(@)static* + "plus or star cannot be a repetition separator": $(@)+ * $(@)* + + "no space between ident and paren": let _ = f(0) + f[0] + Struct {}; + "space between keyword and paren": return (a,) & for x in (..) + "some special case keywords": pub(crate), fn() -> u8, Self(0, 0) +); diff --git a/src/test/rustdoc/source-version-separator.rs b/src/test/rustdoc/source-version-separator.rs index 45a555eaa15..8d23ca91801 100644 --- a/src/test/rustdoc/source-version-separator.rs +++ b/src/test/rustdoc/source-version-separator.rs @@ -1,10 +1,9 @@ #![stable(feature = "bar", since = "1.0")] #![crate_name = "foo"] - #![feature(staged_api)] // @has foo/trait.Bar.html -// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0· source · ' +// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · ' #[stable(feature = "bar", since = "1.0")] pub trait Bar { // @has - '//div[@id="tymethod.foo"]/*[@class="rightside"]' '3.0 · source' @@ -15,7 +14,7 @@ pub trait Bar { // @has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0 · source' // @has foo/struct.Foo.html -// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0· source · ' +// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · ' #[stable(feature = "baz", since = "1.0")] pub struct Foo; diff --git a/src/test/rustdoc/version-separator-without-source.rs b/src/test/rustdoc/version-separator-without-source.rs new file mode 100644 index 00000000000..bffe5030a84 --- /dev/null +++ b/src/test/rustdoc/version-separator-without-source.rs @@ -0,0 +1,23 @@ +#![doc(html_no_source)] +#![feature(staged_api)] +#![stable(feature = "bar", since = "1.0")] +#![crate_name = "foo"] + +// @has foo/fn.foo.html +// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · ' +// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · ' +#[stable(feature = "bar", since = "1.0")] +pub fn foo() {} + +// @has foo/struct.Bar.html +// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · ' +// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · ' +#[stable(feature = "bar", since = "1.0")] +pub struct Bar; + +impl Bar { + // @has - '//div[@id="method.bar"]/*[@class="rightside"]' '2.0' + // @!has - '//div[@id="method.bar"]/*[@class="rightside"]' '2.0 ·' + #[stable(feature = "foobar", since = "2.0")] + pub fn bar() {} +} diff --git a/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs b/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs index fab2031d952..dd20eef0700 100644 --- a/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs +++ b/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs @@ -18,6 +18,6 @@ struct A { fn main() { let obj = A { foo: Box::new([true, false]) }; let s = json::encode(&obj).unwrap(); - let obj2: A = json::decode(&s).unwrap(); + let obj2: A = json::decode(&s); assert_eq!(obj.foo, obj2.foo); } diff --git a/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs b/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs index 9dedf990f25..18aa974c31d 100644 --- a/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs +++ b/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs @@ -27,7 +27,7 @@ struct B { fn main() { let obj = B { foo: Cell::new(true), bar: RefCell::new(A { baz: 2 }) }; let s = json::encode(&obj).unwrap(); - let obj2: B = json::decode(&s).unwrap(); + let obj2: B = json::decode(&s); assert_eq!(obj.foo.get(), obj2.foo.get()); assert_eq!(obj.bar.borrow().baz, obj2.bar.borrow().baz); } diff --git a/src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.stderr b/src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.stderr index 59732cd84e5..a1056cf85d3 100644 --- a/src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.stderr +++ b/src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.stderr @@ -2,7 +2,7 @@ error: usage of qualified `ty::Ty<'_>` --> $DIR/qualified_ty_ty_ctxt.rs:25:11 | LL | ty_q: ty::Ty<'_>, - | ^^^^^^^^^^ help: try using it unqualified: `Ty<'_>` + | ^^^^^^^^^^ help: try importing it and using it unqualified: `Ty<'_>` | note: the lint level is defined here --> $DIR/qualified_ty_ty_ctxt.rs:4:9 @@ -14,7 +14,7 @@ error: usage of qualified `ty::TyCtxt<'_>` --> $DIR/qualified_ty_ty_ctxt.rs:27:16 | LL | ty_ctxt_q: ty::TyCtxt<'_>, - | ^^^^^^^^^^^^^^ help: try using it unqualified: `TyCtxt<'_>` + | ^^^^^^^^^^^^^^ help: try importing it and using it unqualified: `TyCtxt<'_>` error: aborting due to 2 previous errors diff --git a/src/test/ui-fulldeps/issue-14021.rs b/src/test/ui-fulldeps/issue-14021.rs index be88a593962..acd75170d68 100644 --- a/src/test/ui-fulldeps/issue-14021.rs +++ b/src/test/ui-fulldeps/issue-14021.rs @@ -20,7 +20,7 @@ pub fn main() { let json_object = json::from_str(&json_str); let mut decoder = json::Decoder::new(json_object.unwrap()); - let mut decoded_obj: UnitLikeStruct = Decodable::decode(&mut decoder).unwrap(); + let mut decoded_obj: UnitLikeStruct = Decodable::decode(&mut decoder); assert_eq!(obj, decoded_obj); } diff --git a/src/test/ui-fulldeps/issue-4016.rs b/src/test/ui-fulldeps/issue-4016.rs index 4fd192497a0..65dab8d7704 100644 --- a/src/test/ui-fulldeps/issue-4016.rs +++ b/src/test/ui-fulldeps/issue-4016.rs @@ -12,7 +12,7 @@ trait JD: Decodable<json::Decoder> {} fn exec<T: JD>() { let doc = json::from_str("").unwrap(); let mut decoder = json::Decoder::new(doc); - let _v: T = Decodable::decode(&mut decoder).unwrap(); + let _v: T = Decodable::decode(&mut decoder); panic!() } diff --git a/src/test/ui-fulldeps/issue-4036.rs b/src/test/ui-fulldeps/issue-4036.rs index 05a7a30140a..702bb2d6ef6 100644 --- a/src/test/ui-fulldeps/issue-4036.rs +++ b/src/test/ui-fulldeps/issue-4036.rs @@ -13,5 +13,5 @@ use rustc_serialize::{json, Decodable}; pub fn main() { let json = json::from_str("[1]").unwrap(); let mut decoder = json::Decoder::new(json); - let _x: Vec<isize> = Decodable::decode(&mut decoder).unwrap(); + let _x: Vec<isize> = Decodable::decode(&mut decoder); } diff --git a/src/test/ui/asm/naked-functions.rs b/src/test/ui/asm/naked-functions.rs index 32431d9e7c6..5b4293972ea 100644 --- a/src/test/ui/asm/naked-functions.rs +++ b/src/test/ui/asm/naked-functions.rs @@ -5,7 +5,7 @@ #![feature(naked_functions)] #![feature(or_patterns)] -#![feature(asm_const, asm_sym)] +#![feature(asm_const, asm_sym, asm_unwind)] #![crate_type = "lib"] use std::arch::asm; @@ -32,8 +32,7 @@ pub unsafe extern "C" fn patterns( #[naked] pub unsafe extern "C" fn inc(a: u32) -> u32 { - //~^ WARN naked functions must contain a single asm block - //~| WARN this was previously accepted + //~^ ERROR naked functions must contain a single asm block a + 1 //~^ ERROR referencing function parameters is not allowed in naked functions } @@ -42,21 +41,18 @@ pub unsafe extern "C" fn inc(a: u32) -> u32 { pub unsafe extern "C" fn inc_asm(a: u32) -> u32 { asm!("/* {0} */", in(reg) a, options(noreturn)); //~^ ERROR referencing function parameters is not allowed in naked functions - //~| WARN only `const` and `sym` operands are supported in naked functions - //~| WARN this was previously accepted + //~| ERROR only `const` and `sym` operands are supported in naked functions } #[naked] pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { - //~^ WARN naked functions must contain a single asm block - //~| WARN this was previously accepted + //~^ ERROR naked functions must contain a single asm block (|| a + 1)() } #[naked] pub unsafe extern "C" fn unsupported_operands() { - //~^ WARN naked functions must contain a single asm block - //~| WARN this was previously accepted + //~^ ERROR naked functions must contain a single asm block let mut a = 0usize; let mut b = 0usize; let mut c = 0usize; @@ -65,11 +61,9 @@ pub unsafe extern "C" fn unsupported_operands() { const F: usize = 0usize; static G: usize = 0usize; asm!("/* {0} {1} {2} {3} {4} {5} {6} */", - //~^ WARN asm in naked functions must use `noreturn` option - //~| WARN this was previously accepted + //~^ ERROR asm in naked functions must use `noreturn` option in(reg) a, - //~^ WARN only `const` and `sym` operands are supported in naked functions - //~| WARN this was previously accepted + //~^ ERROR only `const` and `sym` operands are supported in naked functions inlateout(reg) b, inout(reg) c, lateout(reg) d, @@ -81,31 +75,25 @@ pub unsafe extern "C" fn unsupported_operands() { #[naked] pub extern "C" fn missing_assembly() { - //~^ WARN naked functions must contain a single asm block - //~| WARN this was previously accepted + //~^ ERROR naked functions must contain a single asm block } #[naked] pub extern "C" fn too_many_asm_blocks() { - //~^ WARN naked functions must contain a single asm block - //~| WARN this was previously accepted + //~^ ERROR naked functions must contain a single asm block asm!(""); - //~^ WARN asm in naked functions must use `noreturn` option - //~| WARN this was previously accepted + //~^ ERROR asm in naked functions must use `noreturn` option asm!(""); - //~^ WARN asm in naked functions must use `noreturn` option - //~| WARN this was previously accepted + //~^ ERROR asm in naked functions must use `noreturn` option asm!(""); - //~^ WARN asm in naked functions must use `noreturn` option - //~| WARN this was previously accepted + //~^ ERROR asm in naked functions must use `noreturn` option asm!("", options(noreturn)); } pub fn outer(x: u32) -> extern "C" fn(usize) -> usize { #[naked] pub extern "C" fn inner(y: usize) -> usize { - //~^ WARN naked functions must contain a single asm block - //~| WARN this was previously accepted + //~^ ERROR naked functions must contain a single asm block *&y //~^ ERROR referencing function parameters is not allowed in naked functions } @@ -115,18 +103,21 @@ pub fn outer(x: u32) -> extern "C" fn(usize) -> usize { #[naked] unsafe extern "C" fn invalid_options() { asm!("", options(nomem, preserves_flags, noreturn)); - //~^ WARN asm options unsupported in naked functions: `nomem`, `preserves_flags` - //~| WARN this was previously accepted + //~^ ERROR asm options unsupported in naked functions: `nomem`, `preserves_flags` } #[naked] unsafe extern "C" fn invalid_options_continued() { asm!("", options(readonly, nostack), options(pure)); //~^ ERROR asm with the `pure` option must have at least one output - //~| WARN asm options unsupported in naked functions: `nostack`, `pure`, `readonly` - //~| WARN this was previously accepted - //~| WARN asm in naked functions must use `noreturn` option - //~| WARN this was previously accepted + //~| ERROR asm options unsupported in naked functions: `nostack`, `pure`, `readonly` + //~| ERROR asm in naked functions must use `noreturn` option +} + +#[naked] +unsafe extern "C" fn invalid_may_unwind() { + asm!("", options(noreturn, may_unwind)); + //~^ ERROR asm options unsupported in naked functions: `may_unwind` } #[naked] @@ -177,38 +168,32 @@ pub unsafe extern "C" fn inline_none() { #[naked] #[inline] -//~^ WARN naked functions cannot be inlined -//~| WARN this was previously accepted +//~^ ERROR naked functions cannot be inlined pub unsafe extern "C" fn inline_hint() { asm!("", options(noreturn)); } #[naked] #[inline(always)] -//~^ WARN naked functions cannot be inlined -//~| WARN this was previously accepted +//~^ ERROR naked functions cannot be inlined pub unsafe extern "C" fn inline_always() { asm!("", options(noreturn)); } #[naked] #[inline(never)] -//~^ WARN naked functions cannot be inlined -//~| WARN this was previously accepted +//~^ ERROR naked functions cannot be inlined pub unsafe extern "C" fn inline_never() { asm!("", options(noreturn)); } #[naked] #[inline] -//~^ WARN naked functions cannot be inlined -//~| WARN this was previously accepted +//~^ ERROR naked functions cannot be inlined #[inline(always)] -//~^ WARN naked functions cannot be inlined -//~| WARN this was previously accepted +//~^ ERROR naked functions cannot be inlined #[inline(never)] -//~^ WARN naked functions cannot be inlined -//~| WARN this was previously accepted +//~^ ERROR naked functions cannot be inlined pub unsafe extern "C" fn inline_all() { asm!("", options(noreturn)); } diff --git a/src/test/ui/asm/naked-functions.stderr b/src/test/ui/asm/naked-functions.stderr index c2dfe443d60..c1dcc433db6 100644 --- a/src/test/ui/asm/naked-functions.stderr +++ b/src/test/ui/asm/naked-functions.stderr @@ -1,5 +1,5 @@ error: asm with the `pure` option must have at least one output - --> $DIR/naked-functions.rs:124:14 + --> $DIR/naked-functions.rs:111:14 | LL | asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ @@ -29,66 +29,54 @@ LL | P { x, y }: P, | ^^^^^^^^^^ error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:37:5 + --> $DIR/naked-functions.rs:36:5 | LL | a + 1 | ^ | = help: follow the calling convention in asm block to use parameters -warning: naked functions must contain a single asm block +error[E0787]: naked functions must contain a single asm block --> $DIR/naked-functions.rs:34:1 | LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 { LL | | -LL | | LL | | a + 1 | | ----- non-asm is unsupported in naked functions LL | | LL | | } | |_^ - | - = note: `#[warn(unsupported_naked_functions)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:43:31 + --> $DIR/naked-functions.rs:42:31 | LL | asm!("/* {0} */", in(reg) a, options(noreturn)); | ^ | = help: follow the calling convention in asm block to use parameters -warning: only `const` and `sym` operands are supported in naked functions - --> $DIR/naked-functions.rs:43:23 +error[E0787]: only `const` and `sym` operands are supported in naked functions + --> $DIR/naked-functions.rs:42:23 | LL | asm!("/* {0} */", in(reg) a, options(noreturn)); | ^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> -warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:50:1 +error[E0787]: naked functions must contain a single asm block + --> $DIR/naked-functions.rs:48:1 | LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { LL | | -LL | | LL | | (|| a + 1)() | | ------------ non-asm is unsupported in naked functions LL | | } | |_^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> -warning: only `const` and `sym` operands are supported in naked functions - --> $DIR/naked-functions.rs:70:10 +error[E0787]: only `const` and `sym` operands are supported in naked functions + --> $DIR/naked-functions.rs:65:10 | LL | in(reg) a, | ^^^^^^^^^ -... +LL | LL | inlateout(reg) b, | ^^^^^^^^^^^^^^^^ LL | inout(reg) c, @@ -97,31 +85,24 @@ LL | lateout(reg) d, | ^^^^^^^^^^^^^^ LL | out(reg) e, | ^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> -warning: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:67:5 +error[E0787]: asm in naked functions must use `noreturn` option + --> $DIR/naked-functions.rs:63:5 | LL | / asm!("/* {0} {1} {2} {3} {4} {5} {6} */", LL | | -LL | | LL | | in(reg) a, +LL | | ... | LL | | sym G, LL | | ); | |_____^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> -warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:57:1 +error[E0787]: naked functions must contain a single asm block + --> $DIR/naked-functions.rs:54:1 | LL | / pub unsafe extern "C" fn unsupported_operands() { LL | | -LL | | LL | | let mut a = 0usize; | | ------------------- non-asm is unsupported in naked functions LL | | let mut b = 0usize; @@ -136,123 +117,96 @@ LL | | let mut e = 0usize; LL | | ); LL | | } | |_^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> -warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:83:1 +error[E0787]: naked functions must contain a single asm block + --> $DIR/naked-functions.rs:77:1 | LL | / pub extern "C" fn missing_assembly() { LL | | -LL | | LL | | } | |_^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> -warning: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:92:5 +error[E0787]: asm in naked functions must use `noreturn` option + --> $DIR/naked-functions.rs:84:5 | LL | asm!(""); | ^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> -warning: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:95:5 +error[E0787]: asm in naked functions must use `noreturn` option + --> $DIR/naked-functions.rs:86:5 | LL | asm!(""); | ^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> -warning: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:98:5 +error[E0787]: asm in naked functions must use `noreturn` option + --> $DIR/naked-functions.rs:88:5 | LL | asm!(""); | ^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> -warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:89:1 +error[E0787]: naked functions must contain a single asm block + --> $DIR/naked-functions.rs:82:1 | LL | / pub extern "C" fn too_many_asm_blocks() { LL | | -LL | | LL | | asm!(""); -... | +LL | | LL | | asm!(""); | | -------- multiple asm blocks are unsupported in naked functions -... | +LL | | LL | | asm!(""); | | -------- multiple asm blocks are unsupported in naked functions -... | +LL | | LL | | asm!("", options(noreturn)); | | --------------------------- multiple asm blocks are unsupported in naked functions LL | | } | |_^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:109:11 + --> $DIR/naked-functions.rs:97:11 | LL | *&y | ^ | = help: follow the calling convention in asm block to use parameters -warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:106:5 +error[E0787]: naked functions must contain a single asm block + --> $DIR/naked-functions.rs:95:5 | LL | / pub extern "C" fn inner(y: usize) -> usize { LL | | -LL | | LL | | *&y | | --- non-asm is unsupported in naked functions LL | | LL | | } | |_____^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> -warning: asm options unsupported in naked functions: `nomem`, `preserves_flags` - --> $DIR/naked-functions.rs:117:5 +error[E0787]: asm options unsupported in naked functions: `nomem`, `preserves_flags` + --> $DIR/naked-functions.rs:105:5 | LL | asm!("", options(nomem, preserves_flags, noreturn)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> -warning: asm options unsupported in naked functions: `nostack`, `pure`, `readonly` - --> $DIR/naked-functions.rs:124:5 +error[E0787]: asm options unsupported in naked functions: `nostack`, `pure`, `readonly` + --> $DIR/naked-functions.rs:111:5 | LL | asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> -warning: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:124:5 +error[E0787]: asm in naked functions must use `noreturn` option + --> $DIR/naked-functions.rs:111:5 | LL | asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0787]: asm options unsupported in naked functions: `may_unwind` + --> $DIR/naked-functions.rs:119:5 | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> +LL | asm!("", options(noreturn, may_unwind)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: Rust ABI is unsupported in naked functions - --> $DIR/naked-functions.rs:133:15 + --> $DIR/naked-functions.rs:124:15 | LL | pub unsafe fn default_abi() { | ^^^^^^^^^^^ @@ -260,64 +214,47 @@ LL | pub unsafe fn default_abi() { = note: `#[warn(undefined_naked_function_abi)]` on by default warning: Rust ABI is unsupported in naked functions - --> $DIR/naked-functions.rs:139:15 + --> $DIR/naked-functions.rs:130:15 | LL | pub unsafe fn rust_abi() { | ^^^^^^^^ -warning: naked functions cannot be inlined - --> $DIR/naked-functions.rs:179:1 +error: naked functions cannot be inlined + --> $DIR/naked-functions.rs:170:1 | LL | #[inline] | ^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> -warning: naked functions cannot be inlined - --> $DIR/naked-functions.rs:187:1 +error: naked functions cannot be inlined + --> $DIR/naked-functions.rs:177:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> -warning: naked functions cannot be inlined - --> $DIR/naked-functions.rs:195:1 +error: naked functions cannot be inlined + --> $DIR/naked-functions.rs:184:1 | LL | #[inline(never)] | ^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> -warning: naked functions cannot be inlined - --> $DIR/naked-functions.rs:203:1 +error: naked functions cannot be inlined + --> $DIR/naked-functions.rs:191:1 | LL | #[inline] | ^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> -warning: naked functions cannot be inlined - --> $DIR/naked-functions.rs:206:1 +error: naked functions cannot be inlined + --> $DIR/naked-functions.rs:193:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> -warning: naked functions cannot be inlined - --> $DIR/naked-functions.rs:209:1 +error: naked functions cannot be inlined + --> $DIR/naked-functions.rs:195:1 | LL | #[inline(never)] | ^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408> -error: aborting due to 8 previous errors; 23 warnings emitted +error: aborting due to 30 previous errors; 2 warnings emitted +For more information about this error, try `rustc --explain E0787`. diff --git a/src/test/ui/asm/named-asm-labels.stderr b/src/test/ui/asm/named-asm-labels.stderr index b8ff42d86b5..001601497a2 100644 --- a/src/test/ui/asm/named-asm-labels.stderr +++ b/src/test/ui/asm/named-asm-labels.stderr @@ -6,6 +6,7 @@ LL | asm!("bar: nop"); | = note: `#[deny(named_asm_labels)]` on by default = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:27:15 @@ -14,6 +15,7 @@ LL | asm!("abcd:"); | ^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:30:15 @@ -22,6 +24,7 @@ LL | asm!("foo: bar1: nop"); | ^^^ ^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:34:15 @@ -30,6 +33,7 @@ LL | asm!("foo1: nop", "nop"); | ^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:35:15 @@ -38,6 +42,7 @@ LL | asm!("foo2: foo3: nop", "nop"); | ^^^^ ^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:37:22 @@ -46,6 +51,7 @@ LL | asm!("nop", "foo4: nop"); | ^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:38:15 @@ -54,6 +60,7 @@ LL | asm!("foo5: nop", "foo6: nop"); | ^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:38:28 @@ -62,6 +69,7 @@ LL | asm!("foo5: nop", "foo6: nop"); | ^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:43:15 @@ -70,6 +78,7 @@ LL | asm!("foo7: nop; foo8: nop"); | ^^^^ ^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:45:15 @@ -78,6 +87,7 @@ LL | asm!("foo9: nop; nop"); | ^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:46:20 @@ -86,6 +96,7 @@ LL | asm!("nop; foo10: nop"); | ^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:49:15 @@ -94,6 +105,7 @@ LL | asm!("bar2: nop\n bar3: nop"); | ^^^^ ^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:51:15 @@ -102,6 +114,7 @@ LL | asm!("bar4: nop\n nop"); | ^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:52:21 @@ -110,6 +123,7 @@ LL | asm!("nop\n bar5: nop"); | ^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:53:21 @@ -118,6 +132,7 @@ LL | asm!("nop\n bar6: bar7: nop"); | ^^^^ ^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:59:13 @@ -128,6 +143,7 @@ LL | blah3: nop | ^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:68:19 @@ -136,6 +152,7 @@ LL | nop ; blah4: nop | ^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:82:15 @@ -144,6 +161,7 @@ LL | asm!("blah1: 2bar: nop"); | ^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:85:15 @@ -152,6 +170,7 @@ LL | asm!("def: def: nop"); | ^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:86:15 @@ -160,6 +179,7 @@ LL | asm!("def: nop\ndef: nop"); | ^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:87:15 @@ -168,6 +188,7 @@ LL | asm!("def: nop; def: nop"); | ^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:95:15 @@ -176,6 +197,7 @@ LL | asm!("fooo\u{003A} nop"); | ^^^^^^^^^^^^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:96:15 @@ -184,6 +206,7 @@ LL | asm!("foooo\x3A nop"); | ^^^^^^^^^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:99:15 @@ -192,6 +215,7 @@ LL | asm!("fooooo:\u{000A} nop"); | ^^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:100:15 @@ -200,6 +224,7 @@ LL | asm!("foooooo:\x0A nop"); | ^^^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:104:14 @@ -208,6 +233,7 @@ LL | asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:112:13 @@ -216,6 +242,7 @@ LL | ab: nop // ab: does foo | ^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:124:14 @@ -224,6 +251,7 @@ LL | asm!(include_str!("named-asm-labels.s")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information warning: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:134:19 @@ -237,6 +265,7 @@ note: the lint level is defined here LL | #[warn(named_asm_labels)] | ^^^^^^^^^^^^^^^^ = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:143:20 @@ -245,6 +274,7 @@ LL | unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noret | ^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:149:20 @@ -253,6 +283,7 @@ LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noret | ^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:157:20 @@ -261,6 +292,7 @@ LL | unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) } | ^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:167:24 @@ -269,6 +301,7 @@ LL | unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) } | ^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:176:15 @@ -277,6 +310,7 @@ LL | asm!("closure1: nop"); | ^^^^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:180:15 @@ -285,6 +319,7 @@ LL | asm!("closure2: nop"); | ^^^^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: avoid using named labels in inline assembly --> $DIR/named-asm-labels.rs:190:19 @@ -293,6 +328,7 @@ LL | asm!("closure3: nop"); | ^^^^^^^^ | = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information error: aborting due to 35 previous errors; 1 warning emitted diff --git a/src/test/ui/async-await/async-fn-nonsend.rs b/src/test/ui/async-await/async-fn-nonsend.rs index c5453b67ef5..a1a05c0acba 100644 --- a/src/test/ui/async-await/async-fn-nonsend.rs +++ b/src/test/ui/async-await/async-fn-nonsend.rs @@ -1,6 +1,10 @@ // edition:2018 // compile-flags: --crate-type lib +// FIXME(eholk): temporarily disabled while drop range tracking is disabled +// (see generator_interior.rs:27) +// ignore-test + use std::{cell::RefCell, fmt::Debug, rc::Rc}; fn non_sync() -> impl Debug { diff --git a/src/test/ui/async-await/proper-span-for-type-error.fixed b/src/test/ui/async-await/proper-span-for-type-error.fixed new file mode 100644 index 00000000000..1f1e1184dcc --- /dev/null +++ b/src/test/ui/async-await/proper-span-for-type-error.fixed @@ -0,0 +1,11 @@ +// edition:2021 +// run-rustfix +#![allow(dead_code)] + +async fn a() {} + +async fn foo() -> Result<(), i32> { + Ok(a().await) //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/async-await/proper-span-for-type-error.rs b/src/test/ui/async-await/proper-span-for-type-error.rs new file mode 100644 index 00000000000..00ccde1bf99 --- /dev/null +++ b/src/test/ui/async-await/proper-span-for-type-error.rs @@ -0,0 +1,11 @@ +// edition:2021 +// run-rustfix +#![allow(dead_code)] + +async fn a() {} + +async fn foo() -> Result<(), i32> { + a().await //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/async-await/proper-span-for-type-error.stderr b/src/test/ui/async-await/proper-span-for-type-error.stderr new file mode 100644 index 00000000000..611dc0407bf --- /dev/null +++ b/src/test/ui/async-await/proper-span-for-type-error.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/proper-span-for-type-error.rs:8:5 + | +LL | a().await + | ^^^^^^^^^ expected enum `Result`, found `()` + | + = note: expected enum `Result<(), i32>` + found unit type `()` +help: try wrapping the expression in `Ok` + | +LL | Ok(a().await) + | +++ + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/async-await/unresolved_type_param.rs b/src/test/ui/async-await/unresolved_type_param.rs index d313691b388..187356ca140 100644 --- a/src/test/ui/async-await/unresolved_type_param.rs +++ b/src/test/ui/async-await/unresolved_type_param.rs @@ -3,6 +3,10 @@ // (rather than give a general error message) // edition:2018 +// FIXME(eholk): temporarily disabled while drop range tracking is disabled +// (see generator_interior.rs:27) +// ignore-test + async fn bar<T>() -> () {} async fn foo() { diff --git a/src/test/ui/attributes/key-value-expansion.stderr b/src/test/ui/attributes/key-value-expansion.stderr index 268e382327e..1b7cb76b553 100644 --- a/src/test/ui/attributes/key-value-expansion.stderr +++ b/src/test/ui/attributes/key-value-expansion.stderr @@ -16,12 +16,11 @@ LL | bug!(); = note: this error originates in the macro `bug` (in Nightly builds, run with -Z macro-backtrace for more info) error: unexpected token: `{ - let res = - ::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""], - &[::core::fmt::ArgumentV1::new(&"u8", - ::core::fmt::Display::fmt)])); - res - }.as_str()` + let res = + ::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""], + &[::core::fmt::ArgumentV1::new_display(&"u8")])); + res + }.as_str()` --> $DIR/key-value-expansion.rs:48:23 | LL | doc_comment! {format!("{coor}", coor = stringify!($t1)).as_str()} diff --git a/src/test/ui/c-variadic/variadic-ffi-4.stderr b/src/test/ui/c-variadic/variadic-ffi-4.stderr index 4b03fe15494..ff4da5251a9 100644 --- a/src/test/ui/c-variadic/variadic-ffi-4.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-4.stderr @@ -20,7 +20,7 @@ LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f | | | lifetime `'f` defined here LL | ap - | ^^ returning this value requires that `'1` must outlive `'f` + | ^^ function was supposed to return data with lifetime `'f` but it is returning data with lifetime `'1` | = note: requirement occurs because of the type VaListImpl<'_>, which makes the generic argument '_ invariant = note: the struct VaListImpl<'f> is invariant over the parameter 'f diff --git a/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs b/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs index ef12b05fab2..6cb2ff9d813 100644 --- a/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs +++ b/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs @@ -5,8 +5,12 @@ #![cfg_attr(foo, crate_type="bin")] //~^ERROR `crate_type` within //~| WARN this was previously accepted +//~|ERROR `crate_type` within +//~| WARN this was previously accepted #![cfg_attr(foo, crate_name="bar")] //~^ERROR `crate_name` within //~| WARN this was previously accepted +//~|ERROR `crate_name` within +//~| WARN this was previously accepted fn main() {} diff --git a/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr b/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr index 5df2eacc96e..5609f8e9d9f 100644 --- a/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr +++ b/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr @@ -14,7 +14,7 @@ LL | #![deny(warnings)] = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632> error: `crate_name` within an `#![cfg_attr] attribute is deprecated` - --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:8:18 + --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:10:18 | LL | #![cfg_attr(foo, crate_name="bar")] | ^^^^^^^^^^^^^^^^ @@ -22,5 +22,23 @@ LL | #![cfg_attr(foo, crate_name="bar")] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632> -error: aborting due to 2 previous errors +error: `crate_type` within an `#![cfg_attr] attribute is deprecated` + --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:5:18 + | +LL | #![cfg_attr(foo, crate_type="bin")] + | ^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632> + +error: `crate_name` within an `#![cfg_attr] attribute is deprecated` + --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:10:18 + | +LL | #![cfg_attr(foo, crate_name="bar")] + | ^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632> + +error: aborting due to 4 previous errors diff --git a/src/test/ui/closures/issue-84044-drop-non-mut.rs b/src/test/ui/closures/issue-84044-drop-non-mut.rs new file mode 100644 index 00000000000..aed7750f1b9 --- /dev/null +++ b/src/test/ui/closures/issue-84044-drop-non-mut.rs @@ -0,0 +1,6 @@ +// #84044: This used to ICE. + +fn main() { + let f = || {}; + drop(&mut f); //~ ERROR cannot borrow `f` as mutable, as it is not declared as mutable +} diff --git a/src/test/ui/closures/issue-84044-drop-non-mut.stderr b/src/test/ui/closures/issue-84044-drop-non-mut.stderr new file mode 100644 index 00000000000..c0bfad263f1 --- /dev/null +++ b/src/test/ui/closures/issue-84044-drop-non-mut.stderr @@ -0,0 +1,11 @@ +error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable + --> $DIR/issue-84044-drop-non-mut.rs:5:10 + | +LL | let f = || {}; + | - help: consider changing this to be mutable: `mut f` +LL | drop(&mut f); + | ^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr index bdc71b8dcaa..aee782a1c5b 100644 --- a/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr +++ b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr @@ -9,7 +9,7 @@ LL | let c1 : () = c; | expected due to this | = note: expected unit type `()` - found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#19t, extern "rust-call" fn(()), _#20t]]` + found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#16t, extern "rust-call" fn(()), _#15t]]` help: use parentheses to call this closure | LL | let c1 : () = c(); diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr b/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr index 453f18891d3..6a994ce718e 100644 --- a/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr +++ b/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr @@ -9,7 +9,7 @@ LL | let c1 : () = c; | expected due to this | = note: expected unit type `()` - found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#19t, extern "rust-call" fn(()), _#20t]]` + found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#16t, extern "rust-call" fn(()), _#15t]]` help: use parentheses to call this closure | LL | let c1 : () = c(); diff --git a/src/test/ui/coherence/auxiliary/option_future.rs b/src/test/ui/coherence/auxiliary/option_future.rs new file mode 100644 index 00000000000..f71df1b87fc --- /dev/null +++ b/src/test/ui/coherence/auxiliary/option_future.rs @@ -0,0 +1,8 @@ +#![crate_type = "lib"] +#![feature(negative_impls)] +#![feature(rustc_attrs)] + +pub trait Future {} + +#[rustc_with_negative_coherence] +impl<E> !Future for Option<E> where E: Sized {} diff --git a/src/test/ui/coherence/coherence-overlap-negative-trait2.rs b/src/test/ui/coherence/coherence-overlap-negative-trait2.rs new file mode 100644 index 00000000000..1f47b5ba46e --- /dev/null +++ b/src/test/ui/coherence/coherence-overlap-negative-trait2.rs @@ -0,0 +1,18 @@ +// check-pass +// aux-build:option_future.rs +// +// Check that if we promise to not impl what would overlap it doesn't actually overlap + +#![feature(rustc_attrs)] + +extern crate option_future as lib; +use lib::Future; + +trait Termination {} + +#[rustc_with_negative_coherence] +impl<E> Termination for Option<E> where E: Sized {} +#[rustc_with_negative_coherence] +impl<F> Termination for F where F: Future + Sized {} + +fn main() {} diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-1.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-1.rs index 36dd78dd2b1..d20e79b9db3 100644 --- a/src/test/ui/conditional-compilation/cfg-arg-invalid-1.rs +++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-1.rs @@ -1,3 +1,3 @@ // compile-flags: --cfg a(b=c) -// error-pattern: invalid `--cfg` argument: `a(b=c)` (expected `key` or `key="value"`) +// error-pattern: invalid `--cfg` argument: `a(b=c)` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\") fn main() {} diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-1.stderr b/src/test/ui/conditional-compilation/cfg-arg-invalid-1.stderr index 1e7922a9ff1..3a12e978680 100644 --- a/src/test/ui/conditional-compilation/cfg-arg-invalid-1.stderr +++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-1.stderr @@ -1,2 +1,2 @@ -error: invalid `--cfg` argument: `a(b=c)` (expected `key` or `key="value"`) +error: invalid `--cfg` argument: `a(b=c)` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\") diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-9.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-9.rs new file mode 100644 index 00000000000..628b335c873 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-9.rs @@ -0,0 +1,4 @@ +// Test for missing quotes around value, issue #66450. +// compile-flags: --cfg key=value +// error-pattern: invalid `--cfg` argument: `key=value` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\") +fn main() {} diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-9.stderr b/src/test/ui/conditional-compilation/cfg-arg-invalid-9.stderr new file mode 100644 index 00000000000..985b5252258 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-9.stderr @@ -0,0 +1,2 @@ +error: invalid `--cfg` argument: `key=value` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\") + diff --git a/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout b/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout index 99fe9d2e4b3..121138605f1 100644 --- a/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout +++ b/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout @@ -15,4 +15,4 @@ trait Foo<const KIND : bool = true> {} fn foo<const SIZE : usize = 5>() {} struct Range<const FROM : usize = 0, const LEN : usize = 0, const TO : usize = - FROM>; + FROM>; diff --git a/src/test/ui/consts/const-block-const-bound.rs b/src/test/ui/consts/const-block-const-bound.rs index 3d7e171f18c..f3c82c5f968 100644 --- a/src/test/ui/consts/const-block-const-bound.rs +++ b/src/test/ui/consts/const-block-const-bound.rs @@ -16,8 +16,8 @@ impl !Drop for NonDrop {} fn main() { const { f(UnconstDrop); - //~^ ERROR the trait bound `UnconstDrop: Drop` is not satisfied + //~^ ERROR the trait bound `UnconstDrop: ~const Drop` is not satisfied f(NonDrop); - //~^ ERROR the trait bound `NonDrop: Drop` is not satisfied + //~^ ERROR the trait bound `NonDrop: ~const Drop` is not satisfied } } diff --git a/src/test/ui/consts/const-block-const-bound.stderr b/src/test/ui/consts/const-block-const-bound.stderr index 5f912c66bb9..b5f5694ba83 100644 --- a/src/test/ui/consts/const-block-const-bound.stderr +++ b/src/test/ui/consts/const-block-const-bound.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `UnconstDrop: Drop` is not satisfied +error[E0277]: the trait bound `UnconstDrop: ~const Drop` is not satisfied --> $DIR/const-block-const-bound.rs:18:11 | LL | f(UnconstDrop); - | - ^^^^^^^^^^^ the trait `Drop` is not implemented for `UnconstDrop` + | - ^^^^^^^^^^^ expected an implementor of trait `~const Drop` | | | required by a bound introduced by this call | @@ -11,16 +11,18 @@ note: required by a bound in `f` | LL | const fn f<T: ~const Drop>(x: T) {} | ^^^^^^^^^^^ required by this bound in `f` -help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement +help: consider borrowing here | -LL | fn main() where UnconstDrop: Drop { - | +++++++++++++++++++++++ +LL | f(&UnconstDrop); + | + +LL | f(&mut UnconstDrop); + | ++++ -error[E0277]: the trait bound `NonDrop: Drop` is not satisfied +error[E0277]: the trait bound `NonDrop: ~const Drop` is not satisfied --> $DIR/const-block-const-bound.rs:20:11 | LL | f(NonDrop); - | - ^^^^^^^ the trait `Drop` is not implemented for `NonDrop` + | - ^^^^^^^ expected an implementor of trait `~const Drop` | | | required by a bound introduced by this call | @@ -29,6 +31,12 @@ note: required by a bound in `f` | LL | const fn f<T: ~const Drop>(x: T) {} | ^^^^^^^^^^^ required by this bound in `f` +help: consider borrowing here + | +LL | f(&NonDrop); + | + +LL | f(&mut NonDrop); + | ++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs index 1a1d9a6d540..ac9e8b64b48 100644 --- a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs @@ -6,11 +6,10 @@ use std::intrinsics; const FOO: i32 = foo(); const fn foo() -> i32 { unsafe { - let _ = intrinsics::const_allocate(4, 3) as * mut i32; + let _ = intrinsics::const_allocate(4, 3) as *mut i32; //~^ error: evaluation of constant value failed } 1 - } fn main() {} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr index 74fb65ca1a6..2628a78455c 100644 --- a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr @@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed LL | const FOO: i32 = foo(); | ----- inside `FOO` at $DIR/alloc_intrinsic_errors.rs:6:18 ... -LL | let _ = intrinsics::const_allocate(4, 3) as * mut i32; +LL | let _ = intrinsics::const_allocate(4, 3) as *mut i32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | align has to be a power of 2, `3` is not a power of 2 diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs new file mode 100644 index 00000000000..407e69d41a0 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs @@ -0,0 +1,16 @@ +// run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(inline_const)] + +use std::intrinsics; + +struct ZST; + +fn main() { + const { + unsafe { + let _ = intrinsics::const_allocate(0, 0) as *mut ZST; + } + } +} diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs new file mode 100644 index 00000000000..aac90cd54cc --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs @@ -0,0 +1,36 @@ +// run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_mut_refs)] + +use std::intrinsics; + +const _X: () = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 4, 4); +}; + +const Y: &u32 = unsafe { + let ptr = intrinsics::const_allocate(4, 4) as *mut u32; + *ptr = 42; + &*ptr +}; + +const Z: &u32 = &42; + +const _Z: () = unsafe { + let ptr1 = Y as *const _ as *mut u8; + intrinsics::const_deallocate(ptr1, 4, 4); // nop + intrinsics::const_deallocate(ptr1, 2, 4); // nop + intrinsics::const_deallocate(ptr1, 4, 2); // nop + + let ptr2 = Z as *const _ as *mut u8; + intrinsics::const_deallocate(ptr2, 4, 4); // nop + intrinsics::const_deallocate(ptr2, 2, 4); // nop + intrinsics::const_deallocate(ptr2, 4, 2); // nop +}; + +fn main() { + assert_eq!(*Y, 42); + assert_eq!(*Z, 42); +} diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs new file mode 100644 index 00000000000..b6d89a58dce --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs @@ -0,0 +1,22 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_mut_refs)] + +use std::intrinsics; + +const _X: &'static u8 = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 4, 4); + &*ptr + //~^ error: evaluation of constant value failed +}; + +const _Y: u8 = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + let reference = &*ptr; + intrinsics::const_deallocate(ptr, 4, 4); + *reference + //~^ error: evaluation of constant value failed +}; + +fn main() {} diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr new file mode 100644 index 00000000000..4eb1c42e1f7 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_dangling.rs:10:5 + | +LL | &*ptr + | ^^^^^ pointer to alloc2 was dereferenced after this allocation got freed + +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_dangling.rs:18:5 + | +LL | *reference + | ^^^^^^^^^^ pointer to alloc4 was dereferenced after this allocation got freed + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs new file mode 100644 index 00000000000..4010b476990 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs @@ -0,0 +1,13 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] + +use std::intrinsics; + +const _X: () = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 4, 4); + intrinsics::const_deallocate(ptr, 4, 4); + //~^ error: evaluation of constant value failed +}; + +fn main() {} diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr new file mode 100644 index 00000000000..8177a08504b --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_duplicate.rs:9:5 + | +LL | intrinsics::const_deallocate(ptr, 4, 4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to alloc2 was dereferenced after this allocation got freed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs new file mode 100644 index 00000000000..031d70fdc88 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs @@ -0,0 +1,29 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] + +use std::intrinsics; + +const _X: () = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 4, 2); + //~^ error: evaluation of constant value failed +}; +const _Y: () = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 2, 4); + //~^ error: evaluation of constant value failed +}; + +const _Z: () = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 3, 4); + //~^ error: evaluation of constant value failed +}; + +const _W: () = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 4, 3); + //~^ error: evaluation of constant value failed +}; + +fn main() {} diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr new file mode 100644 index 00000000000..650b409b190 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr @@ -0,0 +1,27 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_incorrect_layout.rs:8:5 + | +LL | intrinsics::const_deallocate(ptr, 4, 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: alloc2 has size 4 and alignment 4, but gave size 4 and alignment 2 + +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_incorrect_layout.rs:13:5 + | +LL | intrinsics::const_deallocate(ptr, 2, 4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: alloc4 has size 4 and alignment 4, but gave size 2 and alignment 4 + +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_incorrect_layout.rs:19:5 + | +LL | intrinsics::const_deallocate(ptr, 3, 4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: alloc6 has size 4 and alignment 4, but gave size 3 and alignment 4 + +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_incorrect_layout.rs:25:5 + | +LL | intrinsics::const_deallocate(ptr, 4, 3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ align has to be a power of 2, `3` is not a power of 2 + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs new file mode 100644 index 00000000000..84fb4d2ea87 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs @@ -0,0 +1,17 @@ +// run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(inline_const)] + +use std::intrinsics; + +fn main() { + const { + unsafe { + let ptr1 = intrinsics::const_allocate(0, 0); + let ptr2 = intrinsics::const_allocate(0, 0); + intrinsics::const_deallocate(ptr1, 0, 0); + intrinsics::const_deallocate(ptr2, 0, 0); + } + } +} diff --git a/src/test/ui/consts/miri_unleashed/tls.stderr b/src/test/ui/consts/miri_unleashed/tls.stderr index ebe20348830..a49e50a3eaa 100644 --- a/src/test/ui/consts/miri_unleashed/tls.stderr +++ b/src/test/ui/consts/miri_unleashed/tls.stderr @@ -2,13 +2,13 @@ error[E0080]: could not evaluate static initializer --> $DIR/tls.rs:12:25 | LL | unsafe { let _val = A; } - | ^ cannot access thread local static (DefId(0:6 ~ tls[HASH]::A)) + | ^ cannot access thread local static (DefId(0:6 ~ tls[78b0]::A)) error[E0080]: could not evaluate static initializer --> $DIR/tls.rs:19:26 | LL | unsafe { let _val = &A; } - | ^ cannot access thread local static (DefId(0:6 ~ tls[HASH]::A)) + | ^ cannot access thread local static (DefId(0:6 ~ tls[78b0]::A)) warning: skipping const checks | diff --git a/src/test/ui/fmt/ifmt-unimpl.stderr b/src/test/ui/fmt/ifmt-unimpl.stderr index bee165437cb..6e8dd792191 100644 --- a/src/test/ui/fmt/ifmt-unimpl.stderr +++ b/src/test/ui/fmt/ifmt-unimpl.stderr @@ -5,6 +5,11 @@ LL | format!("{:X}", "3"); | ^^^ the trait `UpperHex` is not implemented for `str` | = note: required because of the requirements on the impl of `UpperHex` for `&str` +note: required by a bound in `ArgumentV1::<'a>::new_upper_hex` + --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL + | +LL | arg_new!(new_upper_hex, UpperHex); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `ArgumentV1::<'a>::new_upper_hex` = note: this error originates in the macro `$crate::__export::format_args` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr index e37ec7f2665..8096f08385c 100644 --- a/src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr +++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr @@ -6,7 +6,7 @@ LL | fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str { | | | lifetime `'a` defined here LL | s - | ^ returning this value requires that `'b` must outlive `'a` + | ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a` diff --git a/src/test/ui/generator/drop-control-flow.rs b/src/test/ui/generator/drop-control-flow.rs index 6319a29f5b7..8540f7617ac 100644 --- a/src/test/ui/generator/drop-control-flow.rs +++ b/src/test/ui/generator/drop-control-flow.rs @@ -1,5 +1,9 @@ // build-pass +// FIXME(eholk): temporarily disabled while drop range tracking is disabled +// (see generator_interior.rs:27) +// ignore-test + // A test to ensure generators capture values that were conditionally dropped, // and also that values that are dropped along all paths to a yield do not get // included in the generator type. diff --git a/src/test/ui/generator/issue-57478.rs b/src/test/ui/generator/issue-57478.rs index 39710febdb9..5c23ecbae32 100644 --- a/src/test/ui/generator/issue-57478.rs +++ b/src/test/ui/generator/issue-57478.rs @@ -1,5 +1,9 @@ // check-pass +// FIXME(eholk): temporarily disabled while drop range tracking is disabled +// (see generator_interior.rs:27) +// ignore-test + #![feature(negative_impls, generators)] struct Foo; diff --git a/src/test/ui/generator/issue-93161.rs b/src/test/ui/generator/issue-93161.rs new file mode 100644 index 00000000000..9988acbcb73 --- /dev/null +++ b/src/test/ui/generator/issue-93161.rs @@ -0,0 +1,93 @@ +// edition:2021 +// run-pass + +#![feature(never_type)] + +use std::future::Future; + +// See if we can run a basic `async fn` +pub async fn foo(x: &u32, y: u32) -> u32 { + let y = &y; + let z = 9; + let z = &z; + let y = async { *y + *z }.await; + let a = 10; + let a = &a; + *x + y + *a +} + +async fn add(x: u32, y: u32) -> u32 { + let a = async { x + y }; + a.await +} + +async fn build_aggregate(a: u32, b: u32, c: u32, d: u32) -> u32 { + let x = (add(a, b).await, add(c, d).await); + x.0 + x.1 +} + +enum Never {} +fn never() -> Never { + panic!() +} + +async fn includes_never(crash: bool, x: u32) -> u32 { + let mut result = async { x * x }.await; + if !crash { + return result; + } + #[allow(unused)] + let bad = never(); + result *= async { x + x }.await; + drop(bad); + result +} + +async fn partial_init(x: u32) -> u32 { + #[allow(unreachable_code)] + let _x: (String, !) = (String::new(), return async { x + x }.await); +} + +async fn read_exact(_from: &mut &[u8], _to: &mut [u8]) -> Option<()> { + Some(()) +} + +async fn hello_world() { + let data = [0u8; 1]; + let mut reader = &data[..]; + + let mut marker = [0u8; 1]; + read_exact(&mut reader, &mut marker).await.unwrap(); +} + +fn run_fut<T>(fut: impl Future<Output = T>) -> T { + use std::sync::Arc; + use std::task::{Context, Poll, Wake, Waker}; + + struct MyWaker; + impl Wake for MyWaker { + fn wake(self: Arc<Self>) { + unimplemented!() + } + } + + let waker = Waker::from(Arc::new(MyWaker)); + let mut context = Context::from_waker(&waker); + + 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 x = 5; + assert_eq!(run_fut(foo(&x, 7)), 31); + assert_eq!(run_fut(build_aggregate(1, 2, 3, 4)), 10); + assert_eq!(run_fut(includes_never(false, 4)), 16); + assert_eq!(run_fut(partial_init(4)), 8); + run_fut(hello_world()); +} diff --git a/src/test/ui/generator/partial-drop.rs b/src/test/ui/generator/partial-drop.rs index 36f6e78cb3b..e89e4b61bbf 100644 --- a/src/test/ui/generator/partial-drop.rs +++ b/src/test/ui/generator/partial-drop.rs @@ -1,3 +1,7 @@ +// FIXME(eholk): temporarily disabled while drop range tracking is disabled +// (see generator_interior.rs:27) +// ignore-test + #![feature(negative_impls, generators)] struct Foo; diff --git a/src/test/ui/generator/print/generator-print-verbose-1.stderr b/src/test/ui/generator/print/generator-print-verbose-1.stderr index 2b9bcb1bf8a..2f7faf520d9 100644 --- a/src/test/ui/generator/print/generator-print-verbose-1.stderr +++ b/src/test/ui/generator/print/generator-print-verbose-1.stderr @@ -9,7 +9,7 @@ note: generator is not `Send` as this value is used across a yield --> $DIR/generator-print-verbose-1.rs:35:9 | LL | let _non_send_gen = make_non_send_generator(); - | ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[HASH]::make_non_send_generator::{opaque#0}), [])` which is not `Send` + | ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[749a]::make_non_send_generator::{opaque#0}), [])` which is not `Send` LL | yield; | ^^^^^ yield occurs here, with `_non_send_gen` maybe used later LL | }; @@ -29,10 +29,10 @@ LL | require_send(send_gen); = help: the trait `Sync` is not implemented for `RefCell<i32>` = note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>` = note: required because it appears within the type `[make_gen2<Arc<RefCell<i32>>>::{closure#0} upvar_tys=(Arc<RefCell<i32>>) {()}]` - = note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[HASH]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])` - = note: required because it appears within the type `Opaque(DefId(0:42 ~ generator_print_verbose_1[HASH]::make_non_send_generator2::{opaque#0}), [])` - = note: required because it appears within the type `{Opaque(DefId(0:42 ~ generator_print_verbose_1[HASH]::make_non_send_generator2::{opaque#0}), []), ()}` - = note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:42 ~ generator_print_verbose_1[HASH]::make_non_send_generator2::{opaque#0}), []), ()}]` + = note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])` + = note: required because it appears within the type `Opaque(DefId(0:42 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])` + = note: required because it appears within the type `{Opaque(DefId(0:42 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), []), ()}` + = note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:42 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), []), ()}]` note: required by a bound in `require_send` --> $DIR/generator-print-verbose-1.rs:26:25 | diff --git a/src/test/ui/generic-associated-types/elided-in-expr-position.rs b/src/test/ui/generic-associated-types/elided-in-expr-position.rs new file mode 100644 index 00000000000..482d0d5c00a --- /dev/null +++ b/src/test/ui/generic-associated-types/elided-in-expr-position.rs @@ -0,0 +1,38 @@ +#![feature(generic_associated_types)] +#![allow(unused)] + +pub trait Trait { + type Assoc<'a> where Self: 'a; + + fn f(&self) -> Self::Assoc<'_>; + + // Disallow elision in return position, for now + fn g(&self) -> Self::Assoc; + //~^ ERROR missing generics for associated type `Trait::Assoc` +} + +pub struct Struct { + item: f32 +} + +pub struct GenericStruct<'a> { + ref_item: &'a f32 +} + +impl Trait for Struct { + type Assoc<'a> = GenericStruct<'a>; + + fn f(&self) -> Self::Assoc<'_> { + Self::Assoc { + ref_item: &self.item + } + } + + // Disallow elision in return position, for now + fn g(&self) -> Self::Assoc { + //~^ ERROR missing generics for associated type `Trait::Assoc` + todo!() + } +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/elided-in-expr-position.stderr b/src/test/ui/generic-associated-types/elided-in-expr-position.stderr new file mode 100644 index 00000000000..9263f3d67e3 --- /dev/null +++ b/src/test/ui/generic-associated-types/elided-in-expr-position.stderr @@ -0,0 +1,35 @@ +error[E0107]: missing generics for associated type `Trait::Assoc` + --> $DIR/elided-in-expr-position.rs:10:26 + | +LL | fn g(&self) -> Self::Assoc; + | ^^^^^ expected 1 lifetime argument + | +note: associated type defined here, with 1 lifetime parameter: `'a` + --> $DIR/elided-in-expr-position.rs:5:10 + | +LL | type Assoc<'a> where Self: 'a; + | ^^^^^ -- +help: add missing lifetime argument + | +LL | fn g(&self) -> Self::Assoc<'_>; + | ~~~~~~~~~ + +error[E0107]: missing generics for associated type `Trait::Assoc` + --> $DIR/elided-in-expr-position.rs:32:26 + | +LL | fn g(&self) -> Self::Assoc { + | ^^^^^ expected 1 lifetime argument + | +note: associated type defined here, with 1 lifetime parameter: `'a` + --> $DIR/elided-in-expr-position.rs:5:10 + | +LL | type Assoc<'a> where Self: 'a; + | ^^^^^ -- +help: add missing lifetime argument + | +LL | fn g(&self) -> Self::Assoc<'_> { + | ~~~~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/generic-associated-types/issue-92954.rs b/src/test/ui/generic-associated-types/issue-92954.rs new file mode 100644 index 00000000000..95c090ff4e9 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-92954.rs @@ -0,0 +1,10 @@ +// check-pass + +#![feature(generic_associated_types)] + +pub trait Foo { + type Assoc<'c>; + fn function() -> for<'x> fn(Self::Assoc<'x>); +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-93141.rs b/src/test/ui/generic-associated-types/issue-93141.rs new file mode 100644 index 00000000000..39ca77d13db --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-93141.rs @@ -0,0 +1,25 @@ +// check-pass + +#![feature(generic_associated_types)] + +pub trait Fooey: Sized { + type Context<'c> where Self: 'c; +} + +pub struct Handle<E: Fooey>(Option<Box<dyn for<'c> Fn(&mut E::Context<'c>)>>); + +fn tuple<T>() -> (Option<T>,) { (Option::None,) } + +pub struct FooImpl {} +impl Fooey for FooImpl { + type Context<'c> = &'c (); +} + +impl FooImpl { + pub fn fail1() -> Handle<Self> { + let (tx,) = tuple(); + Handle(tx) + } +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-93340.rs b/src/test/ui/generic-associated-types/issue-93340.rs new file mode 100644 index 00000000000..d065bde88c4 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-93340.rs @@ -0,0 +1,20 @@ +// check-pass + +#![feature(generic_associated_types)] + +pub trait Scalar: 'static { + type RefType<'a>: ScalarRef<'a>; +} + +pub trait ScalarRef<'a>: 'a {} + +fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefType<'b>) -> O { + todo!() +} + +fn build_expression<A: Scalar, B: Scalar, O: Scalar>( +) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O { + cmp_eq +} + +fn main() {} diff --git a/src/test/ui/intrinsics/const-eval-select-bad.rs b/src/test/ui/intrinsics/const-eval-select-bad.rs index a3171187e69..7d924e2b7f3 100644 --- a/src/test/ui/intrinsics/const-eval-select-bad.rs +++ b/src/test/ui/intrinsics/const-eval-select-bad.rs @@ -4,9 +4,9 @@ use std::intrinsics::const_eval_select; const fn not_fn_items() { const_eval_select((), || {}, || {}); - //~^ ERROR expected a `FnOnce<()>` closure + //~^ ERROR the trait bound const_eval_select((), 42, 0xDEADBEEF); - //~^ ERROR expected a `FnOnce<()>` closure + //~^ ERROR the trait bound //~| ERROR expected a `FnOnce<()>` closure } diff --git a/src/test/ui/intrinsics/const-eval-select-bad.stderr b/src/test/ui/intrinsics/const-eval-select-bad.stderr index 5e1ab584d80..06a7a2f63cf 100644 --- a/src/test/ui/intrinsics/const-eval-select-bad.stderr +++ b/src/test/ui/intrinsics/const-eval-select-bad.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]` +error[E0277]: the trait bound `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]: ~const FnOnce<()>` is not satisfied --> $DIR/const-eval-select-bad.rs:6:27 | LL | const_eval_select((), || {}, || {}); @@ -6,7 +6,12 @@ LL | const_eval_select((), || {}, || {}); | | | required by a bound introduced by this call | - = help: the trait `FnOnce<()>` is not implemented for `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]` + = help: the trait `~const FnOnce<()>` is not implemented for `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]` +note: the trait `FnOnce<()>` is implemented for `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`, but that implementation is not `const` + --> $DIR/const-eval-select-bad.rs:6:27 + | +LL | const_eval_select((), || {}, || {}); + | ^^^^^ = note: wrap the `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `const_eval_select` --> $SRC_DIR/core/src/intrinsics.rs:LL:COL @@ -14,7 +19,7 @@ note: required by a bound in `const_eval_select` LL | F: ~const FnOnce<ARG, Output = RET>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` -error[E0277]: expected a `FnOnce<()>` closure, found `{integer}` +error[E0277]: the trait bound `{integer}: ~const FnOnce<()>` is not satisfied --> $DIR/const-eval-select-bad.rs:8:27 | LL | const_eval_select((), 42, 0xDEADBEEF); @@ -22,7 +27,7 @@ LL | const_eval_select((), 42, 0xDEADBEEF); | | | required by a bound introduced by this call | - = help: the trait `FnOnce<()>` is not implemented for `{integer}` + = help: the trait `~const FnOnce<()>` is not implemented for `{integer}` = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `const_eval_select` --> $SRC_DIR/core/src/intrinsics.rs:LL:COL diff --git a/src/test/ui/issues/issue-16683.nll.stderr b/src/test/ui/issues/issue-16683.nll.stderr index 0e8f520353f..fff681b2e0b 100644 --- a/src/test/ui/issues/issue-16683.nll.stderr +++ b/src/test/ui/issues/issue-16683.nll.stderr @@ -1,20 +1,13 @@ -error[E0521]: borrowed data escapes outside of associated function +error: lifetime may not live long enough --> $DIR/issue-16683.rs:4:9 | LL | trait T<'a> { | -- lifetime `'a` defined here LL | fn a(&'a self) -> &'a bool; LL | fn b(&self) { - | ----- - | | - | `self` is a reference that is only valid in the associated function body - | let's call the lifetime of this reference `'1` + | - let's call the lifetime of this reference `'1` LL | self.a(); - | ^^^^^^^^ - | | - | `self` escapes the associated function body here - | argument requires that `'1` must outlive `'a` + | ^^^^^^^^ argument requires that `'1` must outlive `'a` error: aborting due to previous error -For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/issues/issue-17758.nll.stderr b/src/test/ui/issues/issue-17758.nll.stderr index b929fdbf368..613ef6b907c 100644 --- a/src/test/ui/issues/issue-17758.nll.stderr +++ b/src/test/ui/issues/issue-17758.nll.stderr @@ -1,20 +1,13 @@ -error[E0521]: borrowed data escapes outside of associated function +error: lifetime may not live long enough --> $DIR/issue-17758.rs:7:9 | LL | trait Foo<'a> { | -- lifetime `'a` defined here LL | fn foo(&'a self); LL | fn bar(&self) { - | ----- - | | - | `self` is a reference that is only valid in the associated function body - | let's call the lifetime of this reference `'1` + | - let's call the lifetime of this reference `'1` LL | self.foo(); - | ^^^^^^^^^^ - | | - | `self` escapes the associated function body here - | argument requires that `'1` must outlive `'a` + | ^^^^^^^^^^ argument requires that `'1` must outlive `'a` error: aborting due to previous error -For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/issues/issue-47377.stderr b/src/test/ui/issues/issue-47377.stderr index a7b8b1ca861..4f0fd948e76 100644 --- a/src/test/ui/issues/issue-47377.stderr +++ b/src/test/ui/issues/issue-47377.stderr @@ -7,10 +7,11 @@ LL | let _a = b + ", World!"; | | `+` cannot be used to concatenate two `&str` strings | &str | -help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + = note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference | LL | let _a = b.to_owned() + ", World!"; - | ~~~~~~~~~~~~ + | +++++++++++ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-47380.stderr b/src/test/ui/issues/issue-47380.stderr index f6222c77e2e..b04ac5536c4 100644 --- a/src/test/ui/issues/issue-47380.stderr +++ b/src/test/ui/issues/issue-47380.stderr @@ -7,10 +7,11 @@ LL | println!("🦀🦀🦀🦀🦀"); let _a = b + ", World!"; | | `+` cannot be used to concatenate two `&str` strings | &str | -help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + = note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference | LL | println!("🦀🦀🦀🦀🦀"); let _a = b.to_owned() + ", World!"; - | ~~~~~~~~~~~~ + | +++++++++++ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-5100.stderr b/src/test/ui/issues/issue-5100.stderr index de71e1d1a66..c87a3e348a2 100644 --- a/src/test/ui/issues/issue-5100.stderr +++ b/src/test/ui/issues/issue-5100.stderr @@ -59,10 +59,8 @@ LL | &(true, false) => () error[E0618]: expected function, found `(char, char)` --> $DIR/issue-5100.rs:48:14 | -LL | let v = [('a', 'b') - | ______________-^^^^^^^^^ -LL | | ('c', 'd'), - | |_______________________- call expression requires function +LL | let v = [('a', 'b') + | ^^^^^^^^^^- help: consider separating array elements with a comma: `,` error[E0308]: mismatched types --> $DIR/issue-5100.rs:55:19 diff --git a/src/test/ui/issues/issue-52213.nll.stderr b/src/test/ui/issues/issue-52213.nll.stderr index 359f91309d4..da31bcd5475 100644 --- a/src/test/ui/issues/issue-52213.nll.stderr +++ b/src/test/ui/issues/issue-52213.nll.stderr @@ -7,7 +7,7 @@ LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T { | lifetime `'a` defined here LL | match (&t,) { LL | ((u,),) => u, - | ^ returning this value requires that `'a` must outlive `'b` + | ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` diff --git a/src/test/ui/issues/issue-69455.stderr b/src/test/ui/issues/issue-69455.stderr index 95617e4ecc8..378fdc97dd3 100644 --- a/src/test/ui/issues/issue-69455.stderr +++ b/src/test/ui/issues/issue-69455.stderr @@ -1,14 +1,14 @@ error[E0282]: type annotations needed - --> $DIR/issue-69455.rs:29:5 + --> $DIR/issue-69455.rs:29:20 | LL | type Output; | ------------ `<Self as Test<Rhs>>::Output` defined here ... LL | println!("{}", 23u64.test(xs.iter().sum())); - | ^^^^^^^^^^^^^^^---------------------------^ - | | | - | | this method call resolves to `<Self as Test<Rhs>>::Output` - | cannot infer type for type parameter `T` declared on the associated function `new` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | this method call resolves to `<Self as Test<Rhs>>::Output` + | cannot infer type for type parameter `T` declared on the associated function `new_display` | = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/lint/lint-unconditional-recursion.rs b/src/test/ui/lint/lint-unconditional-recursion.rs index d2a0329585b..ad052d36f20 100644 --- a/src/test/ui/lint/lint-unconditional-recursion.rs +++ b/src/test/ui/lint/lint-unconditional-recursion.rs @@ -149,4 +149,46 @@ pub fn panics(x: bool) { } } +pub fn unreachable1() { + panic!(); + unreachable1(); // WARN unreachable statement +} + +pub fn unreachable2() { + loop {} + unreachable2(); // WARN unreachable statement +} + +pub fn drop_and_replace(mut a: Option<String>) { //~ ERROR function cannot return without recursing + a = None; + drop_and_replace(a); +} + +// Calls are assumed to return normally. +pub fn call() -> String { //~ ERROR function cannot return without recursing + let s = String::new(); + call(); + s +} + +// Arithmetic operations are assumed not to overflow. +pub fn overflow_check(a: i32, b: i32) { //~ ERROR function cannot return without recursing + let _ = a + b; + overflow_check(a, b); +} + +pub struct Point { + pub x: f32, + pub y: f32, +} + +impl Default for Point { + fn default() -> Self { //~ ERROR function cannot return without recursing + Point { + x: Default::default(), + ..Default::default() + } + } +} + fn main() {} diff --git a/src/test/ui/lint/lint-unconditional-recursion.stderr b/src/test/ui/lint/lint-unconditional-recursion.stderr index fb884e31299..c11b73f41ca 100644 --- a/src/test/ui/lint/lint-unconditional-recursion.stderr +++ b/src/test/ui/lint/lint-unconditional-recursion.stderr @@ -153,5 +153,49 @@ LL | self.as_ref() | = help: a `loop` may express intention better if this is on purpose -error: aborting due to 14 previous errors +error: function cannot return without recursing + --> $DIR/lint-unconditional-recursion.rs:162:1 + | +LL | pub fn drop_and_replace(mut a: Option<String>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +LL | a = None; +LL | drop_and_replace(a); + | ------------------- recursive call site + | + = help: a `loop` may express intention better if this is on purpose + +error: function cannot return without recursing + --> $DIR/lint-unconditional-recursion.rs:168:1 + | +LL | pub fn call() -> String { + | ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +LL | let s = String::new(); +LL | call(); + | ------ recursive call site + | + = help: a `loop` may express intention better if this is on purpose + +error: function cannot return without recursing + --> $DIR/lint-unconditional-recursion.rs:175:1 + | +LL | pub fn overflow_check(a: i32, b: i32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +LL | let _ = a + b; +LL | overflow_check(a, b); + | -------------------- recursive call site + | + = help: a `loop` may express intention better if this is on purpose + +error: function cannot return without recursing + --> $DIR/lint-unconditional-recursion.rs:186:5 + | +LL | fn default() -> Self { + | ^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +... +LL | ..Default::default() + | ------------------ recursive call site + | + = help: a `loop` may express intention better if this is on purpose + +error: aborting due to 18 previous errors diff --git a/src/test/ui/match/issue-82392.stdout b/src/test/ui/match/issue-82392.stdout index 4f46e32dc30..2054d43c409 100644 --- a/src/test/ui/match/issue-82392.stdout +++ b/src/test/ui/match/issue-82392.stdout @@ -7,13 +7,11 @@ extern crate std; // check-pass pub fn main() ({ - (if (true as bool) - ({ } as - ()) else if (let Some(a) = - ((Some as - fn(i32) -> Option<i32> {Option::<i32>::Some})((3 - as - i32)) - as Option<i32>) as bool) - ({ } as ()) as ()) - } as ()) + (if (true as bool) + ({ } as + ()) else if (let Some(a) = + ((Some as + fn(i32) -> Option<i32> {Option::<i32>::Some})((3 + as i32)) as Option<i32>) as bool) ({ } as ()) + as ()) + } as ()) diff --git a/src/test/ui/match/match-ref-mut-invariance.nll.stderr b/src/test/ui/match/match-ref-mut-invariance.nll.stderr index 1dc29d2088c..c8a7876dc54 100644 --- a/src/test/ui/match/match-ref-mut-invariance.nll.stderr +++ b/src/test/ui/match/match-ref-mut-invariance.nll.stderr @@ -6,7 +6,7 @@ LL | impl<'b> S<'b> { LL | fn bar<'a>(&'a mut self) -> &'a mut &'a i32 { | -- lifetime `'a` defined here LL | match self.0 { ref mut x => x } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a mutable reference to &i32 diff --git a/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr b/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr index 8b87c3da28b..11ddf1487dd 100644 --- a/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr +++ b/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr @@ -7,7 +7,7 @@ LL | fn bar<'a>(&'a mut self) -> &'a mut &'a i32 { | -- lifetime `'a` defined here LL | let ref mut x = self.0; LL | x - | ^ returning this value requires that `'a` must outlive `'b` + | ^ associated function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a mutable reference to &i32 diff --git a/src/test/ui/mismatched_types/overloaded-calls-bad.rs b/src/test/ui/mismatched_types/overloaded-calls-bad.rs index 902a6ec81d6..d62625faaaa 100644 --- a/src/test/ui/mismatched_types/overloaded-calls-bad.rs +++ b/src/test/ui/mismatched_types/overloaded-calls-bad.rs @@ -30,4 +30,5 @@ fn main() { //~^ ERROR this function takes 1 argument but 0 arguments were supplied let ans = s("burma", "shave"); //~^ ERROR this function takes 1 argument but 2 arguments were supplied + //~| ERROR mismatched types } diff --git a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr index 264d7cbb9b1..9ae9c474162 100644 --- a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr +++ b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr @@ -18,6 +18,12 @@ note: associated function defined here LL | extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; | ^^^^^^^^ +error[E0308]: mismatched types + --> $DIR/overloaded-calls-bad.rs:31:17 + | +LL | let ans = s("burma", "shave"); + | ^^^^^^^ expected `isize`, found `&str` + error[E0057]: this function takes 1 argument but 2 arguments were supplied --> $DIR/overloaded-calls-bad.rs:31:15 | @@ -32,7 +38,7 @@ note: associated function defined here LL | extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; | ^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0057, E0308. For more information about an error, try `rustc --explain E0057`. diff --git a/src/test/ui/nll/issue-52113.stderr b/src/test/ui/nll/issue-52113.stderr index dcf03386734..f70ae2edd7f 100644 --- a/src/test/ui/nll/issue-52113.stderr +++ b/src/test/ui/nll/issue-52113.stderr @@ -7,7 +7,7 @@ LL | fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> i | lifetime `'a` defined here ... LL | x - | ^ returning this value requires that `'a` must outlive `'b` + | ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` diff --git a/src/test/ui/nll/issue-55394.nll.stderr b/src/test/ui/nll/issue-55394.nll.stderr index d0723047ac0..24b8c84b4a9 100644 --- a/src/test/ui/nll/issue-55394.nll.stderr +++ b/src/test/ui/nll/issue-55394.nll.stderr @@ -6,7 +6,7 @@ LL | fn new(bar: &mut Bar) -> Self { | | | let's call the lifetime of this reference `'1` LL | Foo { bar } - | ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2` + | ^^^^^^^^^^^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: aborting due to previous error diff --git a/src/test/ui/nll/issue-67007-escaping-data.rs b/src/test/ui/nll/issue-67007-escaping-data.rs index 8c21737e05f..99b6d512261 100644 --- a/src/test/ui/nll/issue-67007-escaping-data.rs +++ b/src/test/ui/nll/issue-67007-escaping-data.rs @@ -14,7 +14,7 @@ struct Consumer<'tcx>(&'tcx ()); impl<'tcx> Consumer<'tcx> { fn bad_method<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) { - let other = self.use_fcx(fcx); //~ ERROR borrowed data + let other = self.use_fcx(fcx); //~ ERROR lifetime may not live long enough fcx.use_it(other); } diff --git a/src/test/ui/nll/issue-67007-escaping-data.stderr b/src/test/ui/nll/issue-67007-escaping-data.stderr index 2834d6fb0d2..ce067e23aa3 100644 --- a/src/test/ui/nll/issue-67007-escaping-data.stderr +++ b/src/test/ui/nll/issue-67007-escaping-data.stderr @@ -1,21 +1,14 @@ -error[E0521]: borrowed data escapes outside of associated function +error: lifetime may not live long enough --> $DIR/issue-67007-escaping-data.rs:17:21 | LL | impl<'tcx> Consumer<'tcx> { | ---- lifetime `'tcx` defined here LL | fn bad_method<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) { - | -- ----- --- `fcx` is a reference that is only valid in the associated function body - | | | - | | `self` declared here, outside of the associated function body - | lifetime `'a` defined here + | -- lifetime `'a` defined here LL | let other = self.use_fcx(fcx); - | ^^^^^^^^^^^^^^^^^ - | | - | `fcx` escapes the associated function body here - | argument requires that `'a` must outlive `'tcx` + | ^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'tcx` | = help: consider adding the following bound: `'a: 'tcx` error: aborting due to previous error -For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/nll/mir_check_cast_closure.stderr b/src/test/ui/nll/mir_check_cast_closure.stderr index 113e220e513..f34cafe308d 100644 --- a/src/test/ui/nll/mir_check_cast_closure.stderr +++ b/src/test/ui/nll/mir_check_cast_closure.stderr @@ -7,7 +7,7 @@ LL | fn bar<'a, 'b>() -> fn(&'a u32, &'b u32) -> &'a u32 { | lifetime `'a` defined here LL | let g: fn(_, _) -> _ = |_x, y| y; LL | g - | ^ returning this value requires that `'b` must outlive `'a` + | ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a` diff --git a/src/test/ui/nll/outlives-suggestion-more.stderr b/src/test/ui/nll/outlives-suggestion-more.stderr index a80e59d4822..7f98aa5801d 100644 --- a/src/test/ui/nll/outlives-suggestion-more.stderr +++ b/src/test/ui/nll/outlives-suggestion-more.stderr @@ -6,7 +6,7 @@ LL | fn foo1<'a, 'b, 'c, 'd>(x: &'a usize, y: &'b usize) -> (&'c usize, &'d usiz | | | lifetime `'a` defined here LL | (x, y) - | ^^^^^^ returning this value requires that `'a` must outlive `'c` + | ^^^^^^ function was supposed to return data with lifetime `'c` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'c` @@ -18,7 +18,7 @@ LL | fn foo1<'a, 'b, 'c, 'd>(x: &'a usize, y: &'b usize) -> (&'c usize, &'d usiz | | | lifetime `'b` defined here LL | (x, y) - | ^^^^^^ returning this value requires that `'b` must outlive `'d` + | ^^^^^^ function was supposed to return data with lifetime `'d` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'd` @@ -35,7 +35,7 @@ LL | fn foo2<'a, 'b, 'c>(x: &'a usize, y: &'b usize) -> (&'c usize, &'static usi | | | lifetime `'a` defined here LL | (x, y) - | ^^^^^^ returning this value requires that `'a` must outlive `'c` + | ^^^^^^ function was supposed to return data with lifetime `'c` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'c` diff --git a/src/test/ui/nll/outlives-suggestion-simple.rs b/src/test/ui/nll/outlives-suggestion-simple.rs index 41e4d83aa92..496cf92400c 100644 --- a/src/test/ui/nll/outlives-suggestion-simple.rs +++ b/src/test/ui/nll/outlives-suggestion-simple.rs @@ -70,7 +70,7 @@ pub struct Foo2<'a> { impl<'a> Foo2<'a> { // should not produce outlives suggestions to name 'self fn get_bar(&self) -> Bar2 { - Bar2::new(&self) //~ERROR borrowed data escapes outside of associated function + Bar2::new(&self) //~ERROR lifetime may not live long enough } } diff --git a/src/test/ui/nll/outlives-suggestion-simple.stderr b/src/test/ui/nll/outlives-suggestion-simple.stderr index 3b2017d2d03..8e6e4f1a476 100644 --- a/src/test/ui/nll/outlives-suggestion-simple.stderr +++ b/src/test/ui/nll/outlives-suggestion-simple.stderr @@ -6,7 +6,7 @@ LL | fn foo1<'a, 'b>(x: &'a usize) -> &'b usize { | | | lifetime `'a` defined here LL | x - | ^ returning this value requires that `'a` must outlive `'b` + | ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` @@ -53,7 +53,7 @@ LL | fn foo4<'a, 'b, 'c>(x: &'a usize) -> (&'b usize, &'c usize) { | lifetime `'a` defined here ... LL | (x, x) - | ^^^^^^ returning this value requires that `'a` must outlive `'b` + | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` @@ -73,7 +73,7 @@ LL | impl<'a> Bar<'a> { LL | pub fn get<'b>(&self) -> &'b usize { | -- lifetime `'b` defined here LL | self.x - | ^^^^^^ returning this value requires that `'a` must outlive `'b` + | ^^^^^^ associated function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` @@ -85,28 +85,20 @@ LL | impl<'a> Baz<'a> { LL | fn get<'b>(&'b self) -> &'a i32 { | -- lifetime `'b` defined here LL | self.x - | ^^^^^^ returning this value requires that `'b` must outlive `'a` + | ^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a` -error[E0521]: borrowed data escapes outside of associated function +error: lifetime may not live long enough --> $DIR/outlives-suggestion-simple.rs:73:9 | LL | impl<'a> Foo2<'a> { | -- lifetime `'a` defined here LL | // should not produce outlives suggestions to name 'self LL | fn get_bar(&self) -> Bar2 { - | ----- - | | - | `self` declared here, outside of the associated function body - | `self` is a reference that is only valid in the associated function body - | let's call the lifetime of this reference `'1` + | - let's call the lifetime of this reference `'1` LL | Bar2::new(&self) - | ^^^^^^^^^^^^^^^^ - | | - | `self` escapes the associated function body here - | argument requires that `'1` must outlive `'a` + | ^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'a` error: aborting due to 9 previous errors -For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr index 5e56e12eda0..3e6fe789a8b 100644 --- a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr +++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr @@ -4,11 +4,11 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> { | -- ^^^^^^^^^^^^ | | - | hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[HASH]::foo), BrAnon(0)) T` captures the anonymous lifetime defined here + | hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0)) T` captures the anonymous lifetime defined here | -help: to declare that the `impl Trait` captures `ReFree(DefId(0:8 ~ impl_trait_captures[HASH]::foo), BrAnon(0))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[HASH]::foo), BrAnon(0))` lifetime bound +help: to declare that the `impl Trait` captures `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0))` lifetime bound | -LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[HASH]::foo), BrAnon(0)) { +LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0)) { | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/nll/type-alias-free-regions.nll.stderr b/src/test/ui/nll/type-alias-free-regions.nll.stderr index bde73b05894..45fd5a2f1d6 100644 --- a/src/test/ui/nll/type-alias-free-regions.nll.stderr +++ b/src/test/ui/nll/type-alias-free-regions.nll.stderr @@ -6,7 +6,7 @@ LL | impl<'a> FromBox<'a> for C<'a> { LL | fn from_box(b: Box<B>) -> Self { | - has type `Box<Box<&'1 isize>>` LL | C { f: b } - | ^^^^^^^^^^ returning this value requires that `'1` must outlive `'a` + | ^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/type-alias-free-regions.rs:27:9 @@ -16,7 +16,7 @@ LL | impl<'a> FromTuple<'a> for C<'a> { LL | fn from_tuple(b: (B,)) -> Self { | - has type `(Box<&'1 isize>,)` LL | C { f: Box::new(b.0) } - | ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'a` + | ^^^^^^^^^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1` error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/type-check-pointer-coercions.stderr b/src/test/ui/nll/type-check-pointer-coercions.stderr index ccb3d33ac40..b392c2007d3 100644 --- a/src/test/ui/nll/type-check-pointer-coercions.stderr +++ b/src/test/ui/nll/type-check-pointer-coercions.stderr @@ -6,7 +6,7 @@ LL | fn shared_to_const<'a, 'b>(x: &&'a i32) -> *const &'b i32 { | | | lifetime `'a` defined here LL | x - | ^ returning this value requires that `'a` must outlive `'b` + | ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` @@ -18,7 +18,7 @@ LL | fn unique_to_const<'a, 'b>(x: &mut &'a i32) -> *const &'b i32 { | | | lifetime `'a` defined here LL | x - | ^ returning this value requires that `'a` must outlive `'b` + | ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` @@ -47,7 +47,7 @@ LL | fn unique_to_mut<'a, 'b>(x: &mut &'a i32) -> *mut &'b i32 { | lifetime `'a` defined here LL | // Two errors because *mut is invariant LL | x - | ^ returning this value requires that `'a` must outlive `'b` + | ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a mutable pointer to &i32 @@ -64,7 +64,7 @@ LL | fn mut_to_const<'a, 'b>(x: *mut &'a i32) -> *const &'b i32 { | | | lifetime `'a` defined here LL | x - | ^ returning this value requires that `'a` must outlive `'b` + | ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` @@ -77,7 +77,7 @@ LL | fn array_elem<'a, 'b>(x: &'a i32) -> *const &'b i32 { | lifetime `'a` defined here ... LL | y - | ^ returning this value requires that `'a` must outlive `'b` + | ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` @@ -90,7 +90,7 @@ LL | fn array_coerce<'a, 'b>(x: &'a i32) -> *const [&'b i32; 3] { | lifetime `'a` defined here ... LL | y - | ^ returning this value requires that `'a` must outlive `'b` + | ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` @@ -103,7 +103,7 @@ LL | fn nested_array<'a, 'b>(x: &'a i32) -> *const [&'b i32; 2] { | lifetime `'a` defined here ... LL | y - | ^ returning this value requires that `'a` must outlive `'b` + | ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` diff --git a/src/test/ui/nll/user-annotations/wf-self-type.stderr b/src/test/ui/nll/user-annotations/wf-self-type.stderr index 33bb1c519b1..902b4c68755 100644 --- a/src/test/ui/nll/user-annotations/wf-self-type.stderr +++ b/src/test/ui/nll/user-annotations/wf-self-type.stderr @@ -6,7 +6,7 @@ LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () { | | | lifetime `'a` defined here LL | Foo::xmute(u) - | ^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a` diff --git a/src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr index 900cdfca244..61e96f59fed 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr @@ -7,7 +7,7 @@ LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait { | lifetime `'a` defined here ... LL | ss - | ^^ returning this value requires that `'a` must outlive `'b` + | ^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` diff --git a/src/test/ui/parser/issues/issue-93282.rs b/src/test/ui/parser/issues/issue-93282.rs new file mode 100644 index 00000000000..7be8b25363e --- /dev/null +++ b/src/test/ui/parser/issues/issue-93282.rs @@ -0,0 +1,4 @@ +fn main() { + f<'a,> + //~^ ERROR expected +} diff --git a/src/test/ui/parser/issues/issue-93282.stderr b/src/test/ui/parser/issues/issue-93282.stderr new file mode 100644 index 00000000000..20e6c3ed8a8 --- /dev/null +++ b/src/test/ui/parser/issues/issue-93282.stderr @@ -0,0 +1,13 @@ +error: expected one of `.`, `:`, `;`, `?`, `for`, `loop`, `while`, `{`, `}`, or an operator, found `,` + --> $DIR/issue-93282.rs:2:9 + | +LL | f<'a,> + | ^ expected one of 10 possible tokens + | +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments + | +LL | f::<'a,> + | ++ + +error: aborting due to previous error + diff --git a/src/test/ui/proc-macro/cfg-eval-inner.stdout b/src/test/ui/proc-macro/cfg-eval-inner.stdout index debbad57a86..9d25def587c 100644 --- a/src/test/ui/proc-macro/cfg-eval-inner.stdout +++ b/src/test/ui/proc-macro/cfg-eval-inner.stdout @@ -1,9 +1,9 @@ PRINT-ATTR INPUT (DISPLAY): impl Foo < [u8 ; - { - #! [rustc_dummy(cursed_inner)] #! [allow(unused)] struct Inner - { field : [u8 ; { #! [rustc_dummy(another_cursed_inner)] 1 }] } 0 - }] > { #! [rustc_dummy(evaluated_attr)] fn bar() {} } +{ + #! [rustc_dummy(cursed_inner)] #! [allow(unused)] struct Inner + { field : [u8 ; { #! [rustc_dummy(another_cursed_inner)] 1 }] } 0 +}] > { #! [rustc_dummy(evaluated_attr)] fn bar() {} } PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "impl", diff --git a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.rs b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.rs index 113235051b2..0c1c51c01a8 100644 --- a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.rs +++ b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.rs @@ -4,7 +4,14 @@ extern crate test_macros; #[derive(Print)] -enum ProceduralMasqueradeDummyType { //~ ERROR using +enum ProceduralMasqueradeDummyType { +//~^ ERROR using +//~| WARN this was previously +//~| ERROR using +//~| WARN this was previously +//~| ERROR using +//~| WARN this was previously +//~| ERROR using //~| WARN this was previously Input } diff --git a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stderr b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stderr index dff71c9eacd..554613be65a 100644 --- a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stderr +++ b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stderr @@ -9,7 +9,37 @@ LL | enum ProceduralMasqueradeDummyType { = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling. -error: aborting due to previous error +error: using `procedural-masquerade` crate + --> $DIR/issue-73933-procedural-masquerade.rs:7:6 + | +LL | enum ProceduralMasqueradeDummyType { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> + = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling. + +error: using `procedural-masquerade` crate + --> $DIR/issue-73933-procedural-masquerade.rs:7:6 + | +LL | enum ProceduralMasqueradeDummyType { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> + = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling. + +error: using `procedural-masquerade` crate + --> $DIR/issue-73933-procedural-masquerade.rs:7:6 + | +LL | enum ProceduralMasqueradeDummyType { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> + = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling. + +error: aborting due to 4 previous errors Future incompatibility report: Future breakage diagnostic: error: using `procedural-masquerade` crate @@ -23,3 +53,36 @@ LL | enum ProceduralMasqueradeDummyType { = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling. +Future breakage diagnostic: +error: using `procedural-masquerade` crate + --> $DIR/issue-73933-procedural-masquerade.rs:7:6 + | +LL | enum ProceduralMasqueradeDummyType { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> + = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling. + +Future breakage diagnostic: +error: using `procedural-masquerade` crate + --> $DIR/issue-73933-procedural-masquerade.rs:7:6 + | +LL | enum ProceduralMasqueradeDummyType { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> + = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling. + +Future breakage diagnostic: +error: using `procedural-masquerade` crate + --> $DIR/issue-73933-procedural-masquerade.rs:7:6 + | +LL | enum ProceduralMasqueradeDummyType { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> + = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling. + diff --git a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stdout b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stdout index 8a8fbf06824..50334589d0b 100644 --- a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stdout +++ b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stdout @@ -14,9 +14,9 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "Input", - span: #0 bytes(173..178), + span: #0 bytes(315..320), }, ], - span: #0 bytes(121..180), + span: #0 bytes(121..322), }, ] diff --git a/src/test/ui/proc-macro/issue-75930-derive-cfg.stderr b/src/test/ui/proc-macro/issue-75930-derive-cfg.stderr index 25f36108001..69d72b55cdf 100644 --- a/src/test/ui/proc-macro/issue-75930-derive-cfg.stderr +++ b/src/test/ui/proc-macro/issue-75930-derive-cfg.stderr @@ -11,5 +11,17 @@ LL | #[derive(Print)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202> -warning: 1 warning emitted +warning: derive helper attribute is used before it is introduced + --> $DIR/issue-75930-derive-cfg.rs:19:3 + | +LL | #[print_helper(a)] + | ^^^^^^^^^^^^ +... +LL | #[derive(Print)] + | ----- the attribute is introduced here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202> + +warning: 2 warnings emitted diff --git a/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout index fdd178a5229..c81fa201cbc 100644 --- a/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout +++ b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout @@ -4,23 +4,23 @@ struct Foo < #[cfg(FALSE)] A, B > #[cfg(FALSE)] first : String, #[cfg_attr(FALSE, deny(warnings))] second : bool, third : [u8 ; - { - #[cfg(FALSE)] struct Bar ; #[cfg(not(FALSE))] struct Inner ; - #[cfg(FALSE)] let a = 25 ; match true - { - #[cfg(FALSE)] true => {}, - #[cfg_attr(not(FALSE), allow(warnings))] false => {}, _ => {} - } ; #[print_helper(should_be_removed)] fn removed_fn() - { #! [cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn - kept_fn() { #! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum - { - Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] String, u8) - } struct - TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] bool, u8) ; fn plain_removed_fn() - { #! [cfg_attr(not(FALSE), cfg(FALSE))] } 0 - }], #[print_helper(d)] fourth : B + { + #[cfg(FALSE)] struct Bar ; #[cfg(not(FALSE))] struct Inner ; + #[cfg(FALSE)] let a = 25 ; match true + { + #[cfg(FALSE)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))] + false => {}, _ => {} + } ; #[print_helper(should_be_removed)] fn removed_fn() + { #! [cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() + { #! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum + { + Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32, + #[cfg(FALSE)] String, u8) + } struct + TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32, + #[cfg(FALSE)] bool, u8) ; fn plain_removed_fn() + { #! [cfg_attr(not(FALSE), cfg(FALSE))] } 0 + }], #[print_helper(d)] fourth : B } PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { @@ -1276,14 +1276,14 @@ PRINT-DERIVE INPUT (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[print_hel { second : bool, third : [u8 ; - { - #[cfg(not(FALSE))] struct Inner ; match true - { #[allow(warnings)] false => {}, _ => {} } ; #[print_helper(c)] - #[cfg(not(FALSE))] fn kept_fn() - { #! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum - { Foo(#[cfg(not(FALSE))] i32, u8) } struct - TupleStruct(#[cfg(not(FALSE))] i32, u8) ; 0 - }], #[print_helper(d)] fourth : B + { + #[cfg(not(FALSE))] struct Inner ; match true + { #[allow(warnings)] false => {}, _ => {} } ; #[print_helper(c)] + #[cfg(not(FALSE))] fn kept_fn() + { #! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum + { Foo(#[cfg(not(FALSE))] i32, u8) } struct + TupleStruct(#[cfg(not(FALSE))] i32, u8) ; 0 + }], #[print_helper(d)] fourth : B } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Punct { diff --git a/src/test/ui/proc-macro/macro-rules-derive-cfg.stdout b/src/test/ui/proc-macro/macro-rules-derive-cfg.stdout index 6e2b6a2e5bd..74641058ef3 100644 --- a/src/test/ui/proc-macro/macro-rules-derive-cfg.stdout +++ b/src/test/ui/proc-macro/macro-rules-derive-cfg.stdout @@ -2,10 +2,10 @@ PRINT-DERIVE INPUT (DISPLAY): struct Foo { val : [bool ; - { - let a = #[rustc_dummy(first)] #[rustc_dummy(second)] - { #! [allow(unused)] 30 } ; 0 - }] + { + let a = #[rustc_dummy(first)] #[rustc_dummy(second)] + { #! [allow(unused)] 30 } ; 0 + }] } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { diff --git a/src/test/ui/proc-macro/quote-debug.stdout b/src/test/ui/proc-macro/quote-debug.stdout index 4bdc04b9ac4..79651f01b95 100644 --- a/src/test/ui/proc-macro/quote-debug.stdout +++ b/src/test/ui/proc-macro/quote-debug.stdout @@ -19,29 +19,27 @@ extern crate proc_macro; fn main() { [crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("let", - crate::Span::recover_proc_macro_span(0)))), - crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("hello", - crate::Span::recover_proc_macro_span(1)))), - crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3d}', - crate::Spacing::Alone))), - crate::TokenStream::from(crate::TokenTree::Literal({ - let mut iter = - "\"world\"".parse::<crate::TokenStream>().unwrap().into_iter(); - if let (Some(crate::TokenTree::Literal(mut lit)), - None) = - (iter.next(), - iter.next()) - { - lit.set_span(crate::Span::recover_proc_macro_span(2)); - lit - } else { - { - ::core::panicking::panic("internal error: entered unreachable code") - } - } - })), - crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3b}', - crate::Spacing::Alone)))].iter().cloned().collect::<crate::TokenStream>() + crate::Span::recover_proc_macro_span(0)))), + crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("hello", + crate::Span::recover_proc_macro_span(1)))), + crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3d}', + crate::Spacing::Alone))), + crate::TokenStream::from(crate::TokenTree::Literal({ + let mut iter = + "\"world\"".parse::<crate::TokenStream>().unwrap().into_iter(); + if let (Some(crate::TokenTree::Literal(mut lit)), + None) = + (iter.next(), iter.next()) { + lit.set_span(crate::Span::recover_proc_macro_span(2)); + lit + } else { + { + ::core::panicking::panic("internal error: entered unreachable code") + } + } + })), + crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3b}', + crate::Spacing::Alone)))].iter().cloned().collect::<crate::TokenStream>() } const _: () = { diff --git a/src/test/ui/reachable/expr_unary.rs b/src/test/ui/reachable/expr_unary.rs index e229d22ebc7..190c7447dcc 100644 --- a/src/test/ui/reachable/expr_unary.rs +++ b/src/test/ui/reachable/expr_unary.rs @@ -5,8 +5,8 @@ #![deny(unreachable_code)] fn foo() { - let x: ! = ! { return; }; //~ ERROR unreachable - //~| ERROR cannot apply unary operator `!` to type `!` + let x: ! = * { return; }; //~ ERROR unreachable + //~| ERROR type `!` cannot be dereferenced } fn main() { } diff --git a/src/test/ui/reachable/expr_unary.stderr b/src/test/ui/reachable/expr_unary.stderr index 063d841c25e..0a763087c6f 100644 --- a/src/test/ui/reachable/expr_unary.stderr +++ b/src/test/ui/reachable/expr_unary.stderr @@ -1,13 +1,13 @@ -error[E0600]: cannot apply unary operator `!` to type `!` +error[E0614]: type `!` cannot be dereferenced --> $DIR/expr_unary.rs:8:16 | -LL | let x: ! = ! { return; }; - | ^^^^^^^^^^^^^ cannot apply unary operator `!` +LL | let x: ! = * { return; }; + | ^^^^^^^^^^^^^ error: unreachable expression --> $DIR/expr_unary.rs:8:16 | -LL | let x: ! = ! { return; }; +LL | let x: ! = * { return; }; | ^^^^------^^^ | | | | | any code following this expression is unreachable @@ -21,4 +21,4 @@ LL | #![deny(unreachable_code)] error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0600`. +For more information about this error, try `rustc --explain E0614`. diff --git a/src/test/ui/recursion/issue-83150.rs b/src/test/ui/recursion/issue-83150.rs index 650ad22d206..dc25004f89b 100644 --- a/src/test/ui/recursion/issue-83150.rs +++ b/src/test/ui/recursion/issue-83150.rs @@ -6,6 +6,6 @@ fn main() { func(&mut iter) } -fn func<T: Iterator<Item = u8>>(iter: &mut T) { +fn func<T: Iterator<Item = u8>>(iter: &mut T) { //~ WARN function cannot return without recursing func(&mut iter.map(|x| x + 1)) } diff --git a/src/test/ui/recursion/issue-83150.stderr b/src/test/ui/recursion/issue-83150.stderr index d45bfc3ca55..4c8469be626 100644 --- a/src/test/ui/recursion/issue-83150.stderr +++ b/src/test/ui/recursion/issue-83150.stderr @@ -1,8 +1,19 @@ +warning: function cannot return without recursing + --> $DIR/issue-83150.rs:9:1 + | +LL | fn func<T: Iterator<Item = u8>>(iter: &mut T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +LL | func(&mut iter.map(|x| x + 1)) + | ------------------------------ recursive call site + | + = note: `#[warn(unconditional_recursion)]` on by default + = help: a `loop` may express intention better if this is on purpose + error[E0275]: overflow evaluating the requirement `Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>: Iterator` | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`) = note: required because of the requirements on the impl of `Iterator` for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>` -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/regions/region-object-lifetime-2.nll.stderr b/src/test/ui/regions/region-object-lifetime-2.nll.stderr index db45a03ad18..d95289f3f9d 100644 --- a/src/test/ui/regions/region-object-lifetime-2.nll.stderr +++ b/src/test/ui/regions/region-object-lifetime-2.nll.stderr @@ -6,7 +6,7 @@ LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () { | | | lifetime `'a` defined here LL | x.borrowed() - | ^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr index 7e8f78067e0..92588819076 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr @@ -31,7 +31,7 @@ LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> { | | | lifetime `'a` defined here LL | Box::new(v) - | ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b` + | ^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr index 62032bcb609..246b6483c21 100644 --- a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr +++ b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr @@ -1,18 +1,13 @@ -error[E0521]: borrowed data escapes outside of function +error: lifetime may not live long enough --> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:20:5 | LL | fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) { - | -- -- - - `b` is a reference that is only valid in the function body - | | | | - | | | `a` declared here, outside of the function body - | | lifetime `'b` defined here + | -- -- lifetime `'b` defined here + | | | lifetime `'a` defined here LL | // Here the value provided for 'y is 'b, and hence 'b:'a does not hold. LL | f.method(b); - | ^^^^^^^^^^^ - | | - | `b` escapes the function body here - | argument requires that `'b` must outlive `'a` + | ^^^^^^^^^^^ argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of the type Inv<'_>, which makes the generic argument '_ invariant @@ -21,4 +16,3 @@ LL | f.method(b); error: aborting due to previous error -For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/regions/regions-bounds.nll.stderr b/src/test/ui/regions/regions-bounds.nll.stderr index dd702755c7e..84226a57553 100644 --- a/src/test/ui/regions/regions-bounds.nll.stderr +++ b/src/test/ui/regions/regions-bounds.nll.stderr @@ -6,7 +6,7 @@ LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> { | | | lifetime `'a` defined here LL | return e; - | ^ returning this value requires that `'a` must outlive `'b` + | ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` @@ -18,7 +18,7 @@ LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> { | | | lifetime `'a` defined here LL | return e; - | ^ returning this value requires that `'a` must outlive `'b` + | ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr index c2bd3bbf823..25566742099 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr +++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr @@ -7,7 +7,7 @@ LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + | lifetime `'a` defined here LL | // A outlives 'a AND 'b...but not 'c. LL | Box::new(v) as Box<dyn SomeTrait + 'a> - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'c` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'c` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'c` diff --git a/src/test/ui/regions/regions-creating-enums4.nll.stderr b/src/test/ui/regions/regions-creating-enums4.nll.stderr index dda374c90d9..91cf57e099d 100644 --- a/src/test/ui/regions/regions-creating-enums4.nll.stderr +++ b/src/test/ui/regions/regions-creating-enums4.nll.stderr @@ -6,7 +6,7 @@ LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> { | | | lifetime `'a` defined here LL | Ast::Add(x, y) - | ^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` diff --git a/src/test/ui/regions/regions-early-bound-error-method.nll.stderr b/src/test/ui/regions/regions-early-bound-error-method.nll.stderr index 4957bcf3f73..7f10c051f29 100644 --- a/src/test/ui/regions/regions-early-bound-error-method.nll.stderr +++ b/src/test/ui/regions/regions-early-bound-error-method.nll.stderr @@ -6,7 +6,7 @@ LL | impl<'a> Box<'a> { LL | fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a isize { | -- lifetime `'b` defined here LL | g2.get() - | ^^^^^^^^ returning this value requires that `'b` must outlive `'a` + | ^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a` diff --git a/src/test/ui/regions/regions-free-region-ordering-incorrect.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-incorrect.nll.stderr index 106d3df2744..f7c75033c04 100644 --- a/src/test/ui/regions/regions-free-region-ordering-incorrect.nll.stderr +++ b/src/test/ui/regions/regions-free-region-ordering-incorrect.nll.stderr @@ -9,7 +9,7 @@ LL | / match self.next { LL | | Some(ref next) => next.get(), LL | | None => &self.val LL | | } - | |_________^ returning this value requires that `'a` must outlive `'b` + | |_________^ associated function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` diff --git a/src/test/ui/regions/regions-infer-not-param.nll.stderr b/src/test/ui/regions/regions-infer-not-param.nll.stderr index e211f9d1391..3183aee23d9 100644 --- a/src/test/ui/regions/regions-infer-not-param.nll.stderr +++ b/src/test/ui/regions/regions-infer-not-param.nll.stderr @@ -2,7 +2,7 @@ error: lifetime may not live long enough --> $DIR/regions-infer-not-param.rs:15:54 | LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p } - | -- -- lifetime `'b` defined here ^ returning this value requires that `'a` must outlive `'b` + | -- -- lifetime `'b` defined here ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | | | lifetime `'a` defined here | @@ -25,7 +25,7 @@ error: lifetime may not live long enough --> $DIR/regions-infer-not-param.rs:19:63 | LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } - | -- -- lifetime `'b` defined here ^ returning this value requires that `'a` must outlive `'b` + | -- -- lifetime `'b` defined here ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | | | lifetime `'a` defined here | diff --git a/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr b/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr index bf325d56013..26f0fcae638 100644 --- a/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr +++ b/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr @@ -7,7 +7,7 @@ LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy { | lifetime `'a` defined here LL | // Without knowing 'a:'b, we can't coerce LL | x - | ^ returning this value requires that `'a` must outlive `'b` + | ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a mutable reference to dyn Dummy @@ -23,7 +23,7 @@ LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dum | lifetime `'a` defined here LL | // We can't coerce because it is packed in `Wrapper` LL | x - | ^ returning this value requires that `'b` must outlive `'a` + | ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a mutable reference to dyn Dummy diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs index 34d2d84da93..4a36515b991 100644 --- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs +++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs @@ -14,10 +14,12 @@ fn _if_let_guard() { //~^ ERROR `let` expressions in this position are unstable () if true && let 0 = 1 => {} - //~^ ERROR `let` expressions in this position are unstable + //~^ ERROR `if let` guards are experimental + //~| ERROR `let` expressions in this position are unstable () if let 0 = 1 && true => {} - //~^ ERROR `let` expressions in this position are unstable + //~^ ERROR `if let` guards are experimental + //~| ERROR `let` expressions in this position are unstable () if (let 0 = 1) && true => {} //~^ ERROR `let` expressions in this position are unstable @@ -30,14 +32,17 @@ fn _if_let_guard() { //~| ERROR `let` expressions in this position are unstable () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} - //~^ ERROR `let` expressions in this position are unstable + //~^ ERROR `if let` guards are experimental + //~| ERROR `let` expressions in this position are unstable //~| ERROR `let` expressions in this position are unstable //~| ERROR `let` expressions in this position are unstable //~| ERROR `let` expressions in this position are unstable //~| ERROR `let` expressions in this position are unstable () if let Range { start: _, end: _ } = (true..true) && false => {} - //~^ ERROR `let` expressions in this position are unstable + //~^ ERROR `if let` guards are experimental + //~| ERROR `let` expressions in this position are unstable + _ => {} } } diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr index 0cda6ba9a99..8d93fb87f7a 100644 --- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr +++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr @@ -1,5 +1,5 @@ error: no rules expected the token `let` - --> $DIR/feature-gate.rs:64:15 + --> $DIR/feature-gate.rs:69:15 | LL | macro_rules! use_expr { | --------------------- when calling this macro @@ -18,7 +18,47 @@ LL | () if let 0 = 1 => {} = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` error[E0658]: `if let` guards are experimental - --> $DIR/feature-gate.rs:60:12 + --> $DIR/feature-gate.rs:16:12 + | +LL | () if true && let 0 = 1 => {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` + +error[E0658]: `if let` guards are experimental + --> $DIR/feature-gate.rs:20:12 + | +LL | () if let 0 = 1 && true => {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` + +error[E0658]: `if let` guards are experimental + --> $DIR/feature-gate.rs:34:12 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` + +error[E0658]: `if let` guards are experimental + --> $DIR/feature-gate.rs:42:12 + | +LL | () if let Range { start: _, end: _ } = (true..true) && false => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` + +error[E0658]: `if let` guards are experimental + --> $DIR/feature-gate.rs:65:12 | LL | () if let 0 = 1 => {} | ^^^^^^^^^^^^ @@ -55,7 +95,7 @@ LL | () if true && let 0 = 1 => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:19:15 + --> $DIR/feature-gate.rs:20:15 | LL | () if let 0 = 1 && true => {} | ^^^^^^^^^ @@ -64,7 +104,7 @@ LL | () if let 0 = 1 && true => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:22:16 + --> $DIR/feature-gate.rs:24:16 | LL | () if (let 0 = 1) && true => {} | ^^^^^^^^^ @@ -73,7 +113,7 @@ LL | () if (let 0 = 1) && true => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:25:24 + --> $DIR/feature-gate.rs:27:24 | LL | () if true && (let 0 = 1) => {} | ^^^^^^^^^ @@ -82,7 +122,7 @@ LL | () if true && (let 0 = 1) => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:28:16 + --> $DIR/feature-gate.rs:30:16 | LL | () if (let 0 = 1) && (let 0 = 1) => {} | ^^^^^^^^^ @@ -91,7 +131,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:28:31 + --> $DIR/feature-gate.rs:30:31 | LL | () if (let 0 = 1) && (let 0 = 1) => {} | ^^^^^^^^^ @@ -100,7 +140,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:32:15 + --> $DIR/feature-gate.rs:34:15 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -109,7 +149,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:32:28 + --> $DIR/feature-gate.rs:34:28 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -118,7 +158,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:32:42 + --> $DIR/feature-gate.rs:34:42 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -127,7 +167,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:32:55 + --> $DIR/feature-gate.rs:34:55 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -136,7 +176,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:32:68 + --> $DIR/feature-gate.rs:34:68 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -145,7 +185,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:39:15 + --> $DIR/feature-gate.rs:42:15 | LL | () if let Range { start: _, end: _ } = (true..true) && false => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -154,7 +194,7 @@ LL | () if let Range { start: _, end: _ } = (true..true) && false => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:54:16 + --> $DIR/feature-gate.rs:59:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^^^^^^^ @@ -163,7 +203,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:56:16 + --> $DIR/feature-gate.rs:61:16 | LL | use_expr!((let 0 = 1)); | ^^^^^^^^^ @@ -171,6 +211,6 @@ LL | use_expr!((let 0 = 1)); = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable -error: aborting due to 19 previous errors +error: aborting due to 23 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-93150.rs b/src/test/ui/rfc-2497-if-let-chains/issue-93150.rs new file mode 100644 index 00000000000..f90b9ab0d40 --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/issue-93150.rs @@ -0,0 +1,8 @@ +fn main() { + match true { + _ if let true = true && true => {} + //~^ ERROR `if let` guards are + //~| ERROR `let` expressions in this + _ => {} + } +} diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-93150.stderr b/src/test/ui/rfc-2497-if-let-chains/issue-93150.stderr new file mode 100644 index 00000000000..b25f299a219 --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/issue-93150.stderr @@ -0,0 +1,22 @@ +error[E0658]: `if let` guards are experimental + --> $DIR/issue-93150.rs:3:11 + | +LL | _ if let true = true && true => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/issue-93150.rs:3:14 + | +LL | _ if let true = true && true => {} + | ^^^^^^^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs b/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs index 8800d3e66f9..82c4120b4c7 100644 --- a/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs +++ b/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs @@ -37,7 +37,7 @@ checker!(rename_params, r#"impl Foo fn hello(#[angery(true)] a : i32, #[a2] b : i32, #[what = "how"] c : u32) {} fn hello2(#[a1] #[a2] a : i32, #[what = "how"] b : i32, #[angery(true)] c : - u32) {} fn + u32) {} fn hello_self(#[a1] #[a2] & self, #[a1] #[a2] a : i32, #[what = "how"] b : - i32, #[angery(true)] c : u32) {} + i32, #[angery(true)] c : u32) {} }"#); diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs index 7b012083c5a..99eacaa837f 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs @@ -1,5 +1,5 @@ -// FIXME(fee1-dead): this should have a better error message #![feature(const_trait_impl)] + struct NonConstAdd(i32); impl std::ops::Add for NonConstAdd { @@ -16,7 +16,7 @@ trait Foo { impl const Foo for NonConstAdd { type Bar = NonConstAdd; - //~^ ERROR + //~^ ERROR: cannot add `NonConstAdd` to `NonConstAdd` in const contexts } trait Baz { diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr index 4a4b4de4758..0788b17a1c0 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr @@ -1,10 +1,15 @@ -error[E0277]: cannot add `NonConstAdd` to `NonConstAdd` +error[E0277]: cannot add `NonConstAdd` to `NonConstAdd` in const contexts --> $DIR/assoc-type.rs:18:16 | LL | type Bar = NonConstAdd; | ^^^^^^^^^^^ no implementation for `NonConstAdd + NonConstAdd` | - = help: the trait `Add` is not implemented for `NonConstAdd` + = help: the trait `~const Add` is not implemented for `NonConstAdd` +note: the trait `Add` is implemented for `NonConstAdd`, but that implementation is not `const` + --> $DIR/assoc-type.rs:18:16 + | +LL | type Bar = NonConstAdd; + | ^^^^^^^^^^^ note: required by a bound in `Foo::Bar` --> $DIR/assoc-type.rs:14:15 | @@ -12,8 +17,8 @@ LL | type Bar: ~const std::ops::Add; | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::Bar` help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement | -LL | impl const Foo for NonConstAdd where NonConstAdd: Add { - | ++++++++++++++++++++++ +LL | impl const Foo for NonConstAdd where NonConstAdd: ~const Add { + | +++++++++++++++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr index 0440f17a704..35b7fe8e401 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr @@ -1,4 +1,4 @@ -error[E0277]: can't compare `S` with `S` +error[E0277]: can't compare `S` with `S` in const contexts --> $DIR/call-generic-method-nonconst.rs:19:34 | LL | pub const EQ: bool = equals_self(&S); @@ -6,7 +6,12 @@ LL | pub const EQ: bool = equals_self(&S); | | | required by a bound introduced by this call | - = help: the trait `PartialEq` is not implemented for `S` + = help: the trait `~const PartialEq` is not implemented for `S` +note: the trait `PartialEq` is implemented for `S`, but that implementation is not `const` + --> $DIR/call-generic-method-nonconst.rs:19:34 + | +LL | pub const EQ: bool = equals_self(&S); + | ^^ note: required by a bound in `equals_self` --> $DIR/call-generic-method-nonconst.rs:12:25 | diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr index 04c21101e75..d280cd2556f 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr @@ -1,65 +1,75 @@ -error: `~const` is not allowed here - --> $DIR/const-drop-fail.rs:27:35 - | -LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>); - | ^^^^^^^^ - | - = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions - -error[E0277]: the trait bound `NonTrivialDrop: Drop` is not satisfied - --> $DIR/const-drop-fail.rs:45:5 +error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied + --> $DIR/const-drop-fail.rs:44:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call ... LL | NonTrivialDrop, - | ^^^^^^^^^^^^^^ the trait `Drop` is not implemented for `NonTrivialDrop` + | ^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop` | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:36:19 + --> $DIR/const-drop-fail.rs:35:19 | LL | const fn check<T: ~const Drop>(_: T) {} | ^^^^^^^^^^^ required by this bound in `check` +help: consider borrowing here + | +LL | &NonTrivialDrop, + | + +LL | &mut NonTrivialDrop, + | ++++ -error[E0277]: the trait bound `ConstImplWithDropGlue: Drop` is not satisfied - --> $DIR/const-drop-fail.rs:47:5 +error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied in `ConstImplWithDropGlue` + --> $DIR/const-drop-fail.rs:46:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call ... LL | ConstImplWithDropGlue(NonTrivialDrop), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Drop` is not implemented for `ConstImplWithDropGlue` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `ConstImplWithDropGlue`, the trait `~const Drop` is not implemented for `NonTrivialDrop` | +note: the trait `Drop` is implemented for `NonTrivialDrop`, but that implementation is not `const` + --> $DIR/const-drop-fail.rs:46:5 + | +LL | ConstImplWithDropGlue(NonTrivialDrop), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required because it appears within the type `ConstImplWithDropGlue` + --> $DIR/const-drop-fail.rs:17:8 + | +LL | struct ConstImplWithDropGlue(NonTrivialDrop); + | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:36:19 + --> $DIR/const-drop-fail.rs:35:19 | LL | const fn check<T: ~const Drop>(_: T) {} | ^^^^^^^^^^^ required by this bound in `check` -error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied - --> $DIR/const-drop-fail.rs:49:5 +error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: ~const Drop` is not satisfied + --> $DIR/const-drop-fail.rs:48:5 | +LL | const _: () = check($exp); + | ----- required by a bound introduced by this call +... LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop` | -note: required by a bound in `ConstDropImplWithBounds` - --> $DIR/const-drop-fail.rs:27:35 - | -LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>); - | ^^^^^^^^ required by this bound in `ConstDropImplWithBounds` - -error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied - --> $DIR/const-drop-fail.rs:49:5 +note: required because of the requirements on the impl of `~const Drop` for `ConstDropImplWithBounds<NonTrivialDrop>` + --> $DIR/const-drop-fail.rs:29:25 | -LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop` +LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> { + | ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `check` + --> $DIR/const-drop-fail.rs:35:19 | -note: required by a bound in `ConstDropImplWithBounds` - --> $DIR/const-drop-fail.rs:27:35 +LL | const fn check<T: ~const Drop>(_: T) {} + | ^^^^^^^^^^^ required by this bound in `check` +help: consider borrowing here | -LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>); - | ^^^^^^^^ required by this bound in `ConstDropImplWithBounds` +LL | &ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData), + | + +LL | &mut ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData), + | ++++ -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs index 3d4de088f55..4622723c189 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs @@ -24,8 +24,7 @@ trait A { fn a() { println!("A"); } } impl A for NonTrivialDrop {} -struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>); -//~^ ERROR `~const` is not allowed +struct ConstDropImplWithBounds<T: A>(PhantomData<T>); impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> { fn drop(&mut self) { @@ -48,7 +47,6 @@ check_all! { //~^ ERROR the trait bound ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData), //~^ ERROR the trait bound - //~| ERROR the trait bound } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr index 04c21101e75..d280cd2556f 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr @@ -1,65 +1,75 @@ -error: `~const` is not allowed here - --> $DIR/const-drop-fail.rs:27:35 - | -LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>); - | ^^^^^^^^ - | - = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions - -error[E0277]: the trait bound `NonTrivialDrop: Drop` is not satisfied - --> $DIR/const-drop-fail.rs:45:5 +error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied + --> $DIR/const-drop-fail.rs:44:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call ... LL | NonTrivialDrop, - | ^^^^^^^^^^^^^^ the trait `Drop` is not implemented for `NonTrivialDrop` + | ^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop` | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:36:19 + --> $DIR/const-drop-fail.rs:35:19 | LL | const fn check<T: ~const Drop>(_: T) {} | ^^^^^^^^^^^ required by this bound in `check` +help: consider borrowing here + | +LL | &NonTrivialDrop, + | + +LL | &mut NonTrivialDrop, + | ++++ -error[E0277]: the trait bound `ConstImplWithDropGlue: Drop` is not satisfied - --> $DIR/const-drop-fail.rs:47:5 +error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied in `ConstImplWithDropGlue` + --> $DIR/const-drop-fail.rs:46:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call ... LL | ConstImplWithDropGlue(NonTrivialDrop), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Drop` is not implemented for `ConstImplWithDropGlue` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `ConstImplWithDropGlue`, the trait `~const Drop` is not implemented for `NonTrivialDrop` | +note: the trait `Drop` is implemented for `NonTrivialDrop`, but that implementation is not `const` + --> $DIR/const-drop-fail.rs:46:5 + | +LL | ConstImplWithDropGlue(NonTrivialDrop), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required because it appears within the type `ConstImplWithDropGlue` + --> $DIR/const-drop-fail.rs:17:8 + | +LL | struct ConstImplWithDropGlue(NonTrivialDrop); + | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:36:19 + --> $DIR/const-drop-fail.rs:35:19 | LL | const fn check<T: ~const Drop>(_: T) {} | ^^^^^^^^^^^ required by this bound in `check` -error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied - --> $DIR/const-drop-fail.rs:49:5 +error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: ~const Drop` is not satisfied + --> $DIR/const-drop-fail.rs:48:5 | +LL | const _: () = check($exp); + | ----- required by a bound introduced by this call +... LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop` | -note: required by a bound in `ConstDropImplWithBounds` - --> $DIR/const-drop-fail.rs:27:35 - | -LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>); - | ^^^^^^^^ required by this bound in `ConstDropImplWithBounds` - -error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied - --> $DIR/const-drop-fail.rs:49:5 +note: required because of the requirements on the impl of `~const Drop` for `ConstDropImplWithBounds<NonTrivialDrop>` + --> $DIR/const-drop-fail.rs:29:25 | -LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop` +LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> { + | ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `check` + --> $DIR/const-drop-fail.rs:35:19 | -note: required by a bound in `ConstDropImplWithBounds` - --> $DIR/const-drop-fail.rs:27:35 +LL | const fn check<T: ~const Drop>(_: T) {} + | ^^^^^^^^^^^ required by this bound in `check` +help: consider borrowing here | -LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>); - | ^^^^^^^^ required by this bound in `ConstDropImplWithBounds` +LL | &ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData), + | + +LL | &mut ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData), + | ++++ -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs b/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs index 292017a1de2..13363c506d5 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs @@ -3,6 +3,7 @@ #![feature(const_trait_impl)] #![feature(const_fn_trait_bound)] #![feature(const_mut_refs)] +#![feature(never_type)] #![cfg_attr(precise, feature(const_precise_live_drops))] struct S<'a>(&'a mut u8); @@ -45,6 +46,33 @@ mod t { pub struct HasConstDrop(pub ConstDrop); pub struct TrivialFields(pub u8, pub i8, pub usize, pub isize); + + pub trait SomeTrait { + fn foo(); + } + impl const SomeTrait for () { + fn foo() {} + } + // non-const impl + impl SomeTrait for i32 { + fn foo() {} + } + + pub struct ConstDropWithBound<T: SomeTrait>(pub core::marker::PhantomData<T>); + + impl<T: ~const SomeTrait> const Drop for ConstDropWithBound<T> { + fn drop(&mut self) { + T::foo(); + } + } + + pub struct ConstDropWithNonconstBound<T: SomeTrait>(pub core::marker::PhantomData<T>); + + impl<T: SomeTrait> const Drop for ConstDropWithNonconstBound<T> { + fn drop(&mut self) { + // Note: we DON'T use the `T: SomeTrait` bound + } + } } use t::*; @@ -61,6 +89,9 @@ implements_const_drop! { TrivialFields(1, 2, 3, 4), &1, &1 as *const i32, + ConstDropWithBound::<()>, + ConstDropWithNonconstBound::<i32>, + Result::<i32, !>::Ok(1), } fn main() { diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs index 7db04fe1ac3..76ea17159ac 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs @@ -10,7 +10,7 @@ pub trait Foo { #[default_method_body_is_const] fn foo() { foo::<()>(); - //~^ ERROR the trait bound `(): Tr` is not satisfied + //~^ ERROR the trait bound `(): ~const Tr` is not satisfied } } diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr index 6e7e4b3a472..bc807507fd6 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr @@ -1,9 +1,14 @@ -error[E0277]: the trait bound `(): Tr` is not satisfied +error[E0277]: the trait bound `(): ~const Tr` is not satisfied --> $DIR/default-method-body-is-const-body-checking.rs:12:15 | LL | foo::<()>(); - | ^^ the trait `Tr` is not implemented for `()` + | ^^ the trait `~const Tr` is not implemented for `()` | +note: the trait `Tr` is implemented for `()`, but that implementation is not `const` + --> $DIR/default-method-body-is-const-body-checking.rs:12:15 + | +LL | foo::<()>(); + | ^^ note: required by a bound in `foo` --> $DIR/default-method-body-is-const-body-checking.rs:7:28 | @@ -11,8 +16,8 @@ LL | const fn foo<T>() where T: ~const Tr {} | ^^^^^^^^^ required by this bound in `foo` help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement | -LL | pub trait Foo where (): Tr { - | ++++++++++++ +LL | pub trait Foo where (): ~const Tr { + | +++++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr index 08d91d7daf8..f9b5d81c63b 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr @@ -1,9 +1,14 @@ -error[E0277]: the trait bound `T: Bar` is not satisfied +error[E0277]: the trait bound `T: ~const Bar` is not satisfied --> $DIR/trait-where-clause.rs:14:5 | LL | T::b(); - | ^^^^ the trait `Bar` is not implemented for `T` + | ^^^^ the trait `~const Bar` is not implemented for `T` | +note: the trait `Bar` is implemented for `T`, but that implementation is not `const` + --> $DIR/trait-where-clause.rs:14:5 + | +LL | T::b(); + | ^^^^ note: required by a bound in `Foo::b` --> $DIR/trait-where-clause.rs:8:24 | @@ -11,15 +16,20 @@ LL | fn b() where Self: ~const Bar; | ^^^^^^^^^^ required by this bound in `Foo::b` help: consider further restricting this bound | -LL | const fn test1<T: ~const Foo + Bar + Bar>() { - | +++++ +LL | const fn test1<T: ~const Foo + Bar + ~const Bar>() { + | ++++++++++++ -error[E0277]: the trait bound `T: Bar` is not satisfied +error[E0277]: the trait bound `T: ~const Bar` is not satisfied --> $DIR/trait-where-clause.rs:16:5 | LL | T::c::<T>(); - | ^^^^^^^^^ the trait `Bar` is not implemented for `T` + | ^^^^^^^^^ the trait `~const Bar` is not implemented for `T` | +note: the trait `Bar` is implemented for `T`, but that implementation is not `const` + --> $DIR/trait-where-clause.rs:16:5 + | +LL | T::c::<T>(); + | ^^^^^^^^^ note: required by a bound in `Foo::c` --> $DIR/trait-where-clause.rs:9:13 | @@ -27,8 +37,8 @@ LL | fn c<T: ~const Bar>(); | ^^^^^^^^^^ required by this bound in `Foo::c` help: consider further restricting this bound | -LL | const fn test1<T: ~const Foo + Bar + Bar>() { - | +++++ +LL | const fn test1<T: ~const Foo + Bar + ~const Bar>() { + | ++++++++++++ error[E0277]: the trait bound `T: Bar` is not satisfied --> $DIR/trait-where-clause.rs:28:5 diff --git a/src/test/ui/rust-2018/edition-lint-nested-empty-paths.fixed b/src/test/ui/rust-2018/edition-lint-nested-empty-paths.fixed index 03d15cea280..acb0aa420ab 100644 --- a/src/test/ui/rust-2018/edition-lint-nested-empty-paths.fixed +++ b/src/test/ui/rust-2018/edition-lint-nested-empty-paths.fixed @@ -17,14 +17,28 @@ crate mod foo { use crate::foo::{bar::{baz::{}}}; //~^ ERROR absolute paths must start with //~| WARN this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| WARN this is accepted in the current edition use crate::foo::{bar::{XX, baz::{}}}; //~^ ERROR absolute paths must start with //~| WARN this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| WARN this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| WARN this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| WARN this is accepted in the current edition use crate::foo::{bar::{baz::{}, baz1::{}}}; //~^ ERROR absolute paths must start with //~| WARN this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| WARN this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| WARN this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| WARN this is accepted in the current edition fn main() { } diff --git a/src/test/ui/rust-2018/edition-lint-nested-empty-paths.rs b/src/test/ui/rust-2018/edition-lint-nested-empty-paths.rs index d898daaba59..4825528e97f 100644 --- a/src/test/ui/rust-2018/edition-lint-nested-empty-paths.rs +++ b/src/test/ui/rust-2018/edition-lint-nested-empty-paths.rs @@ -17,14 +17,28 @@ crate mod foo { use foo::{bar::{baz::{}}}; //~^ ERROR absolute paths must start with //~| WARN this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| WARN this is accepted in the current edition use foo::{bar::{XX, baz::{}}}; //~^ ERROR absolute paths must start with //~| WARN this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| WARN this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| WARN this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| WARN this is accepted in the current edition use foo::{bar::{baz::{}, baz1::{}}}; //~^ ERROR absolute paths must start with //~| WARN this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| WARN this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| WARN this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| WARN this is accepted in the current edition fn main() { } diff --git a/src/test/ui/rust-2018/edition-lint-nested-empty-paths.stderr b/src/test/ui/rust-2018/edition-lint-nested-empty-paths.stderr index 54a4fed5cf9..8a3113729b4 100644 --- a/src/test/ui/rust-2018/edition-lint-nested-empty-paths.stderr +++ b/src/test/ui/rust-2018/edition-lint-nested-empty-paths.stderr @@ -13,7 +13,16 @@ LL | #![deny(absolute_paths_not_starting_with_crate)] = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-nested-empty-paths.rs:21:5 + --> $DIR/edition-lint-nested-empty-paths.rs:17:5 + | +LL | use foo::{bar::{baz::{}}}; + | ^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}}}` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-nested-empty-paths.rs:23:5 | LL | use foo::{bar::{XX, baz::{}}}; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{XX, baz::{}}}` @@ -22,7 +31,61 @@ LL | use foo::{bar::{XX, baz::{}}}; = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-nested-empty-paths.rs:25:5 + --> $DIR/edition-lint-nested-empty-paths.rs:23:5 + | +LL | use foo::{bar::{XX, baz::{}}}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{XX, baz::{}}}` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-nested-empty-paths.rs:23:5 + | +LL | use foo::{bar::{XX, baz::{}}}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{XX, baz::{}}}` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-nested-empty-paths.rs:23:5 + | +LL | use foo::{bar::{XX, baz::{}}}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{XX, baz::{}}}` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-nested-empty-paths.rs:33:5 + | +LL | use foo::{bar::{baz::{}, baz1::{}}}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}, baz1::{}}}` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-nested-empty-paths.rs:33:5 + | +LL | use foo::{bar::{baz::{}, baz1::{}}}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}, baz1::{}}}` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-nested-empty-paths.rs:33:5 + | +LL | use foo::{bar::{baz::{}, baz1::{}}}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}, baz1::{}}}` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-nested-empty-paths.rs:33:5 | LL | use foo::{bar::{baz::{}, baz1::{}}}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}, baz1::{}}}` @@ -30,5 +93,5 @@ LL | use foo::{bar::{baz::{}, baz1::{}}}; = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> -error: aborting due to 3 previous errors +error: aborting due to 10 previous errors diff --git a/src/test/ui/rust-2018/edition-lint-nested-paths.fixed b/src/test/ui/rust-2018/edition-lint-nested-paths.fixed index 7c6e4a71a37..4eb1184cb6d 100644 --- a/src/test/ui/rust-2018/edition-lint-nested-paths.fixed +++ b/src/test/ui/rust-2018/edition-lint-nested-paths.fixed @@ -6,6 +6,12 @@ use crate::foo::{a, b}; //~^ ERROR absolute paths must start with //~| this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| this is accepted in the current edition mod foo { crate fn a() {} @@ -21,6 +27,10 @@ fn main() { use crate::foo::{self as x, c}; //~^ ERROR absolute paths must start with //~| this is accepted in the current edition + //~| ERROR absolute paths must start with + //~| this is accepted in the current edition + //~| ERROR absolute paths must start with + //~| this is accepted in the current edition x::a(); c(); } diff --git a/src/test/ui/rust-2018/edition-lint-nested-paths.rs b/src/test/ui/rust-2018/edition-lint-nested-paths.rs index 3925f76391a..2a358224d9b 100644 --- a/src/test/ui/rust-2018/edition-lint-nested-paths.rs +++ b/src/test/ui/rust-2018/edition-lint-nested-paths.rs @@ -6,6 +6,12 @@ use foo::{a, b}; //~^ ERROR absolute paths must start with //~| this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| this is accepted in the current edition +//~| ERROR absolute paths must start with +//~| this is accepted in the current edition mod foo { crate fn a() {} @@ -21,6 +27,10 @@ fn main() { use foo::{self as x, c}; //~^ ERROR absolute paths must start with //~| this is accepted in the current edition + //~| ERROR absolute paths must start with + //~| this is accepted in the current edition + //~| ERROR absolute paths must start with + //~| this is accepted in the current edition x::a(); c(); } diff --git a/src/test/ui/rust-2018/edition-lint-nested-paths.stderr b/src/test/ui/rust-2018/edition-lint-nested-paths.stderr index c2f91e342f5..3d596022b0a 100644 --- a/src/test/ui/rust-2018/edition-lint-nested-paths.stderr +++ b/src/test/ui/rust-2018/edition-lint-nested-paths.stderr @@ -13,7 +13,52 @@ LL | #![deny(absolute_paths_not_starting_with_crate)] = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-nested-paths.rs:21:13 + --> $DIR/edition-lint-nested-paths.rs:6:5 + | +LL | use foo::{a, b}; + | ^^^^^^^^^^^ help: use `crate`: `crate::foo::{a, b}` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-nested-paths.rs:6:5 + | +LL | use foo::{a, b}; + | ^^^^^^^^^^^ help: use `crate`: `crate::foo::{a, b}` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-nested-paths.rs:6:5 + | +LL | use foo::{a, b}; + | ^^^^^^^^^^^ help: use `crate`: `crate::foo::{a, b}` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-nested-paths.rs:27:13 + | +LL | use foo::{self as x, c}; + | ^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{self as x, c}` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-nested-paths.rs:27:13 + | +LL | use foo::{self as x, c}; + | ^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{self as x, c}` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-nested-paths.rs:27:13 | LL | use foo::{self as x, c}; | ^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{self as x, c}` @@ -21,5 +66,5 @@ LL | use foo::{self as x, c}; = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> -error: aborting due to 2 previous errors +error: aborting due to 7 previous errors diff --git a/src/test/ui/rust-2018/edition-lint-paths.fixed b/src/test/ui/rust-2018/edition-lint-paths.fixed index f91405929ee..46adf02a391 100644 --- a/src/test/ui/rust-2018/edition-lint-paths.fixed +++ b/src/test/ui/rust-2018/edition-lint-paths.fixed @@ -12,17 +12,25 @@ pub mod foo { use crate::bar::Bar; //~^ ERROR absolute //~| WARN this is accepted in the current edition + //~| ERROR absolute + //~| WARN this is accepted in the current edition + use super::bar::Bar2; use crate::bar::Bar3; use crate::bar; //~^ ERROR absolute //~| WARN this is accepted in the current edition + use crate::bar as something_else; use crate::{main, Bar as SomethingElse}; //~^ ERROR absolute //~| WARN this is accepted in the current edition + //~| ERROR absolute + //~| WARN this is accepted in the current edition + //~| ERROR absolute + //~| WARN this is accepted in the current edition use crate::{main as another_main, Bar as SomethingElse2}; @@ -34,6 +42,8 @@ pub mod foo { use crate::bar::Bar; //~^ ERROR absolute //~| WARN this is accepted in the current edition +//~| ERROR absolute +//~| WARN this is accepted in the current edition pub mod bar { use edition_lint_paths as foo; @@ -51,11 +61,14 @@ mod baz { impl crate::foo::SomeTrait for u32 {} //~^ ERROR absolute //~| WARN this is accepted in the current edition +//~| ERROR absolute +//~| WARN this is accepted in the current edition fn main() { let x = crate::bar::Bar; //~^ ERROR absolute //~| WARN this is accepted in the current edition + let x = bar::Bar; let x = crate::bar::Bar; let x = self::bar::Bar; diff --git a/src/test/ui/rust-2018/edition-lint-paths.rs b/src/test/ui/rust-2018/edition-lint-paths.rs index 52c97c7a253..f70bf90d681 100644 --- a/src/test/ui/rust-2018/edition-lint-paths.rs +++ b/src/test/ui/rust-2018/edition-lint-paths.rs @@ -12,17 +12,25 @@ pub mod foo { use bar::Bar; //~^ ERROR absolute //~| WARN this is accepted in the current edition + //~| ERROR absolute + //~| WARN this is accepted in the current edition + use super::bar::Bar2; use crate::bar::Bar3; use bar; //~^ ERROR absolute //~| WARN this is accepted in the current edition + use crate::bar as something_else; use {main, Bar as SomethingElse}; //~^ ERROR absolute //~| WARN this is accepted in the current edition + //~| ERROR absolute + //~| WARN this is accepted in the current edition + //~| ERROR absolute + //~| WARN this is accepted in the current edition use crate::{main as another_main, Bar as SomethingElse2}; @@ -34,6 +42,8 @@ pub mod foo { use bar::Bar; //~^ ERROR absolute //~| WARN this is accepted in the current edition +//~| ERROR absolute +//~| WARN this is accepted in the current edition pub mod bar { use edition_lint_paths as foo; @@ -51,11 +61,14 @@ mod baz { impl ::foo::SomeTrait for u32 {} //~^ ERROR absolute //~| WARN this is accepted in the current edition +//~| ERROR absolute +//~| WARN this is accepted in the current edition fn main() { let x = ::bar::Bar; //~^ ERROR absolute //~| WARN this is accepted in the current edition + let x = bar::Bar; let x = crate::bar::Bar; let x = self::bar::Bar; diff --git a/src/test/ui/rust-2018/edition-lint-paths.stderr b/src/test/ui/rust-2018/edition-lint-paths.stderr index 23deeda14a4..481c68e1033 100644 --- a/src/test/ui/rust-2018/edition-lint-paths.stderr +++ b/src/test/ui/rust-2018/edition-lint-paths.stderr @@ -13,7 +13,16 @@ LL | #![deny(absolute_paths_not_starting_with_crate)] = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-paths.rs:18:9 + --> $DIR/edition-lint-paths.rs:12:9 + | +LL | use bar::Bar; + | ^^^^^^^^ help: use `crate`: `crate::bar::Bar` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-paths.rs:21:9 | LL | use bar; | ^^^ help: use `crate`: `crate::bar` @@ -22,7 +31,7 @@ LL | use bar; = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-paths.rs:23:9 + --> $DIR/edition-lint-paths.rs:27:9 | LL | use {main, Bar as SomethingElse}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::{main, Bar as SomethingElse}` @@ -31,7 +40,34 @@ LL | use {main, Bar as SomethingElse}; = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-paths.rs:34:5 + --> $DIR/edition-lint-paths.rs:27:9 + | +LL | use {main, Bar as SomethingElse}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::{main, Bar as SomethingElse}` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-paths.rs:27:9 + | +LL | use {main, Bar as SomethingElse}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::{main, Bar as SomethingElse}` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-paths.rs:42:5 + | +LL | use bar::Bar; + | ^^^^^^^^ help: use `crate`: `crate::bar::Bar` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-paths.rs:42:5 | LL | use bar::Bar; | ^^^^^^^^ help: use `crate`: `crate::bar::Bar` @@ -40,7 +76,7 @@ LL | use bar::Bar; = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-paths.rs:46:9 + --> $DIR/edition-lint-paths.rs:56:9 | LL | use *; | ^ help: use `crate`: `crate::*` @@ -49,7 +85,16 @@ LL | use *; = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-paths.rs:51:6 + --> $DIR/edition-lint-paths.rs:61:6 + | +LL | impl ::foo::SomeTrait for u32 {} + | ^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::SomeTrait` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-paths.rs:61:6 | LL | impl ::foo::SomeTrait for u32 {} | ^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::SomeTrait` @@ -58,7 +103,7 @@ LL | impl ::foo::SomeTrait for u32 {} = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-paths.rs:56:13 + --> $DIR/edition-lint-paths.rs:68:13 | LL | let x = ::bar::Bar; | ^^^^^^^^^^ help: use `crate`: `crate::bar::Bar` @@ -66,5 +111,5 @@ LL | let x = ::bar::Bar; = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> -error: aborting due to 7 previous errors +error: aborting due to 12 previous errors diff --git a/src/test/ui/rust-2018/extern-crate-rename.fixed b/src/test/ui/rust-2018/extern-crate-rename.fixed index ea832ef3e7d..05b881a9b08 100644 --- a/src/test/ui/rust-2018/extern-crate-rename.fixed +++ b/src/test/ui/rust-2018/extern-crate-rename.fixed @@ -12,6 +12,8 @@ extern crate edition_lint_paths as my_crate; use crate::my_crate::foo; //~^ ERROR absolute paths must start //~| WARNING this is accepted in the current edition +//~| ERROR absolute paths must start +//~| WARNING this is accepted in the current edition fn main() { foo(); diff --git a/src/test/ui/rust-2018/extern-crate-rename.rs b/src/test/ui/rust-2018/extern-crate-rename.rs index b1f617dd884..6e327be193b 100644 --- a/src/test/ui/rust-2018/extern-crate-rename.rs +++ b/src/test/ui/rust-2018/extern-crate-rename.rs @@ -12,6 +12,8 @@ extern crate edition_lint_paths as my_crate; use my_crate::foo; //~^ ERROR absolute paths must start //~| WARNING this is accepted in the current edition +//~| ERROR absolute paths must start +//~| WARNING this is accepted in the current edition fn main() { foo(); diff --git a/src/test/ui/rust-2018/extern-crate-rename.stderr b/src/test/ui/rust-2018/extern-crate-rename.stderr index 4bccbc51223..f2f379ca396 100644 --- a/src/test/ui/rust-2018/extern-crate-rename.stderr +++ b/src/test/ui/rust-2018/extern-crate-rename.stderr @@ -12,5 +12,14 @@ LL | #![deny(absolute_paths_not_starting_with_crate)] = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> -error: aborting due to previous error +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/extern-crate-rename.rs:12:5 + | +LL | use my_crate::foo; + | ^^^^^^^^^^^^^ help: use `crate`: `crate::my_crate::foo` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: aborting due to 2 previous errors diff --git a/src/test/ui/rust-2018/extern-crate-submod.fixed b/src/test/ui/rust-2018/extern-crate-submod.fixed index 9b0b0dd8ee1..fdbd893abed 100644 --- a/src/test/ui/rust-2018/extern-crate-submod.fixed +++ b/src/test/ui/rust-2018/extern-crate-submod.fixed @@ -19,6 +19,9 @@ mod m { use crate::m::edition_lint_paths::foo; //~^ ERROR absolute paths must start //~| WARNING this is accepted in the current edition +//~| ERROR absolute paths must start +//~| WARNING this is accepted in the current edition + fn main() { foo(); diff --git a/src/test/ui/rust-2018/extern-crate-submod.rs b/src/test/ui/rust-2018/extern-crate-submod.rs index dfce9128c51..c2b915849f0 100644 --- a/src/test/ui/rust-2018/extern-crate-submod.rs +++ b/src/test/ui/rust-2018/extern-crate-submod.rs @@ -19,6 +19,9 @@ mod m { use m::edition_lint_paths::foo; //~^ ERROR absolute paths must start //~| WARNING this is accepted in the current edition +//~| ERROR absolute paths must start +//~| WARNING this is accepted in the current edition + fn main() { foo(); diff --git a/src/test/ui/rust-2018/extern-crate-submod.stderr b/src/test/ui/rust-2018/extern-crate-submod.stderr index 3c75319aeda..c4c3168bc97 100644 --- a/src/test/ui/rust-2018/extern-crate-submod.stderr +++ b/src/test/ui/rust-2018/extern-crate-submod.stderr @@ -12,5 +12,14 @@ LL | #![deny(absolute_paths_not_starting_with_crate)] = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> -error: aborting due to previous error +error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/extern-crate-submod.rs:19:5 + | +LL | use m::edition_lint_paths::foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::m::edition_lint_paths::foo` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> + +error: aborting due to 2 previous errors diff --git a/src/test/ui/save-analysis/issue-89066.rs b/src/test/ui/save-analysis/issue-89066.rs new file mode 100644 index 00000000000..2873f5237d4 --- /dev/null +++ b/src/test/ui/save-analysis/issue-89066.rs @@ -0,0 +1,28 @@ +// compile-flags: -Zsave-analysis + +// Check that this does not ICE. +// Stolen from src/test/ui/const-generics/generic_arg_infer/infer-arg-test.rs + +#![feature(generic_arg_infer)] + +struct All<'a, T, const N: usize> { + v: &'a T, +} + +struct BadInfer<_>; +//~^ ERROR expected identifier +//~| ERROR parameter `_` is never used + +fn all_fn<'a, T, const N: usize>() {} + +fn bad_infer_fn<_>() {} +//~^ ERROR expected identifier + + +fn main() { + let a: All<_, _, _>; + //~^ ERROR this struct takes 2 generic arguments but 3 generic arguments were supplied + all_fn(); + let v: [u8; _]; + let v: [u8; 10] = [0; _]; +} diff --git a/src/test/ui/save-analysis/issue-89066.stderr b/src/test/ui/save-analysis/issue-89066.stderr new file mode 100644 index 00000000000..a3ff1c02b2a --- /dev/null +++ b/src/test/ui/save-analysis/issue-89066.stderr @@ -0,0 +1,39 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-89066.rs:12:17 + | +LL | struct BadInfer<_>; + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-89066.rs:18:17 + | +LL | fn bad_infer_fn<_>() {} + | ^ expected identifier, found reserved identifier + +error[E0392]: parameter `_` is never used + --> $DIR/issue-89066.rs:12:17 + | +LL | struct BadInfer<_>; + | ^ unused parameter + | + = help: consider removing `_`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `_` to be a const parameter, use `const _: usize` instead + +error[E0107]: this struct takes 2 generic arguments but 3 generic arguments were supplied + --> $DIR/issue-89066.rs:23:10 + | +LL | let a: All<_, _, _>; + | ^^^ - help: remove this generic argument + | | + | expected 2 generic arguments + | +note: struct defined here, with 2 generic parameters: `T`, `N` + --> $DIR/issue-89066.rs:8:8 + | +LL | struct All<'a, T, const N: usize> { + | ^^^ - - + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0107, E0392. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index 92e86bf5d6c..e2e7ce1ed18 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -7,10 +7,11 @@ LL | let x = "Hello " + "World!"; | | `+` cannot be used to concatenate two `&str` strings | &str | -help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + = note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference | LL | let x = "Hello ".to_owned() + "World!"; - | ~~~~~~~~~~~~~~~~~~~ + | +++++++++++ error[E0369]: cannot add `World` to `World` --> $DIR/issue-39018.rs:8:26 @@ -46,10 +47,10 @@ LL | let x = "Hello " + "World!".to_owned(); | | `+` cannot be used to concatenate a `&str` with a `String` | &str | -help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left +help: create an owned `String` on the left and add a borrow on the right | LL | let x = "Hello ".to_owned() + &"World!".to_owned(); - | ~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ + | +++++++++++ + error[E0369]: cannot add `&String` to `&String` --> $DIR/issue-39018.rs:26:16 @@ -60,10 +61,12 @@ LL | let _ = &a + &b; | | `+` cannot be used to concatenate two `&str` strings | &String | -help: String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + = note: string concatenation requires an owned `String` on the left +help: remove the borrow to obtain an owned `String` | -LL | let _ = a + &b; - | ~ +LL - let _ = &a + &b; +LL + let _ = a + &b; + | error[E0369]: cannot add `String` to `&String` --> $DIR/issue-39018.rs:27:16 @@ -74,10 +77,11 @@ LL | let _ = &a + b; | | `+` cannot be used to concatenate a `&str` with a `String` | &String | -help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left +help: remove the borrow on the left and add one on the right | -LL | let _ = a + &b; - | ~ ~~ +LL - let _ = &a + b; +LL + let _ = a + &b; + | error[E0308]: mismatched types --> $DIR/issue-39018.rs:29:17 @@ -97,10 +101,10 @@ LL | let _ = e + b; | | `+` cannot be used to concatenate a `&str` with a `String` | &String | -help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left +help: create an owned `String` on the left and add a borrow on the right | LL | let _ = e.to_owned() + &b; - | ~~~~~~~~~~~~ ~~ + | +++++++++++ + error[E0369]: cannot add `&String` to `&String` --> $DIR/issue-39018.rs:31:15 @@ -111,10 +115,11 @@ LL | let _ = e + &b; | | `+` cannot be used to concatenate two `&str` strings | &String | -help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + = note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference | LL | let _ = e.to_owned() + &b; - | ~~~~~~~~~~~~ + | +++++++++++ error[E0369]: cannot add `&str` to `&String` --> $DIR/issue-39018.rs:32:15 @@ -125,10 +130,11 @@ LL | let _ = e + d; | | `+` cannot be used to concatenate two `&str` strings | &String | -help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + = note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference | LL | let _ = e.to_owned() + d; - | ~~~~~~~~~~~~ + | +++++++++++ error[E0369]: cannot add `&&str` to `&String` --> $DIR/issue-39018.rs:33:15 @@ -139,10 +145,11 @@ LL | let _ = e + &d; | | `+` cannot be used to concatenate two `&str` strings | &String | -help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + = note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference | LL | let _ = e.to_owned() + &d; - | ~~~~~~~~~~~~ + | +++++++++++ error[E0369]: cannot add `&&str` to `&&str` --> $DIR/issue-39018.rs:34:16 @@ -169,10 +176,11 @@ LL | let _ = c + &d; | | `+` cannot be used to concatenate two `&str` strings | &str | -help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + = note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference | LL | let _ = c.to_owned() + &d; - | ~~~~~~~~~~~~ + | +++++++++++ error[E0369]: cannot add `&str` to `&str` --> $DIR/issue-39018.rs:37:15 @@ -183,10 +191,11 @@ LL | let _ = c + d; | | `+` cannot be used to concatenate two `&str` strings | &str | -help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + = note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference | LL | let _ = c.to_owned() + d; - | ~~~~~~~~~~~~ + | +++++++++++ error: aborting due to 14 previous errors diff --git a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr index ad51707070f..1a7eb82c95b 100644 --- a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr +++ b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr @@ -1,4 +1,4 @@ -error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[HASH]::Id::This) }, Ty((I,))), [])` +error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[54ea]::Id::This) }, Ty((I,))), [])` --> $DIR/repeated_projection_type.rs:19:1 | LL | / impl<I, V: Id<This = (I,)>> X for V { diff --git a/src/test/ui/str/str-concat-on-double-ref.stderr b/src/test/ui/str/str-concat-on-double-ref.stderr index dee28897f4d..bd354679f78 100644 --- a/src/test/ui/str/str-concat-on-double-ref.stderr +++ b/src/test/ui/str/str-concat-on-double-ref.stderr @@ -7,10 +7,11 @@ LL | let c = a + b; | | `+` cannot be used to concatenate two `&str` strings | &String | -help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + = note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference | LL | let c = a.to_owned() + b; - | ~~~~~~~~~~~~ + | +++++++++++ error: aborting due to previous error diff --git a/src/test/ui/suggestions/args-instead-of-tuple-errors.rs b/src/test/ui/suggestions/args-instead-of-tuple-errors.rs new file mode 100644 index 00000000000..2c3ee5fcb80 --- /dev/null +++ b/src/test/ui/suggestions/args-instead-of-tuple-errors.rs @@ -0,0 +1,16 @@ +// Ensure we don't suggest tuple-wrapping when we'd end up with a type error + +fn main() { + // we shouldn't suggest to fix these - `2` isn't a `bool` + + let _: Option<(i32, bool)> = Some(1, 2); + //~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied + int_bool(1, 2); + //~^ ERROR this function takes 1 argument but 2 arguments were supplied + + let _: Option<(i8,)> = Some(); + //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied +} + +fn int_bool(_: (i32, bool)) { +} diff --git a/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr new file mode 100644 index 00000000000..a2ad602dbd4 --- /dev/null +++ b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr @@ -0,0 +1,33 @@ +error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied + --> $DIR/args-instead-of-tuple-errors.rs:6:34 + | +LL | let _: Option<(i32, bool)> = Some(1, 2); + | ^^^^ - - supplied 2 arguments + | | + | expected 1 argument + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/args-instead-of-tuple-errors.rs:8:5 + | +LL | int_bool(1, 2); + | ^^^^^^^^ - - supplied 2 arguments + | | + | expected 1 argument + | +note: function defined here + --> $DIR/args-instead-of-tuple-errors.rs:15:4 + | +LL | fn int_bool(_: (i32, bool)) { + | ^^^^^^^^ -------------- + +error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied + --> $DIR/args-instead-of-tuple-errors.rs:11:28 + | +LL | let _: Option<(i8,)> = Some(); + | ^^^^-- supplied 0 arguments + | | + | expected 1 argument + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0061`. diff --git a/src/test/ui/suggestions/args-instead-of-tuple.fixed b/src/test/ui/suggestions/args-instead-of-tuple.fixed new file mode 100644 index 00000000000..c9b8a41d469 --- /dev/null +++ b/src/test/ui/suggestions/args-instead-of-tuple.fixed @@ -0,0 +1,27 @@ +// Test suggesting tuples where bare arguments may have been passed +// See issue #86481 for details. + +// run-rustfix + +fn main() { + let _: Result<(i32, i8), ()> = Ok((1, 2)); + //~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied + let _: Option<(i32, i8, &'static str)> = Some((1, 2, "hi")); + //~^ ERROR this enum variant takes 1 argument but 3 arguments were supplied + let _: Option<()> = Some(()); + //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied + + two_ints((1, 2)); //~ ERROR this function takes 1 argument + + with_generic((3, 4)); //~ ERROR this function takes 1 argument +} + +fn two_ints(_: (i32, i32)) { +} + +fn with_generic<T: Copy + Send>((a, b): (i32, T)) { + if false { + // test generics/bound handling + with_generic((a, b)); //~ ERROR this function takes 1 argument + } +} diff --git a/src/test/ui/suggestions/args-instead-of-tuple.rs b/src/test/ui/suggestions/args-instead-of-tuple.rs new file mode 100644 index 00000000000..d4cc3024dd0 --- /dev/null +++ b/src/test/ui/suggestions/args-instead-of-tuple.rs @@ -0,0 +1,27 @@ +// Test suggesting tuples where bare arguments may have been passed +// See issue #86481 for details. + +// run-rustfix + +fn main() { + let _: Result<(i32, i8), ()> = Ok(1, 2); + //~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied + let _: Option<(i32, i8, &'static str)> = Some(1, 2, "hi"); + //~^ ERROR this enum variant takes 1 argument but 3 arguments were supplied + let _: Option<()> = Some(); + //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied + + two_ints(1, 2); //~ ERROR this function takes 1 argument + + with_generic(3, 4); //~ ERROR this function takes 1 argument +} + +fn two_ints(_: (i32, i32)) { +} + +fn with_generic<T: Copy + Send>((a, b): (i32, T)) { + if false { + // test generics/bound handling + with_generic(a, b); //~ ERROR this function takes 1 argument + } +} diff --git a/src/test/ui/suggestions/args-instead-of-tuple.stderr b/src/test/ui/suggestions/args-instead-of-tuple.stderr new file mode 100644 index 00000000000..172db7ee3df --- /dev/null +++ b/src/test/ui/suggestions/args-instead-of-tuple.stderr @@ -0,0 +1,84 @@ +error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied + --> $DIR/args-instead-of-tuple.rs:7:36 + | +LL | let _: Result<(i32, i8), ()> = Ok(1, 2); + | ^^ - - supplied 2 arguments + | +help: use parentheses to construct a tuple + | +LL | let _: Result<(i32, i8), ()> = Ok((1, 2)); + | + + + +error[E0061]: this enum variant takes 1 argument but 3 arguments were supplied + --> $DIR/args-instead-of-tuple.rs:9:46 + | +LL | let _: Option<(i32, i8, &'static str)> = Some(1, 2, "hi"); + | ^^^^ - - ---- supplied 3 arguments + | +help: use parentheses to construct a tuple + | +LL | let _: Option<(i32, i8, &'static str)> = Some((1, 2, "hi")); + | + + + +error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied + --> $DIR/args-instead-of-tuple.rs:11:25 + | +LL | let _: Option<()> = Some(); + | ^^^^-- supplied 0 arguments + | +help: expected the unit value `()`; create it with empty parentheses + | +LL | let _: Option<()> = Some(()); + | ++ + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/args-instead-of-tuple.rs:14:5 + | +LL | two_ints(1, 2); + | ^^^^^^^^ - - supplied 2 arguments + | +note: function defined here + --> $DIR/args-instead-of-tuple.rs:19:4 + | +LL | fn two_ints(_: (i32, i32)) { + | ^^^^^^^^ ------------- +help: use parentheses to construct a tuple + | +LL | two_ints((1, 2)); + | + + + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/args-instead-of-tuple.rs:16:5 + | +LL | with_generic(3, 4); + | ^^^^^^^^^^^^ - - supplied 2 arguments + | +note: function defined here + --> $DIR/args-instead-of-tuple.rs:22:4 + | +LL | fn with_generic<T: Copy + Send>((a, b): (i32, T)) { + | ^^^^^^^^^^^^ ---------------- +help: use parentheses to construct a tuple + | +LL | with_generic((3, 4)); + | + + + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/args-instead-of-tuple.rs:25:9 + | +LL | with_generic(a, b); + | ^^^^^^^^^^^^ - - supplied 2 arguments + | +note: function defined here + --> $DIR/args-instead-of-tuple.rs:22:4 + | +LL | fn with_generic<T: Copy + Send>((a, b): (i32, T)) { + | ^^^^^^^^^^^^ ---------------- +help: use parentheses to construct a tuple + | +LL | with_generic((a, b)); + | + + + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0061`. diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr index 63d291ed7cd..b125eacfb6c 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr @@ -38,4 +38,5 @@ LL | impl MyTrait for Box<dyn ObjectTrait<Assoc = i32> + '_> { error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0515`. +Some errors have detailed explanations: E0515, E0772. +For more information about an error, try `rustc --explain E0515`. diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr index 55a1bbf18ab..ed094c1365c 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr @@ -131,4 +131,5 @@ LL | impl MyTrait for Box<dyn ObjectTrait + '_> { error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0759`. +Some errors have detailed explanations: E0759, E0772. +For more information about an error, try `rustc --explain E0759`. diff --git a/src/test/ui/suggestions/private-field.rs b/src/test/ui/suggestions/private-field.rs new file mode 100644 index 00000000000..1cc4d2a4d06 --- /dev/null +++ b/src/test/ui/suggestions/private-field.rs @@ -0,0 +1,19 @@ +// compile-flags: --crate-type lib +pub struct S { + pub val: string::MyString, +} + +pub fn test(s: S) { + dbg!(s.cap) //~ ERROR: no field `cap` on type `S` [E0609] +} + +pub(crate) mod string { + + pub struct MyString { + buf: MyVec, + } + + struct MyVec { + cap: usize, + } +} diff --git a/src/test/ui/suggestions/private-field.stderr b/src/test/ui/suggestions/private-field.stderr new file mode 100644 index 00000000000..c38c795e07a --- /dev/null +++ b/src/test/ui/suggestions/private-field.stderr @@ -0,0 +1,11 @@ +error[E0609]: no field `cap` on type `S` + --> $DIR/private-field.rs:7:12 + | +LL | dbg!(s.cap) + | ^^^ unknown field + | + = note: available fields are: `val` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0609`. diff --git a/src/test/ui/symbol-names/basic.legacy.stderr b/src/test/ui/symbol-names/basic.legacy.stderr index e0e798dac40..5b343b637c3 100644 --- a/src/test/ui/symbol-names/basic.legacy.stderr +++ b/src/test/ui/symbol-names/basic.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN5basic4main17h<SYMBOL_HASH>) +error: symbol-name(_ZN5basic4main17h7c2c715a9b77648bE) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(basic::main::h<SYMBOL_HASH>) +error: demangling(basic::main::h7c2c715a9b77648b) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/basic.v0.stderr b/src/test/ui/symbol-names/basic.v0.stderr index 27308fc5ec3..1f02781364e 100644 --- a/src/test/ui/symbol-names/basic.v0.stderr +++ b/src/test/ui/symbol-names/basic.v0.stderr @@ -4,7 +4,7 @@ error: symbol-name(_RNvCsCRATE_HASH_5basic4main) LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(basic[HASH]::main) +error: demangling(basic[b751b4a00e2291d9]::main) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/foreign-types.stderr b/src/test/ui/symbol-names/foreign-types.stderr index fcffdd2a8ec..d6ee388ddf8 100644 --- a/src/test/ui/symbol-names/foreign-types.stderr +++ b/src/test/ui/symbol-names/foreign-types.stderr @@ -4,7 +4,7 @@ error: symbol-name(_RMCsCRATE_HASH_13foreign_typesINtB<REF>_5CheckNvB<REF>_11For LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<foreign_types[HASH]::Check<foreign_types[HASH]::ForeignType>>) +error: demangling(<foreign_types[49eeeb51f120b431]::Check<foreign_types[49eeeb51f120b431]::ForeignType>>) --> $DIR/foreign-types.rs:13:1 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/impl1.legacy.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr index b17a073ee49..b6012e41594 100644 --- a/src/test/ui/symbol-names/impl1.legacy.stderr +++ b/src/test/ui/symbol-names/impl1.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN5impl13foo3Foo3bar17h<SYMBOL_HASH>) +error: symbol-name(_ZN5impl13foo3Foo3bar17<SYMBOL_HASH>) --> $DIR/impl1.rs:14:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(impl1::foo::Foo::bar::h<SYMBOL_HASH>) +error: demangling(impl1::foo::Foo::bar::<SYMBOL_HASH>) --> $DIR/impl1.rs:14:9 | LL | #[rustc_symbol_name] @@ -22,13 +22,13 @@ error: def-path(foo::Foo::bar) LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ -error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h<SYMBOL_HASH>) +error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17<SYMBOL_HASH>) --> $DIR/impl1.rs:32:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(impl1::bar::<impl impl1::foo::Foo>::baz::h<SYMBOL_HASH>) +error: demangling(impl1::bar::<impl impl1::foo::Foo>::baz::<SYMBOL_HASH>) --> $DIR/impl1.rs:32:9 | LL | #[rustc_symbol_name] @@ -46,13 +46,13 @@ error: def-path(bar::<impl foo::Foo>::baz) LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ -error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$3$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17h<SYMBOL_HASH>) +error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$3$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17<SYMBOL_HASH>) --> $DIR/impl1.rs:62:13 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method::h<SYMBOL_HASH>) +error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method::<SYMBOL_HASH>) --> $DIR/impl1.rs:62:13 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/impl1.v0.stderr b/src/test/ui/symbol-names/impl1.v0.stderr index 06778e57fb1..48f7473b6a0 100644 --- a/src/test/ui/symbol-names/impl1.v0.stderr +++ b/src/test/ui/symbol-names/impl1.v0.stderr @@ -4,7 +4,7 @@ error: symbol-name(_RNvMNtCsCRATE_HASH_5impl13fooNtB<REF>_3Foo3bar) LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<impl1[HASH]::foo::Foo>::bar) +error: demangling(<impl1[2c09c4f1c7c8e90c]::foo::Foo>::bar) --> $DIR/impl1.rs:14:9 | LL | #[rustc_symbol_name] @@ -28,7 +28,7 @@ error: symbol-name(_RNvMNtCsCRATE_HASH_5impl13barNtNtB<REF>_3foo3Foo3baz) LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<impl1[HASH]::foo::Foo>::baz) +error: demangling(<impl1[2c09c4f1c7c8e90c]::foo::Foo>::baz) --> $DIR/impl1.rs:32:9 | LL | #[rustc_symbol_name] @@ -52,7 +52,7 @@ error: symbol-name(_RNvXNCNvCsCRATE_HASH_5impl14mains_0ARDNtB<REF>_3Foop5AssocFG LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<[&dyn impl1[HASH]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[HASH]::AutoTrait; 3usize] as impl1[HASH]::main::{closure#1}::Bar>::method) +error: demangling(<[&dyn impl1[2c09c4f1c7c8e90c]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[2c09c4f1c7c8e90c]::AutoTrait; 3usize] as impl1[2c09c4f1c7c8e90c]::main::{closure#1}::Bar>::method) --> $DIR/impl1.rs:62:13 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/issue-60925.legacy.stderr b/src/test/ui/symbol-names/issue-60925.legacy.stderr index 46cb84e57bf..dbeab457194 100644 --- a/src/test/ui/symbol-names/issue-60925.legacy.stderr +++ b/src/test/ui/symbol-names/issue-60925.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h<SYMBOL_HASH>) +error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h419983d0842a72aeE) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h<SYMBOL_HASH>) +error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h419983d0842a72ae) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/issue-60925.v0.stderr b/src/test/ui/symbol-names/issue-60925.v0.stderr index 1cddba92085..408c957c6a1 100644 --- a/src/test/ui/symbol-names/issue-60925.v0.stderr +++ b/src/test/ui/symbol-names/issue-60925.v0.stderr @@ -4,7 +4,7 @@ error: symbol-name(_RNvMNtCsCRATE_HASH_11issue_609253fooINtB<REF>_3FooNtNtB<REF> LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<issue_60925[HASH]::foo::Foo<issue_60925[HASH]::llvm::Foo>>::foo) +error: demangling(<issue_60925[775bc577f14ef671]::foo::Foo<issue_60925[775bc577f14ef671]::llvm::Foo>>::foo) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/issue-75326.legacy.stderr b/src/test/ui/symbol-names/issue-75326.legacy.stderr index 74e481badb0..aadc0cf43a2 100644 --- a/src/test/ui/symbol-names/issue-75326.legacy.stderr +++ b/src/test/ui/symbol-names/issue-75326.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next17h<SYMBOL_HASH>) +error: symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next17SYMBOL_HASH) --> $DIR/issue-75326.rs:41:5 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next::h<SYMBOL_HASH>) +error: demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next::SYMBOL_HASH) --> $DIR/issue-75326.rs:41:5 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/issue-75326.v0.stderr b/src/test/ui/symbol-names/issue-75326.v0.stderr index 446fb8d6cf6..3d7803a0c3b 100644 --- a/src/test/ui/symbol-names/issue-75326.v0.stderr +++ b/src/test/ui/symbol-names/issue-75326.v0.stderr @@ -4,7 +4,7 @@ error: symbol-name(_RNvXINICsCRATE_HASH_11issue_75326s_0pppEINtB<REF>_3FooppENtB LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<issue_75326[HASH]::Foo<_, _> as issue_75326[HASH]::Iterator2>::next) +error: demangling(<issue_75326[e8e253d78520f2a2]::Foo<_, _> as issue_75326[e8e253d78520f2a2]::Iterator2>::next) --> $DIR/issue-75326.rs:41:5 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/trait-objects.v0.stderr b/src/test/ui/symbol-names/trait-objects.v0.stderr index 6c5e55ed2ae..47192ce5b83 100644 --- a/src/test/ui/symbol-names/trait-objects.v0.stderr +++ b/src/test/ui/symbol-names/trait-objects.v0.stderr @@ -4,7 +4,7 @@ error: symbol-name(_RNvXCsCRATE_HASH_13trait_objectsRDG_INtNtNtCsCRATE_HASH_4cor LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects[HASH]::Bar>::method) +error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects[7260a56bea9f357b]::Bar>::method) --> $DIR/trait-objects.rs:15:5 | LL | #[rustc_symbol_name] @@ -22,7 +22,7 @@ error: symbol-name(_RNvXs_CsCRATE_HASH_13trait_objectsRDG_INtNtNtCsCRATE_HASH_4c LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[HASH]::Foo>::method) +error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[7260a56bea9f357b]::Foo>::method) --> $DIR/trait-objects.rs:27:5 | LL | #[rustc_symbol_name] @@ -40,7 +40,7 @@ error: symbol-name(_RNvXs0_CsCRATE_HASH_13trait_objectsRDG_INtNtNtCsCRATE_HASH_4 LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[HASH]::Baz>::method) +error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[7260a56bea9f357b]::Baz>::method) --> $DIR/trait-objects.rs:39:5 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr b/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr index 480f442fedd..bf277362dba 100644 --- a/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr +++ b/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr @@ -7,10 +7,11 @@ LL | ...ཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔ | | `+` cannot be used to concatenate two `&str` strings | &str | -help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + = note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference | LL | let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun.to_owned() + " really fun!"; - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | +++++++++++ error: aborting due to previous error diff --git a/src/test/ui/thir-tree.stdout b/src/test/ui/thir-tree.stdout index a732eb68a2b..3c84be8e8f8 100644 --- a/src/test/ui/thir-tree.stdout +++ b/src/test/ui/thir-tree.stdout @@ -1,4 +1,4 @@ -DefId(0:3 ~ thir_tree[HASH]::main): +DefId(0:3 ~ thir_tree[8f1d]::main): Thir { arms: [], exprs: [ @@ -30,7 +30,7 @@ Thir { region_scope: Node(2), lint_level: Explicit( HirId { - owner: DefId(0:3 ~ thir_tree[HASH]::main), + owner: DefId(0:3 ~ thir_tree[8f1d]::main), local_id: 2, }, ), diff --git a/src/test/ui/traits/issue-91594.rs b/src/test/ui/traits/issue-91594.rs new file mode 100644 index 00000000000..930f7f0c6ad --- /dev/null +++ b/src/test/ui/traits/issue-91594.rs @@ -0,0 +1,17 @@ +// #91594: This used to ICE. + +trait Component<M> { + type Interface; +} +trait HasComponent<I> {} + +struct Foo; + +impl HasComponent<<Foo as Component<Foo>>::Interface> for Foo {} +//~^ ERROR the trait bound `Foo: HasComponent<()>` is not satisfied + +impl<M: HasComponent<()>> Component<M> for Foo { + type Interface = u8; +} + +fn main() {} diff --git a/src/test/ui/traits/issue-91594.stderr b/src/test/ui/traits/issue-91594.stderr new file mode 100644 index 00000000000..10298a0c703 --- /dev/null +++ b/src/test/ui/traits/issue-91594.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `Foo: HasComponent<()>` is not satisfied + --> $DIR/issue-91594.rs:10:6 + | +LL | impl HasComponent<<Foo as Component<Foo>>::Interface> for Foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo` + | + = help: the following implementations were found: + <Foo as HasComponent<<Foo as Component<Foo>>::Interface>> +note: required because of the requirements on the impl of `Component<Foo>` for `Foo` + --> $DIR/issue-91594.rs:13:27 + | +LL | impl<M: HasComponent<()>> Component<M> for Foo { + | ^^^^^^^^^^^^ ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/tuple/array-diagnostics.rs b/src/test/ui/tuple/array-diagnostics.rs new file mode 100644 index 00000000000..1929dab0731 --- /dev/null +++ b/src/test/ui/tuple/array-diagnostics.rs @@ -0,0 +1,7 @@ +fn main() { + let _tmp = [ + ("C200B40A82", 3), + ("C200B40A83", 4) //~ ERROR: expected function, found `(&'static str, {integer})` [E0618] + ("C200B40A8537", 5), + ]; +} diff --git a/src/test/ui/tuple/array-diagnostics.stderr b/src/test/ui/tuple/array-diagnostics.stderr new file mode 100644 index 00000000000..a10d7af470c --- /dev/null +++ b/src/test/ui/tuple/array-diagnostics.stderr @@ -0,0 +1,9 @@ +error[E0618]: expected function, found `(&'static str, {integer})` + --> $DIR/array-diagnostics.rs:4:9 + | +LL | ("C200B40A83", 4) + | ^^^^^^^^^^^^^^^^^- help: consider separating array elements with a comma: `,` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0618`. diff --git a/src/test/ui/type-alias-impl-trait/issue-60662.stdout b/src/test/ui/type-alias-impl-trait/issue-60662.stdout index 14a49f20e6b..a46047d9174 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60662.stdout +++ b/src/test/ui/type-alias-impl-trait/issue-60662.stdout @@ -10,5 +10,5 @@ extern crate std; trait Animal { } fn main() { - pub type ServeFut = /*impl Trait*/; - } + pub type ServeFut = /*impl Trait*/; + } diff --git a/src/test/ui/variance/variance-contravariant-arg-object.nll.stderr b/src/test/ui/variance/variance-contravariant-arg-object.nll.stderr index 91d4fd2e971..3315eaaf1c0 100644 --- a/src/test/ui/variance/variance-contravariant-arg-object.nll.stderr +++ b/src/test/ui/variance/variance-contravariant-arg-object.nll.stderr @@ -7,7 +7,7 @@ LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>) | lifetime `'min` defined here ... LL | v - | ^ returning this value requires that `'min` must outlive `'max` + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` | = help: consider adding the following bound: `'min: 'max` @@ -20,7 +20,7 @@ LL | fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>) | lifetime `'min` defined here ... LL | v - | ^ returning this value requires that `'min` must outlive `'max` + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` | = help: consider adding the following bound: `'min: 'max` diff --git a/src/test/ui/variance/variance-covariant-arg-object.nll.stderr b/src/test/ui/variance/variance-covariant-arg-object.nll.stderr index 37fdea960be..b116b8e263f 100644 --- a/src/test/ui/variance/variance-covariant-arg-object.nll.stderr +++ b/src/test/ui/variance/variance-covariant-arg-object.nll.stderr @@ -7,7 +7,7 @@ LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>) | lifetime `'min` defined here ... LL | v - | ^ returning this value requires that `'min` must outlive `'max` + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` | = help: consider adding the following bound: `'min: 'max` @@ -20,7 +20,7 @@ LL | fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>) | lifetime `'min` defined here ... LL | v - | ^ returning this value requires that `'min` must outlive `'max` + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` | = help: consider adding the following bound: `'min: 'max` diff --git a/src/test/ui/variance/variance-invariant-arg-object.nll.stderr b/src/test/ui/variance/variance-invariant-arg-object.nll.stderr index f6265980af7..303c7f3388a 100644 --- a/src/test/ui/variance/variance-invariant-arg-object.nll.stderr +++ b/src/test/ui/variance/variance-invariant-arg-object.nll.stderr @@ -7,7 +7,7 @@ LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>) | lifetime `'min` defined here ... LL | v - | ^ returning this value requires that `'min` must outlive `'max` + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` | = help: consider adding the following bound: `'min: 'max` @@ -20,7 +20,7 @@ LL | fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>) | lifetime `'min` defined here ... LL | v - | ^ returning this value requires that `'min` must outlive `'max` + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` | = help: consider adding the following bound: `'min: 'max` diff --git a/src/test/ui/variance/variance-use-contravariant-struct-1.nll.stderr b/src/test/ui/variance/variance-use-contravariant-struct-1.nll.stderr index eddd4b217c0..837c70ca313 100644 --- a/src/test/ui/variance/variance-use-contravariant-struct-1.nll.stderr +++ b/src/test/ui/variance/variance-use-contravariant-struct-1.nll.stderr @@ -7,7 +7,7 @@ LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>) | lifetime `'min` defined here ... LL | v - | ^ returning this value requires that `'min` must outlive `'max` + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` | = help: consider adding the following bound: `'min: 'max` diff --git a/src/test/ui/variance/variance-use-covariant-struct-1.nll.stderr b/src/test/ui/variance/variance-use-covariant-struct-1.nll.stderr index a86c1b93a73..bab858c5acb 100644 --- a/src/test/ui/variance/variance-use-covariant-struct-1.nll.stderr +++ b/src/test/ui/variance/variance-use-covariant-struct-1.nll.stderr @@ -7,7 +7,7 @@ LL | fn foo<'min,'max>(v: SomeStruct<&'min ()>) | lifetime `'min` defined here ... LL | v - | ^ returning this value requires that `'min` must outlive `'max` + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` | = help: consider adding the following bound: `'min: 'max` diff --git a/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr b/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr index 6890cb115c3..f1df2a88b6b 100644 --- a/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr +++ b/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr @@ -7,7 +7,7 @@ LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>) | lifetime `'min` defined here ... LL | v - | ^ returning this value requires that `'min` must outlive `'max` + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` | = help: consider adding the following bound: `'min: 'max` = note: requirement occurs because of the type SomeStruct<&()>, which makes the generic argument &() invariant @@ -23,7 +23,7 @@ LL | fn bar<'min,'max>(v: SomeStruct<&'min ()>) | lifetime `'min` defined here ... LL | v - | ^ returning this value requires that `'min` must outlive `'max` + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` | = help: consider adding the following bound: `'min: 'max` = note: requirement occurs because of the type SomeStruct<&()>, which makes the generic argument &() invariant diff --git a/src/test/ui/wf/wf-static-method.nll.stderr b/src/test/ui/wf/wf-static-method.nll.stderr index 9c066a7bdb0..26504311195 100644 --- a/src/test/ui/wf/wf-static-method.nll.stderr +++ b/src/test/ui/wf/wf-static-method.nll.stderr @@ -7,7 +7,7 @@ LL | impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () { | lifetime `'a` defined here ... LL | u - | ^ returning this value requires that `'b` must outlive `'a` + | ^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a` @@ -33,7 +33,7 @@ LL | impl<'a, 'b> Evil<'a, 'b> { | lifetime `'a` defined here LL | fn inherent_evil(u: &'b u32) -> &'a u32 { LL | u - | ^ returning this value requires that `'b` must outlive `'a` + | ^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a` @@ -45,7 +45,7 @@ LL | fn evil<'a, 'b>(b: &'b u32) -> &'a u32 { | | | lifetime `'a` defined here LL | <()>::static_evil(b) - | ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a` @@ -57,7 +57,7 @@ LL | fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 { | | | lifetime `'a` defined here LL | <IndirectEvil>::static_evil(b) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a` @@ -69,7 +69,7 @@ LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 { | | | lifetime `'a` defined here LL | <Evil>::inherent_evil(b) - | ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a` diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 95bb3c92bf516017e812e7f1c14c2dea3845b30 +Subproject 1c034752de0df744fcd7788fcbca158830b8bf8 diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 258a8256f53..d66e6cf7fb6 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -981,7 +981,7 @@ Released 2021-03-25 [#6532](https://github.com/rust-lang/rust-clippy/pull/6532) * [`single_match`] Suggest `if` over `if let` when possible [#6574](https://github.com/rust-lang/rust-clippy/pull/6574) -* [`ref_in_deref`] Use parentheses correctly in suggestion +* `ref_in_deref` Use parentheses correctly in suggestion [#6609](https://github.com/rust-lang/rust-clippy/pull/6609) * [`stable_sort_primitive`] Clarify error message [#6611](https://github.com/rust-lang/rust-clippy/pull/6611) @@ -3227,7 +3227,6 @@ Released 2018-09-13 [`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes [`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference -[`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once diff --git a/src/tools/clippy/clippy_dev/src/bless.rs b/src/tools/clippy/clippy_dev/src/bless.rs index daf0fcc993b..dcc2502e4c5 100644 --- a/src/tools/clippy/clippy_dev/src/bless.rs +++ b/src/tools/clippy/clippy_dev/src/bless.rs @@ -9,9 +9,14 @@ use walkdir::WalkDir; use crate::clippy_project_root; +#[cfg(not(windows))] +static CARGO_CLIPPY_EXE: &str = "cargo-clippy"; +#[cfg(windows)] +static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe"; + static CLIPPY_BUILD_TIME: SyncLazy<Option<std::time::SystemTime>> = SyncLazy::new(|| { let mut path = std::env::current_exe().unwrap(); - path.set_file_name("cargo-clippy"); + path.set_file_name(CARGO_CLIPPY_EXE); fs::metadata(path).ok()?.modified().ok() }); diff --git a/src/tools/clippy/clippy_dev/src/lint.rs b/src/tools/clippy/clippy_dev/src/lint.rs index dfd16f71054..b8287980a4b 100644 --- a/src/tools/clippy/clippy_dev/src/lint.rs +++ b/src/tools/clippy/clippy_dev/src/lint.rs @@ -7,7 +7,6 @@ pub fn run(filename: &str) { .args(["-Z", "no-codegen"]) .args(["--edition", "2021"]) .arg(filename) - .env("__CLIPPY_INTERNAL_TESTS", "true") .status() .expect("failed to run cargo") .code(); diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs index 5061c9d1eaf..e109ee0009e 100644 --- a/src/tools/clippy/clippy_lints/src/approx_const.rs +++ b/src/tools/clippy/clippy_lints/src/approx_const.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::{meets_msrv, msrvs}; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol; diff --git a/src/tools/clippy/clippy_lints/src/as_conversions.rs b/src/tools/clippy/clippy_lints/src/as_conversions.rs index 53704da1046..88b91d58907 100644 --- a/src/tools/clippy/clippy_lints/src/as_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/as_conversions.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Expr, ExprKind}; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -48,7 +48,7 @@ declare_lint_pass!(AsConversions => [AS_CONVERSIONS]); impl EarlyLintPass for AsConversions { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if in_external_macro(cx.sess, expr.span) { + if in_external_macro(cx.sess(), expr.span) { return; } diff --git a/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs b/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs index b8f5217af2b..9f8eb488c29 100644 --- a/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs @@ -94,4 +94,6 @@ impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr { } } } + + extract_msrv_attr!(LateContext); } diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index 1915d990c12..470c8c7ea26 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -23,15 +23,14 @@ pub(super) fn check( if_chain! { if let LitKind::Int(n, _) = lit.node; - if let Some(src) = snippet_opt(cx, lit.span); + if let Some(src) = snippet_opt(cx, cast_expr.span); if cast_to.is_floating_point(); if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node); let from_nbits = 128 - n.leading_zeros(); let to_nbits = fp_ty_mantissa_nbits(cast_to); if from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits && num_lit.is_decimal(); then { - let literal_str = if is_unary_neg(cast_expr) { format!("-{}", num_lit.integer) } else { num_lit.integer.into() }; - lint_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to); + lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to); return true } } @@ -48,7 +47,7 @@ pub(super) fn check( | LitKind::Float(_, LitFloatType::Suffixed(_)) if cast_from.kind() == cast_to.kind() => { - if let Some(src) = snippet_opt(cx, lit.span) { + if let Some(src) = snippet_opt(cx, cast_expr.span) { if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) { lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to); } @@ -113,7 +112,3 @@ fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 { _ => 0, } } - -fn is_unary_neg(expr: &Expr<'_>) -> bool { - matches!(expr.kind, ExprKind::Unary(UnOp::Neg, _)) -} diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index feb5f100de5..c0adab790f0 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; +use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::ty::peel_mid_ty_refs; use clippy_utils::{get_parent_expr, get_parent_node, is_lint_allowed, path_to_local}; use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; @@ -10,11 +11,10 @@ use rustc_hir::{ Pat, PatKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{self, Ty, TyCtxt, TyS, TypeckResults}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{symbol::sym, Span}; -use std::iter; declare_clippy_lint! { /// ### What it does @@ -131,8 +131,6 @@ pub struct Dereferencing { struct StateData { /// Span of the top level expression span: Span, - /// The required mutability - target_mut: Mutability, } enum State { @@ -141,9 +139,13 @@ enum State { // The number of calls in a sequence which changed the referenced type ty_changed_count: usize, is_final_ufcs: bool, + /// The required mutability + target_mut: Mutability, }, DerefedBorrow { - count: u32, + count: usize, + required_precedence: i8, + msg: &'static str, }, } @@ -214,59 +216,98 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { 1 }, is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)), - }, - StateData { - span: expr.span, target_mut, }, + StateData { span: expr.span }, )); }, RefOp::AddrOf => { // Find the number of times the borrow is auto-derefed. let mut iter = find_adjustments(cx.tcx, typeck, expr).iter(); - if let Some((i, adjust)) = iter.by_ref().enumerate().find_map(|(i, adjust)| { - if !matches!(adjust.kind, Adjust::Deref(_)) { - Some((i, adjust)) - } else if !adjust.target.is_ref() { - // Add one to the number of references found. - Some((i + 1, adjust)) + let mut deref_count = 0usize; + let next_adjust = loop { + match iter.next() { + Some(adjust) => { + if !matches!(adjust.kind, Adjust::Deref(_)) { + break Some(adjust); + } else if !adjust.target.is_ref() { + deref_count += 1; + break iter.next(); + } + deref_count += 1; + }, + None => break None, + }; + }; + + // Determine the required number of references before any can be removed. In all cases the + // reference made by the current expression will be removed. After that there are four cases to + // handle. + // + // 1. Auto-borrow will trigger in the current position, so no further references are required. + // 2. Auto-deref ends at a reference, or the underlying type, so one extra needs to be left to + // handle the automatically inserted re-borrow. + // 3. Auto-deref hits a user-defined `Deref` impl, so at least one reference needs to exist to + // start auto-deref. + // 4. If the chain of non-user-defined derefs ends with a mutable re-borrow, and re-borrow + // adjustments will not be inserted automatically, then leave one further reference to avoid + // moving a mutable borrow. + // e.g. + // fn foo<T>(x: &mut Option<&mut T>, y: &mut T) { + // let x = match x { + // // Removing the borrow will cause `x` to be moved + // Some(x) => &mut *x, + // None => y + // }; + // } + let deref_msg = + "this expression creates a reference which is immediately dereferenced by the compiler"; + let borrow_msg = "this expression borrows a value the compiler would automatically borrow"; + + let (required_refs, required_precedence, msg) = if is_auto_borrow_position(parent, expr.hir_id) + { + (1, PREC_POSTFIX, if deref_count == 1 { borrow_msg } else { deref_msg }) + } else if let Some(&Adjust::Borrow(AutoBorrow::Ref(_, mutability))) = + next_adjust.map(|a| &a.kind) + { + if matches!(mutability, AutoBorrowMutability::Mut { .. }) + && !is_auto_reborrow_position(parent) + { + (3, 0, deref_msg) } else { - None - } - }) { - // Found two consecutive derefs. At least one can be removed. - if i > 1 { - let target_mut = iter::once(adjust) - .chain(iter) - .find_map(|adjust| match adjust.kind { - Adjust::Borrow(AutoBorrow::Ref(_, m)) => Some(m.into()), - _ => None, - }) - // This default should never happen. Auto-deref always reborrows. - .unwrap_or(Mutability::Not); - self.state = Some(( - // Subtract one for the current borrow expression, and one to cover the last - // reference which can't be removed (it's either reborrowed, or needed for - // auto-deref to happen). - State::DerefedBorrow { - count: - // Truncation here would require more than a `u32::MAX` level reference. The compiler - // does not support this. - #[allow(clippy::cast_possible_truncation)] - { i as u32 - 2 } - }, - StateData { - span: expr.span, - target_mut, - }, - )); + (2, 0, deref_msg) } + } else { + (2, 0, deref_msg) + }; + + if deref_count >= required_refs { + self.state = Some(( + State::DerefedBorrow { + // One of the required refs is for the current borrow expression, the remaining ones + // can't be removed without breaking the code. See earlier comment. + count: deref_count - required_refs, + required_precedence, + msg, + }, + StateData { span: expr.span }, + )); } }, _ => (), } }, - (Some((State::DerefMethod { ty_changed_count, .. }, data)), RefOp::Method(_)) => { + ( + Some(( + State::DerefMethod { + target_mut, + ty_changed_count, + .. + }, + data, + )), + RefOp::Method(_), + ) => { self.state = Some(( State::DerefMethod { ty_changed_count: if deref_method_same_type(typeck.expr_ty(expr), typeck.expr_ty(sub_expr)) { @@ -275,12 +316,30 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { ty_changed_count + 1 }, is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)), + target_mut, }, data, )); }, - (Some((State::DerefedBorrow { count }, data)), RefOp::AddrOf) if count != 0 => { - self.state = Some((State::DerefedBorrow { count: count - 1 }, data)); + ( + Some(( + State::DerefedBorrow { + count, + required_precedence, + msg, + }, + data, + )), + RefOp::AddrOf, + ) if count != 0 => { + self.state = Some(( + State::DerefedBorrow { + count: count - 1, + required_precedence, + msg, + }, + data, + )); }, (Some((state, data)), _) => report(cx, expr, state, data), @@ -455,6 +514,30 @@ fn is_linted_explicit_deref_position(parent: Option<Node<'_>>, child_id: HirId, } } +/// Checks if the given expression is in a position which can be auto-reborrowed. +/// Note: This is only correct assuming auto-deref is already occurring. +fn is_auto_reborrow_position(parent: Option<Node<'_>>) -> bool { + match parent { + Some(Node::Expr(parent)) => matches!(parent.kind, ExprKind::MethodCall(..) | ExprKind::Call(..)), + Some(Node::Local(_)) => true, + _ => false, + } +} + +/// Checks if the given expression is a position which can auto-borrow. +fn is_auto_borrow_position(parent: Option<Node<'_>>, child_id: HirId) -> bool { + if let Some(Node::Expr(parent)) = parent { + match parent.kind { + ExprKind::MethodCall(_, [self_arg, ..], _) => self_arg.hir_id == child_id, + ExprKind::Field(..) => true, + ExprKind::Call(f, _) => f.hir_id == child_id, + _ => false, + } + } else { + false + } +} + /// Adjustments are sometimes made in the parent block rather than the expression itself. fn find_adjustments<'tcx>( tcx: TyCtxt<'tcx>, @@ -503,6 +586,7 @@ fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData) State::DerefMethod { ty_changed_count, is_final_ufcs, + target_mut, } => { let mut app = Applicability::MachineApplicable; let (expr_str, expr_is_macro_call) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app); @@ -517,12 +601,12 @@ fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData) }; let addr_of_str = if ty_changed_count < ref_count { // Check if a reborrow from &mut T -> &T is required. - if data.target_mut == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) { + if target_mut == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) { "&*" } else { "" } - } else if data.target_mut == Mutability::Mut { + } else if target_mut == Mutability::Mut { "&mut " } else { "&" @@ -538,7 +622,7 @@ fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData) cx, EXPLICIT_DEREF_METHODS, data.span, - match data.target_mut { + match target_mut { Mutability::Not => "explicit `deref` method call", Mutability::Mut => "explicit `deref_mut` method call", }, @@ -547,19 +631,24 @@ fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData) app, ); }, - State::DerefedBorrow { .. } => { + State::DerefedBorrow { + required_precedence, + msg, + .. + } => { let mut app = Applicability::MachineApplicable; let snip = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app).0; span_lint_and_sugg( cx, NEEDLESS_BORROW, data.span, - &format!( - "this expression borrows a reference (`{}`) that is immediately dereferenced by the compiler", - cx.typeck_results().expr_ty(expr), - ), + msg, "change this to", - snip.into(), + if required_precedence > expr.precedence().order() && !has_enclosing_paren(&snip) { + format!("({})", snip) + } else { + snip.into() + }, app, ); }, diff --git a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs index 3c3f3631849..0c27c3f9255 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast; use rustc_data_structures::fx::FxHashSet; -use rustc_lint::{EarlyContext, EarlyLintPass, Level}; +use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use unicode_script::{Script, UnicodeScript}; @@ -72,7 +72,7 @@ impl EarlyLintPass for DisallowedScriptIdents { return; } - let symbols = cx.sess.parse_sess.symbol_gallery.symbols.lock(); + let symbols = cx.sess().parse_sess.symbol_gallery.symbols.lock(); // Sort by `Span` so that error messages make sense with respect to the // order of identifier locations in the code. let mut symbols: Vec<_> = symbols.iter().collect(); diff --git a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs index 92c56c762aa..0b9f54231c5 100644 --- a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs +++ b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Expr, ExprKind}; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -50,7 +50,7 @@ declare_lint_pass!(ElseIfWithoutElse => [ELSE_IF_WITHOUT_ELSE]); impl EarlyLintPass for ElseIfWithoutElse { fn check_expr(&mut self, cx: &EarlyContext<'_>, mut item: &Expr) { - if in_external_macro(cx.sess, item.span) { + if in_external_macro(cx.sess(), item.span) { return; } diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs index 4f89e567430..1f4353fa4f7 100644 --- a/src/tools/clippy/clippy_lints/src/enum_variants.rs +++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs @@ -172,6 +172,9 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n let name = var.ident.name.as_str(); let variant_split = camel_case_split(name); + if variant_split.len() == 1 { + return; + } pre = pre .iter() diff --git a/src/tools/clippy/clippy_lints/src/eq_op.rs b/src/tools/clippy/clippy_lints/src/eq_op.rs index df75b815436..24d7613e6f8 100644 --- a/src/tools/clippy/clippy_lints/src/eq_op.rs +++ b/src/tools/clippy/clippy_lints/src/eq_op.rs @@ -1,12 +1,16 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_then}; +use clippy_utils::get_enclosing_block; use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace}; use clippy_utils::source::snippet; use clippy_utils::ty::{implements_trait, is_copy}; use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, is_in_test_function}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind}; +use rustc_hir::{ + def::Res, def_id::DefId, BinOpKind, BorrowKind, Expr, ExprKind, GenericArg, ItemKind, QPath, Ty, TyKind, +}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -146,6 +150,13 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { let rty = cx.typeck_results().expr_ty(r); let lcpy = is_copy(cx, lty); let rcpy = is_copy(cx, rty); + if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id) { + if (are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty)) + || (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty)) + { + return; // Don't lint + } + } // either operator autorefs or both args are copyable if (requires_ref || (lcpy && rcpy)) && implements_trait(cx, lty, trait_id, &[rty.into()]) { span_lint_and_then( @@ -206,6 +217,14 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { // &foo == bar (&ExprKind::AddrOf(BorrowKind::Ref, _, l), _) => { let lty = cx.typeck_results().expr_ty(l); + if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id) { + let rty = cx.typeck_results().expr_ty(right); + if (are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty)) + || (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty)) + { + return; // Don't lint + } + } let lcpy = is_copy(cx, lty); if (requires_ref || lcpy) && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()]) @@ -230,6 +249,14 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { // foo == &bar (_, &ExprKind::AddrOf(BorrowKind::Ref, _, r)) => { let rty = cx.typeck_results().expr_ty(r); + if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id) { + let lty = cx.typeck_results().expr_ty(left); + if (are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty)) + || (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty)) + { + return; // Don't lint + } + } let rcpy = is_copy(cx, rty); if (requires_ref || rcpy) && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()]) @@ -251,3 +278,43 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { } } } + +fn in_impl<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, bin_op: DefId) -> Option<(&'tcx Ty<'tcx>, &'tcx Ty<'tcx>)> { + if_chain! { + if let Some(block) = get_enclosing_block(cx, e.hir_id); + if let Some(impl_def_id) = cx.tcx.impl_of_method(block.hir_id.owner.to_def_id()); + let item = cx.tcx.hir().expect_item(impl_def_id.expect_local()); + if let ItemKind::Impl(item) = &item.kind; + if let Some(of_trait) = &item.of_trait; + if let Some(seg) = of_trait.path.segments.last(); + if let Some(Res::Def(_, trait_id)) = seg.res; + if trait_id == bin_op; + if let Some(generic_args) = seg.args; + if let Some(GenericArg::Type(other_ty)) = generic_args.args.last(); + + then { + Some((item.self_ty, other_ty)) + } + else { + None + } + } +} + +fn are_equal<'tcx>(cx: &LateContext<'tcx>, middle_ty: &TyS<'_>, hir_ty: &Ty<'_>) -> bool { + if_chain! { + if let ty::Adt(adt_def, _) = middle_ty.kind(); + if let Some(local_did) = adt_def.did.as_local(); + let item = cx.tcx.hir().expect_item(local_did); + let middle_ty_id = item.def_id.to_def_id(); + if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind; + if let Res::Def(_, hir_ty_id) = path.res; + + then { + hir_ty_id == middle_ty_id + } + else { + false + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs index 3e85c8a9c80..ae18f8081bc 100644 --- a/src/tools/clippy/clippy_lints/src/formatting.rs +++ b/src/tools/clippy/clippy_lints/src/formatting.rs @@ -3,7 +3,7 @@ use clippy_utils::differing_macro_contexts; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; @@ -207,7 +207,7 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::If(_, then, Some(else_)) = &expr.kind; if is_block(else_) || is_if(else_); if !differing_macro_contexts(then.span, else_.span); - if !then.span.from_expansion() && !in_external_macro(cx.sess, expr.span); + if !then.span.from_expansion() && !in_external_macro(cx.sess(), expr.span); // workaround for rust-lang/rust#43081 if expr.span.lo().0 != 0 && expr.span.hi().0 != 0; @@ -259,7 +259,7 @@ fn has_unary_equivalent(bin_op: BinOpKind) -> bool { } fn indentation(cx: &EarlyContext<'_>, span: Span) -> usize { - cx.sess.source_map().lookup_char_pos(span.lo()).col.0 + cx.sess().source_map().lookup_char_pos(span.lo()).col.0 } /// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs index 5ece2cc5ac4..c2f52605151 100644 --- a/src/tools/clippy/clippy_lints/src/from_over_into.rs +++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::{meets_msrv, msrvs}; use if_chain::if_chain; use rustc_hir as hir; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::sym; diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index 104de0ff62f..eed25e9bc0e 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -179,7 +179,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { ) .and_then(|snip| { let i = snip.find("fn")?; - Some(item.span.lo() + BytePos((i + (&snip[i..]).find('(')?) as u32)) + Some(item.span.lo() + BytePos((i + snip[i..].find('(')?) as u32)) }) .expect("failed to create span for type parameters"); Span::new(pos, pos, item.span.ctxt(), item.span.parent()) diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs index 4615122bbf9..2a4bcd773c6 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -4,11 +4,11 @@ use clippy_utils::higher::IfLet; use clippy_utils::ty::is_copy; use clippy_utils::{is_expn_of, is_lint_allowed, meets_msrv, msrvs, path_to_local}; use if_chain::if_chain; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty; use rustc_semver::RustcVersion; @@ -92,9 +92,9 @@ impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice { extract_msrv_attr!(LateContext); } -fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxHashMap<hir::HirId, SliceLintInformation> { +fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<hir::HirId, SliceLintInformation> { let mut removed_pat: FxHashSet<hir::HirId> = FxHashSet::default(); - let mut slices: FxHashMap<hir::HirId, SliceLintInformation> = FxHashMap::default(); + let mut slices: FxIndexMap<hir::HirId, SliceLintInformation> = FxIndexMap::default(); pat.walk_always(|pat| { if let hir::PatKind::Binding(binding, value_hir_id, ident, sub_pat) = pat.kind { // We'll just ignore mut and ref mut for simplicity sake right now @@ -208,10 +208,10 @@ impl SliceLintInformation { fn filter_lintable_slices<'a, 'tcx>( cx: &'a LateContext<'tcx>, - slice_lint_info: FxHashMap<hir::HirId, SliceLintInformation>, + slice_lint_info: FxIndexMap<hir::HirId, SliceLintInformation>, max_suggested_slice: u64, scope: &'tcx hir::Expr<'tcx>, -) -> FxHashMap<hir::HirId, SliceLintInformation> { +) -> FxIndexMap<hir::HirId, SliceLintInformation> { let mut visitor = SliceIndexLintingVisitor { cx, slice_lint_info, @@ -225,7 +225,7 @@ fn filter_lintable_slices<'a, 'tcx>( struct SliceIndexLintingVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, - slice_lint_info: FxHashMap<hir::HirId, SliceLintInformation>, + slice_lint_info: FxIndexMap<hir::HirId, SliceLintInformation>, max_suggested_slice: u64, } diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs index b118d3c8b87..cdefe627efd 100644 --- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs +++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Block, ItemKind, StmtKind}; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -55,7 +55,7 @@ declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]); impl EarlyLintPass for ItemsAfterStatements { fn check_block(&mut self, cx: &EarlyContext<'_>, item: &Block) { - if in_external_macro(cx.sess, item.span) { + if in_external_macro(cx.sess(), item.span) { return; } @@ -69,7 +69,7 @@ impl EarlyLintPass for ItemsAfterStatements { // lint on all further items for stmt in stmts { if let StmtKind::Item(ref it) = *stmt { - if in_external_macro(cx.sess, it.span) { + if in_external_macro(cx.sess(), it.span) { return; } if let ItemKind::MacroDef(..) = it.kind { diff --git a/src/tools/clippy/clippy_lints/src/lib.register_all.rs b/src/tools/clippy/clippy_lints/src/lib.register_all.rs index 87fd7f99748..4721b7f2b47 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_all.rs @@ -247,7 +247,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(redundant_slicing::REDUNDANT_SLICING), LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), LintId::of(reference::DEREF_ADDROF), - LintId::of(reference::REF_IN_DEREF), LintId::of(regex::INVALID_REGEX), LintId::of(repeat_once::REPEAT_ONCE), LintId::of(returns::LET_AND_RETURN), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs b/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs index a21ddf73a11..bd5ff613447 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs @@ -71,7 +71,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL), LintId::of(redundant_slicing::REDUNDANT_SLICING), LintId::of(reference::DEREF_ADDROF), - LintId::of(reference::REF_IN_DEREF), LintId::of(repeat_once::REPEAT_ONCE), LintId::of(strings::STRING_FROM_UTF8_AS_BYTES), LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs index 56146a0fd3a..2d2693832e9 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs @@ -423,7 +423,6 @@ store.register_lints(&[ redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES, ref_option_ref::REF_OPTION_REF, reference::DEREF_ADDROF, - reference::REF_IN_DEREF, regex::INVALID_REGEX, regex::TRIVIAL_REGEX, repeat_once::REPEAT_ONCE, diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 79e9882fef4..f2a7e925dd3 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -581,6 +581,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(needless_question_mark::NeedlessQuestionMark)); store.register_late_pass(move || Box::new(casts::Casts::new(msrv))); store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv))); + store.register_late_pass(move || Box::new(map_clone::MapClone::new(msrv))); store.register_late_pass(|| Box::new(size_of_in_element_count::SizeOfInElementCount)); store.register_late_pass(|| Box::new(same_name_method::SameNameMethod)); @@ -591,7 +592,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: msrv, )) }); - store.register_late_pass(|| Box::new(map_clone::MapClone)); store.register_late_pass(|| Box::new(map_err_ignore::MapErrIgnore)); store.register_late_pass(|| Box::new(shadow::Shadow::default())); store.register_late_pass(|| Box::new(unit_types::UnitTypes)); @@ -703,7 +703,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(mut_key::MutableKeyType)); store.register_late_pass(|| Box::new(modulo_arithmetic::ModuloArithmetic)); store.register_early_pass(|| Box::new(reference::DerefAddrOf)); - store.register_early_pass(|| Box::new(reference::RefInDeref)); store.register_early_pass(|| Box::new(double_parens::DoubleParens)); store.register_late_pass(|| Box::new(to_string_in_display::ToStringInDisplay::new())); store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval)); @@ -935,6 +934,7 @@ pub fn register_renamed(ls: &mut rustc_lint::LintStore) { ls.register_renamed("clippy::if_let_some_result", "clippy::match_result_ok"); ls.register_renamed("clippy::disallowed_type", "clippy::disallowed_types"); ls.register_renamed("clippy::disallowed_method", "clippy::disallowed_methods"); + ls.register_renamed("clippy::ref_in_deref", "clippy::needless_borrow"); // uplifted lints ls.register_renamed("clippy::invalid_ref", "invalid_value"); diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 56505714045..b09c23f31e9 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -13,7 +13,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use rustc_span::symbol::{kw, Symbol}; +use rustc_span::symbol::{kw, Ident, Symbol}; declare_clippy_lint! { /// ### What it does @@ -83,7 +83,7 @@ declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]); impl<'tcx> LateLintPass<'tcx> for Lifetimes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if let ItemKind::Fn(ref sig, ref generics, id) = item.kind { - check_fn_inner(cx, sig.decl, Some(id), generics, item.span, true); + check_fn_inner(cx, sig.decl, Some(id), None, generics, item.span, true); } } @@ -94,6 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { cx, sig.decl, Some(id), + None, &item.generics, item.span, report_extra_lifetimes, @@ -103,11 +104,11 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { if let TraitItemKind::Fn(ref sig, ref body) = item.kind { - let body = match *body { - TraitFn::Required(_) => None, - TraitFn::Provided(id) => Some(id), + let (body, trait_sig) = match *body { + TraitFn::Required(sig) => (None, Some(sig)), + TraitFn::Provided(id) => (Some(id), None), }; - check_fn_inner(cx, sig.decl, body, &item.generics, item.span, true); + check_fn_inner(cx, sig.decl, body, trait_sig, &item.generics, item.span, true); } } } @@ -124,6 +125,7 @@ fn check_fn_inner<'tcx>( cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'_>, body: Option<BodyId>, + trait_sig: Option<&[Ident]>, generics: &'tcx Generics<'_>, span: Span, report_extra_lifetimes: bool, @@ -165,7 +167,7 @@ fn check_fn_inner<'tcx>( } } } - if could_use_elision(cx, decl, body, generics.params) { + if could_use_elision(cx, decl, body, trait_sig, generics.params) { span_lint( cx, NEEDLESS_LIFETIMES, @@ -179,10 +181,31 @@ fn check_fn_inner<'tcx>( } } +// elision doesn't work for explicit self types, see rust-lang/rust#69064 +fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Ident>) -> bool { + if_chain! { + if let Some(ident) = ident; + if ident.name == kw::SelfLower; + if !func.implicit_self.has_implicit_self(); + + if let Some(self_ty) = func.inputs.first(); + then { + let mut visitor = RefVisitor::new(cx); + visitor.visit_ty(self_ty); + + !visitor.all_lts().is_empty() + } + else { + false + } + } +} + fn could_use_elision<'tcx>( cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, body: Option<BodyId>, + trait_sig: Option<&[Ident]>, named_generics: &'tcx [GenericParam<'_>], ) -> bool { // There are two scenarios where elision works: @@ -233,11 +256,24 @@ fn could_use_elision<'tcx>( let input_lts = input_visitor.lts; let output_lts = output_visitor.lts; + if let Some(trait_sig) = trait_sig { + if explicit_self_type(cx, func, trait_sig.first().copied()) { + return false; + } + } + if let Some(body_id) = body { + let body = cx.tcx.hir().body(body_id); + + let first_ident = body.params.first().and_then(|param| param.pat.simple_ident()); + if explicit_self_type(cx, func, first_ident) { + return false; + } + let mut checker = BodyLifetimeChecker { lifetimes_used_in_body: false, }; - checker.visit_expr(&cx.tcx.hir().body(body_id).value); + checker.visit_expr(&body.value); if checker.lifetimes_used_in_body { return false; } diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs index 130543bbbee..b7430f49229 100644 --- a/src/tools/clippy/clippy_lints/src/literal_representation.rs +++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs @@ -7,7 +7,7 @@ use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind}; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; use std::iter; @@ -225,7 +225,7 @@ impl_lint_pass!(LiteralDigitGrouping => [ impl EarlyLintPass for LiteralDigitGrouping { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if in_external_macro(cx.sess, expr.span) { + if in_external_macro(cx.sess(), expr.span) { return; } @@ -418,7 +418,7 @@ impl_lint_pass!(DecimalLiteralRepresentation => [DECIMAL_LITERAL_REPRESENTATION] impl EarlyLintPass for DecimalLiteralRepresentation { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if in_external_macro(cx.sess, expr.span) { + if in_external_macro(cx.sess(), expr.span) { return; } diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index 2af3555e370..babc6fab3c0 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -6,8 +6,8 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - Term, AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId, - IsAsync, ItemKind, LifetimeName, TraitRef, Ty, TyKind, TypeBindingKind, + AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId, + IsAsync, ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs index 50bf2527e39..809aa168a7a 100644 --- a/src/tools/clippy/clippy_lints/src/manual_bits.rs +++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs @@ -72,6 +72,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualBits { } } } + + extract_msrv_attr!(LateContext); } fn get_one_size_of_ty<'tcx>( diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index 63a72d4fdde..33d1bb2985f 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -5,7 +5,7 @@ use clippy_utils::{meets_msrv, msrvs}; use if_chain::if_chain; use rustc_ast::ast::{FieldDef, Item, ItemKind, Variant, VariantData, VisibilityKind}; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Span}; @@ -116,7 +116,7 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants |diag| { if_chain! { if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive)); - let header_span = cx.sess.source_map().span_until_char(item.span, '{'); + let header_span = cx.sess().source_map().span_until_char(item.span, '{'); if let Some(snippet) = snippet_opt(cx, header_span); then { diag.span_suggestion( @@ -149,7 +149,7 @@ fn check_manual_non_exhaustive_struct(cx: &EarlyContext<'_>, item: &Item, data: VariantData::Unit(_) => unreachable!("`VariantData::Unit` is already handled above"), }; - cx.sess.source_map().span_until_char(item.span, delimiter) + cx.sess().source_map().span_until_char(item.span, delimiter) } let fields = data.fields(); diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index c814e013c63..aacabf303a7 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -9,7 +9,7 @@ use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::BinOpKind; use rustc_hir::{BorrowKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs index 22a2552b283..3f8eeb736fb 100644 --- a/src/tools/clippy/clippy_lints/src/map_clone.rs +++ b/src/tools/clippy/clippy_lints/src/map_clone.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; -use clippy_utils::{is_trait_method, peel_blocks}; +use clippy_utils::{is_trait_method, meets_msrv, msrvs, peel_blocks}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -9,7 +9,8 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::Mutability; use rustc_middle::ty; use rustc_middle::ty::adjustment::Adjust; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::Ident; use rustc_span::{sym, Span}; @@ -42,7 +43,17 @@ declare_clippy_lint! { "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types" } -declare_lint_pass!(MapClone => [MAP_CLONE]); +pub struct MapClone { + msrv: Option<RustcVersion>, +} + +impl_lint_pass!(MapClone => [MAP_CLONE]); + +impl MapClone { + pub fn new(msrv: Option<RustcVersion>) -> Self { + Self { msrv } + } +} impl<'tcx> LateLintPass<'tcx> for MapClone { fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) { @@ -65,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { hir::BindingAnnotation::Unannotated, .., name, None ) = inner.kind { if ident_eq(name, closure_expr) { - lint(cx, e.span, args[0].span, true); + self.lint_explicit_closure(cx, e.span, args[0].span, true); } }, hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => { @@ -73,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { hir::ExprKind::Unary(hir::UnOp::Deref, inner) => { if ident_eq(name, inner) { if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() { - lint(cx, e.span, args[0].span, true); + self.lint_explicit_closure(cx, e.span, args[0].span, true); } } }, @@ -90,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { if let ty::Ref(_, ty, mutability) = obj_ty.kind() { if matches!(mutability, Mutability::Not) { let copy = is_copy(cx, ty); - lint(cx, e.span, args[0].span, copy); + self.lint_explicit_closure(cx, e.span, args[0].span, copy); } } else { lint_needless_cloning(cx, e.span, args[0].span); @@ -105,6 +116,8 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { } } } + + extract_msrv_attr!(LateContext); } fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool { @@ -127,31 +140,30 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) { ); } -fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) { - let mut applicability = Applicability::MachineApplicable; - if copied { - span_lint_and_sugg( - cx, - MAP_CLONE, - replace, - "you are using an explicit closure for copying elements", - "consider calling the dedicated `copied` method", - format!( - "{}.copied()", - snippet_with_applicability(cx, root, "..", &mut applicability) - ), - applicability, - ); - } else { +impl MapClone { + fn lint_explicit_closure(&self, cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) { + let mut applicability = Applicability::MachineApplicable; + let message = if is_copy { + "you are using an explicit closure for copying elements" + } else { + "you are using an explicit closure for cloning elements" + }; + let sugg_method = if is_copy && meets_msrv(self.msrv.as_ref(), &msrvs::ITERATOR_COPIED) { + "copied" + } else { + "cloned" + }; + span_lint_and_sugg( cx, MAP_CLONE, replace, - "you are using an explicit closure for cloning elements", - "consider calling the dedicated `cloned` method", + message, + &format!("consider calling the dedicated `{}` method", sugg_method), format!( - "{}.cloned()", - snippet_with_applicability(cx, root, "..", &mut applicability) + "{}.{}()", + snippet_with_applicability(cx, root, "..", &mut applicability), + sugg_method, ), applicability, ); diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs index 411a797b6cb..2579404fb18 100644 --- a/src/tools/clippy/clippy_lints/src/matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches.rs @@ -25,12 +25,12 @@ use rustc_hir::{ Mutability, Node, Pat, PatKind, PathSegment, QPath, RangeEnd, TyKind, }; use rustc_hir::{HirIdMap, HirIdSet}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty, TyS, VariantDef}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; -use rustc_span::sym; +use rustc_span::{sym, symbol::kw}; use std::cmp::Ordering; use std::collections::hash_map::Entry; @@ -961,13 +961,13 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)); if path_str == "Err" { let mut matching_wild = inner.iter().any(is_wild); - let mut ident_bind_name = String::from("_"); + let mut ident_bind_name = kw::Underscore; if !matching_wild { // Looking for unused bindings (i.e.: `_e`) for pat in inner.iter() { if let PatKind::Binding(_, id, ident, None) = pat.kind { if ident.as_str().starts_with('_') && !is_local_used(cx, arm.body, id) { - ident_bind_name = ident.name.as_str().to_string(); + ident_bind_name = ident.name; matching_wild = true; } } @@ -982,7 +982,7 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm span_lint_and_note(cx, MATCH_WILD_ERR_ARM, arm.pat.span, - &format!("`Err({})` matches all errors", &ident_bind_name), + &format!("`Err({})` matches all errors", ident_bind_name), None, "match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable", ); diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs index 7fc39f17232..a184806d021 100644 --- a/src/tools/clippy/clippy_lints/src/mem_replace.rs +++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs @@ -6,7 +6,7 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs index e7d2d550a30..d813edab687 100644 --- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr, hir::ExprKind::MethodCall(method_name, call_args, _) => { if call_args.len() == 1 - && (method_name.ident.name == sym::as_str || method_name.ident.name == sym!(as_ref)) + && (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && { let arg_type = cx.typeck_results().expr_ty(&call_args[0]); let base_type = arg_type.peel_refs(); diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 137c9628eb4..4b43448bf7b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -2180,8 +2180,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods { for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) { if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() { let assoc_ty = match projection_predicate.term { - ty::Term::Ty(ty) => ty, - ty::Term::Const(_c) => continue, + ty::Term::Ty(ty) => ty, + ty::Term::Const(_c) => continue, }; // walk the associated type and check for Self if let Some(self_adt) = self_ty.ty_adt_def() { diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs index 6e09e25109f..d955fad7d41 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs @@ -12,7 +12,7 @@ use clippy_utils::source::snippet_opt; use rustc_ast::ast::{Expr, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind}; use rustc_ast::visit::FnKind; use rustc_data_structures::fx::FxHashMap; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; @@ -342,7 +342,7 @@ impl EarlyLintPass for MiscEarlyLints { } fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if in_external_macro(cx.sess, expr.span) { + if in_external_macro(cx.sess(), expr.span) { return; } diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index 77849e1800f..bad9e0be82e 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -5,7 +5,7 @@ use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, msr use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/src/tools/clippy/clippy_lints/src/module_style.rs b/src/tools/clippy/clippy_lints/src/module_style.rs index 3b65f80cba2..b8dfe996880 100644 --- a/src/tools/clippy/clippy_lints/src/module_style.rs +++ b/src/tools/clippy/clippy_lints/src/module_style.rs @@ -80,9 +80,9 @@ impl EarlyLintPass for ModStyle { return; } - let files = cx.sess.source_map().files(); + let files = cx.sess().source_map().files(); - let trim_to_src = if let RealFileName::LocalPath(p) = &cx.sess.opts.working_dir { + let trim_to_src = if let RealFileName::LocalPath(p) = &cx.sess().opts.working_dir { p.to_string_lossy() } else { return; diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index 0e7ae43ce2d..d4c823d1c1a 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionSome, ResultOk}; -use rustc_hir::{Body, Expr, ExprKind, LangItem, MatchSource, QPath}; +use rustc_hir::{AsyncGeneratorKind, Block, Body, Expr, ExprKind, GeneratorKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyS; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -88,7 +88,26 @@ impl LateLintPass<'_> for NeedlessQuestionMark { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - check(cx, body.value.peel_blocks()); + if let Some(GeneratorKind::Async(AsyncGeneratorKind::Fn)) = body.generator_kind { + if let ExprKind::Block( + Block { + expr: + Some(Expr { + kind: ExprKind::DropTemps(async_body), + .. + }), + .. + }, + _, + ) = body.value.kind + { + if let ExprKind::Block(Block { expr: Some(expr), .. }, ..) = async_body.kind { + check(cx, expr); + } + } + } else { + check(cx, body.value.peel_blocks()); + } } } diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs index 39a37e3e378..0d0c88b02c7 100644 --- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs +++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs @@ -3,7 +3,7 @@ use rustc_ast::ast::{ self, Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind, }; use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor}; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; @@ -356,7 +356,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> { impl EarlyLintPass for NonExpressiveNames { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if in_external_macro(cx.sess, item.span) { + if in_external_macro(cx.sess(), item.span) { return; } @@ -371,7 +371,7 @@ impl EarlyLintPass for NonExpressiveNames { } fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &AssocItem) { - if in_external_macro(cx.sess, item.span) { + if in_external_macro(cx.sess(), item.span) { return; } diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs index e0da12f77fc..c19cea66104 100644 --- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs +++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::ast::{Expr, ExprKind}; use rustc_ast::token::{Lit, LitKind}; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; @@ -51,7 +51,7 @@ declare_lint_pass!(OctalEscapes => [OCTAL_ESCAPES]); impl EarlyLintPass for OctalEscapes { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if in_external_macro(cx.sess, expr.span) { + if in_external_macro(cx.sess(), expr.span) { return; } @@ -101,7 +101,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { // construct a replacement escape // the maximum value is \077, or \x3f, so u8 is sufficient here if let Ok(n) = u8::from_str_radix(&contents[from + 1..to], 8) { - write!(&mut suggest_1, "\\x{:02x}", n).unwrap(); + write!(suggest_1, "\\x{:02x}", n).unwrap(); } // append the null byte as \x00 and the following digits literally diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 63de117a6f1..b5d65542de0 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -1,30 +1,36 @@ //! Checks for usage of `&Vec[_]` and `&String`. use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::ptr::get_spans; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::walk_ptrs_hir_ty; -use clippy_utils::{expr_path_res, is_lint_allowed, match_any_diagnostic_items, paths}; +use clippy_utils::ty::expr_sig; +use clippy_utils::{ + expr_path_res, get_expr_use_or_unification_node, is_lint_allowed, match_any_diagnostic_items, path_to_local, paths, +}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::def::Res; +use rustc_hir::def_id::DefId; +use rustc_hir::hir_id::HirIdMap; +use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{ - BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, Impl, ImplItem, ImplItemKind, Item, ItemKind, - Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, + self as hir, AnonConst, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, + ImplItemKind, ItemKind, Lifetime, LifetimeName, Mutability, Node, Param, ParamName, PatKind, QPath, TraitFn, + TraitItem, TraitItemKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::nested_filter; +use rustc_middle::ty::{self, AssocItems, AssocKind, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; use rustc_span::{sym, MultiSpan}; -use std::borrow::Cow; +use std::fmt; +use std::iter; declare_clippy_lint! { /// ### What it does - /// This lint checks for function arguments of type `&String` - /// or `&Vec` unless the references are mutable. It will also suggest you - /// replace `.clone()` calls with the appropriate `.to_owned()`/`to_string()` - /// calls. + /// This lint checks for function arguments of type `&String`, `&Vec`, + /// `&PathBuf`, and `Cow<_>`. It will also suggest you replace `.clone()` calls + /// with the appropriate `.to_owned()`/`to_string()` calls. /// /// ### Why is this bad? /// Requiring the argument to be of the specific size @@ -32,28 +38,7 @@ declare_clippy_lint! { /// or `&str` usually suffice and can be obtained from other types, too. /// /// ### Known problems - /// The lint does not follow data. So if you have an - /// argument `x` and write `let y = x; y.clone()` the lint will not suggest - /// changing that `.clone()` to `.to_owned()`. - /// - /// Other functions called from this function taking a `&String` or `&Vec` - /// argument may also fail to compile if you change the argument. Applying - /// this lint on them will fix the problem, but they may be in other crates. - /// - /// One notable example of a function that may cause issues, and which cannot - /// easily be changed due to being in the standard library is `Vec::contains`. - /// when called on a `Vec<Vec<T>>`. If a `&Vec` is passed to that method then - /// it will compile, but if a `&[T]` is passed then it will not compile. - /// - /// ```ignore - /// fn cannot_take_a_slice(v: &Vec<u8>) -> bool { - /// let vec_of_vecs: Vec<Vec<u8>> = some_other_fn(); - /// - /// vec_of_vecs.contains(v) - /// } - /// ``` - /// - /// Also there may be `fn(&Vec)`-typed references pointing to your function. + /// There may be `fn(&Vec)`-typed references pointing to your function. /// If you have them, you will get a compiler error after applying this lint's /// suggestions. You then have the choice to undo your changes or change the /// type of the reference. @@ -155,32 +140,86 @@ declare_clippy_lint! { declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF, INVALID_NULL_PTR_USAGE]); impl<'tcx> LateLintPass<'tcx> for Ptr { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if let ItemKind::Fn(ref sig, _, body_id) = item.kind { - check_fn(cx, sig.decl, Some(body_id)); - } - } + fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { + if let TraitItemKind::Fn(sig, trait_method) = &item.kind { + if matches!(trait_method, TraitFn::Provided(_)) { + // Handled by check body. + return; + } - fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { - if let ImplItemKind::Fn(ref sig, body_id) = item.kind { - let parent_item = cx.tcx.hir().get_parent_item(item.hir_id()); - if let Some(Node::Item(it)) = cx.tcx.hir().find_by_def_id(parent_item) { - if let ItemKind::Impl(Impl { of_trait: Some(_), .. }) = it.kind { - return; // ignore trait impls - } + check_mut_from_ref(cx, sig.decl); + for arg in check_fn_args( + cx, + cx.tcx.fn_sig(item.def_id).skip_binder().inputs(), + sig.decl.inputs, + &[], + ) { + span_lint_and_sugg( + cx, + PTR_ARG, + arg.span, + &arg.build_msg(), + "change this to", + format!("{}{}", arg.ref_prefix, arg.deref_ty.display(cx)), + Applicability::Unspecified, + ); } - check_fn(cx, sig.decl, Some(body_id)); } } - fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { - if let TraitItemKind::Fn(ref sig, ref trait_method) = item.kind { - let body_id = if let TraitFn::Provided(b) = *trait_method { - Some(b) - } else { - None - }; - check_fn(cx, sig.decl, body_id); + fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { + let hir = cx.tcx.hir(); + let mut parents = hir.parent_iter(body.value.hir_id); + let (item_id, decl) = match parents.next() { + Some((_, Node::Item(i))) => { + if let ItemKind::Fn(sig, ..) = &i.kind { + (i.def_id, sig.decl) + } else { + return; + } + }, + Some((_, Node::ImplItem(i))) => { + if !matches!(parents.next(), + Some((_, Node::Item(i))) if matches!(&i.kind, ItemKind::Impl(i) if i.of_trait.is_none()) + ) { + return; + } + if let ImplItemKind::Fn(sig, _) = &i.kind { + (i.def_id, sig.decl) + } else { + return; + } + }, + Some((_, Node::TraitItem(i))) => { + if let TraitItemKind::Fn(sig, _) = &i.kind { + (i.def_id, sig.decl) + } else { + return; + } + }, + _ => return, + }; + + check_mut_from_ref(cx, decl); + let sig = cx.tcx.fn_sig(item_id).skip_binder(); + let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, body.params).collect(); + let results = check_ptr_arg_usage(cx, body, &lint_args); + + for (result, args) in results.iter().zip(lint_args.iter()).filter(|(r, _)| !r.skip) { + span_lint_and_then(cx, PTR_ARG, args.span, &args.build_msg(), |diag| { + diag.multipart_suggestion( + "change this to", + iter::once((args.span, format!("{}{}", args.ref_prefix, args.deref_ty.display(cx)))) + .chain(result.replacements.iter().map(|r| { + ( + r.expr_span, + format!("{}{}", snippet_opt(cx, r.self_span).unwrap(), r.replacement), + ) + })) + .collect(), + Applicability::Unspecified, + ); + }); } } @@ -247,154 +286,206 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { } } -#[allow(clippy::too_many_lines)] -fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, opt_body_id: Option<BodyId>) { - let body = opt_body_id.map(|id| cx.tcx.hir().body(id)); - - for (idx, arg) in decl.inputs.iter().enumerate() { - // Honor the allow attribute on parameters. See issue 5644. - if let Some(body) = &body { - if is_lint_allowed(cx, PTR_ARG, body.params[idx].hir_id) { - continue; - } - } +#[derive(Default)] +struct PtrArgResult { + skip: bool, + replacements: Vec<PtrArgReplacement>, +} - let (item_name, path) = if_chain! { - if let TyKind::Rptr(_, MutTy { ty, mutbl: Mutability::Not }) = arg.kind; - if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind; - if let Res::Def(_, did) = path.res; - if let Some(item_name) = cx.tcx.get_diagnostic_name(did); - then { - (item_name, path) - } else { - continue - } - }; +struct PtrArgReplacement { + expr_span: Span, + self_span: Span, + replacement: &'static str, +} - match item_name { - sym::Vec => { - if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) { - span_lint_and_then( - cx, - PTR_ARG, - arg.span, - "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \ - with non-Vec-based slices", - |diag| { - if let Some(ref snippet) = get_only_generic_arg_snippet(cx, arg) { - diag.span_suggestion( - arg.span, - "change this to", - format!("&[{}]", snippet), - Applicability::Unspecified, - ); - } - for (clonespan, suggestion) in spans { - diag.span_suggestion( - clonespan, - &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| { - Cow::Owned(format!("change `{}` to", x)) - }), - suggestion.into(), - Applicability::Unspecified, - ); - } - }, - ); - } +struct PtrArg<'tcx> { + idx: usize, + span: Span, + ty_did: DefId, + ty_name: Symbol, + method_renames: &'static [(&'static str, &'static str)], + ref_prefix: RefPrefix, + deref_ty: DerefTy<'tcx>, + deref_assoc_items: Option<(DefId, &'tcx AssocItems<'tcx>)>, +} +impl PtrArg<'_> { + fn build_msg(&self) -> String { + format!( + "writing `&{}{}` instead of `&{}{}` involves a new object where a slice will do", + self.ref_prefix.mutability.prefix_str(), + self.ty_name, + self.ref_prefix.mutability.prefix_str(), + self.deref_ty.argless_str(), + ) + } +} + +struct RefPrefix { + lt: LifetimeName, + mutability: Mutability, +} +impl fmt::Display for RefPrefix { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use fmt::Write; + f.write_char('&')?; + match self.lt { + LifetimeName::Param(ParamName::Plain(name)) => { + name.fmt(f)?; + f.write_char(' ')?; }, - sym::String => { - if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) { - span_lint_and_then( - cx, - PTR_ARG, - arg.span, - "writing `&String` instead of `&str` involves a new object where a slice will do", - |diag| { - diag.span_suggestion(arg.span, "change this to", "&str".into(), Applicability::Unspecified); - for (clonespan, suggestion) in spans { - diag.span_suggestion_short( - clonespan, - &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| { - Cow::Owned(format!("change `{}` to", x)) - }), - suggestion.into(), - Applicability::Unspecified, - ); - } - }, - ); + LifetimeName::Underscore => f.write_str("'_ ")?, + LifetimeName::Static => f.write_str("'static ")?, + _ => (), + } + f.write_str(self.mutability.prefix_str()) + } +} + +struct DerefTyDisplay<'a, 'tcx>(&'a LateContext<'tcx>, &'a DerefTy<'tcx>); +impl fmt::Display for DerefTyDisplay<'_, '_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use std::fmt::Write; + match self.1 { + DerefTy::Str => f.write_str("str"), + DerefTy::Path => f.write_str("Path"), + DerefTy::Slice(hir_ty, ty) => { + f.write_char('[')?; + match hir_ty.and_then(|s| snippet_opt(self.0, s)) { + Some(s) => f.write_str(&s)?, + None => ty.fmt(f)?, } + f.write_char(']') }, - sym::PathBuf => { - if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_path_buf()"), ("as_path", "")]) { - span_lint_and_then( - cx, - PTR_ARG, - arg.span, - "writing `&PathBuf` instead of `&Path` involves a new object where a slice will do", - |diag| { - diag.span_suggestion( - arg.span, + } + } +} + +enum DerefTy<'tcx> { + Str, + Path, + Slice(Option<Span>, Ty<'tcx>), +} +impl<'tcx> DerefTy<'tcx> { + fn argless_str(&self) -> &'static str { + match *self { + Self::Str => "str", + Self::Path => "Path", + Self::Slice(..) => "[_]", + } + } + + fn display<'a>(&'a self, cx: &'a LateContext<'tcx>) -> DerefTyDisplay<'a, 'tcx> { + DerefTyDisplay(cx, self) + } +} + +fn check_fn_args<'cx, 'tcx: 'cx>( + cx: &'cx LateContext<'tcx>, + tys: &'tcx [Ty<'_>], + hir_tys: &'tcx [hir::Ty<'_>], + params: &'tcx [Param<'_>], +) -> impl Iterator<Item = PtrArg<'tcx>> + 'cx { + tys.iter() + .zip(hir_tys.iter()) + .enumerate() + .filter_map(|(i, (ty, hir_ty))| { + if_chain! { + if let ty::Ref(_, ty, mutability) = *ty.kind(); + if let ty::Adt(adt, substs) = *ty.kind(); + + if let TyKind::Rptr(lt, ref ty) = hir_ty.kind; + if let TyKind::Path(QPath::Resolved(None, path)) = ty.ty.kind; + + // Check that the name as typed matches the actual name of the type. + // e.g. `fn foo(_: &Foo)` shouldn't trigger the lint when `Foo` is an alias for `Vec` + if let [.., name] = path.segments; + if cx.tcx.item_name(adt.did) == name.ident.name; + + if !is_lint_allowed(cx, PTR_ARG, hir_ty.hir_id); + if params.get(i).map_or(true, |p| !is_lint_allowed(cx, PTR_ARG, p.hir_id)); + + then { + let (method_renames, deref_ty, deref_impl_id) = match cx.tcx.get_diagnostic_name(adt.did) { + Some(sym::Vec) => ( + [("clone", ".to_owned()")].as_slice(), + DerefTy::Slice( + name.args + .and_then(|args| args.args.first()) + .and_then(|arg| if let GenericArg::Type(ty) = arg { + Some(ty.span) + } else { + None + }), + substs.type_at(0), + ), + cx.tcx.lang_items().slice_impl() + ), + Some(sym::String) => ( + [("clone", ".to_owned()"), ("as_str", "")].as_slice(), + DerefTy::Str, + cx.tcx.lang_items().str_impl() + ), + Some(sym::PathBuf) => ( + [("clone", ".to_path_buf()"), ("as_path", "")].as_slice(), + DerefTy::Path, + None, + ), + Some(sym::Cow) => { + let ty_name = name.args + .and_then(|args| { + args.args.iter().find_map(|a| match a { + GenericArg::Type(x) => Some(x), + _ => None, + }) + }) + .and_then(|arg| snippet_opt(cx, arg.span)) + .unwrap_or_else(|| substs.type_at(1).to_string()); + span_lint_and_sugg( + cx, + PTR_ARG, + hir_ty.span, + "using a reference to `Cow` is not recommended", "change this to", - "&Path".into(), + format!("&{}{}", mutability.prefix_str(), ty_name), Applicability::Unspecified, ); - for (clonespan, suggestion) in spans { - diag.span_suggestion_short( - clonespan, - &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| { - Cow::Owned(format!("change `{}` to", x)) - }), - suggestion.into(), - Applicability::Unspecified, - ); - } + return None; }, - ); - } - }, - sym::Cow => { - if_chain! { - if let [ref bx] = *path.segments; - if let Some(params) = bx.args; - if !params.parenthesized; - if let Some(inner) = params.args.iter().find_map(|arg| match arg { - GenericArg::Type(ty) => Some(ty), - _ => None, + _ => return None, + }; + return Some(PtrArg { + idx: i, + span: hir_ty.span, + ty_did: adt.did, + ty_name: name.ident.name, + method_renames, + ref_prefix: RefPrefix { + lt: lt.name, + mutability, + }, + deref_ty, + deref_assoc_items: deref_impl_id.map(|id| (id, cx.tcx.associated_items(id))), }); - let replacement = snippet_opt(cx, inner.span); - if let Some(r) = replacement; - then { - span_lint_and_sugg( - cx, - PTR_ARG, - arg.span, - "using a reference to `Cow` is not recommended", - "change this to", - "&".to_owned() + &r, - Applicability::Unspecified, - ); - } } - }, - _ => {}, - } - } + } + None + }) +} +fn check_mut_from_ref(cx: &LateContext<'_>, decl: &FnDecl<'_>) { if let FnRetTy::Return(ty) = decl.output { if let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty) { let mut immutables = vec![]; - for (_, ref mutbl, ref argspan) in decl + for (_, mutbl, argspan) in decl .inputs .iter() .filter_map(get_rptr_lm) .filter(|&(lt, _, _)| lt.name == out.name) { - if *mutbl == Mutability::Mut { + if mutbl == Mutability::Mut { return; } - immutables.push(*argspan); + immutables.push(argspan); } if immutables.is_empty() { return; @@ -413,24 +504,158 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, opt_body_id: Option<BodyId> } } -fn get_only_generic_arg_snippet(cx: &LateContext<'_>, arg: &Ty<'_>) -> Option<String> { - if_chain! { - if let TyKind::Path(QPath::Resolved(_, path)) = walk_ptrs_hir_ty(arg).kind; - if let Some(&PathSegment{args: Some(parameters), ..}) = path.segments.last(); - let types: Vec<_> = parameters.args.iter().filter_map(|arg| match arg { - GenericArg::Type(ty) => Some(ty), - _ => None, - }).collect(); - if types.len() == 1; - then { - snippet_opt(cx, types[0].span) - } else { - None +#[allow(clippy::too_many_lines)] +fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: &[PtrArg<'tcx>]) -> Vec<PtrArgResult> { + struct V<'cx, 'tcx> { + cx: &'cx LateContext<'tcx>, + /// Map from a local id to which argument it came from (index into `Self::args` and + /// `Self::results`) + bindings: HirIdMap<usize>, + /// The arguments being checked. + args: &'cx [PtrArg<'tcx>], + /// The results for each argument (len should match args.len) + results: Vec<PtrArgResult>, + /// The number of arguments which can't be linted. Used to return early. + skip_count: usize, + } + impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> { + type NestedFilter = nested_filter::OnlyBodies; + fn nested_visit_map(&mut self) -> Self::Map { + self.cx.tcx.hir() + } + + fn visit_anon_const(&mut self, _: &'tcx AnonConst) {} + + fn visit_expr(&mut self, e: &'tcx Expr<'_>) { + if self.skip_count == self.args.len() { + return; + } + + // Check if this is local we care about + let args_idx = match path_to_local(e).and_then(|id| self.bindings.get(&id)) { + Some(&i) => i, + None => return walk_expr(self, e), + }; + let args = &self.args[args_idx]; + let result = &mut self.results[args_idx]; + + // Helper function to handle early returns. + let mut set_skip_flag = || { + if result.skip { + self.skip_count += 1; + } + result.skip = true; + }; + + match get_expr_use_or_unification_node(self.cx.tcx, e) { + Some((Node::Stmt(_), _)) => (), + Some((Node::Local(l), _)) => { + // Only trace simple bindings. e.g `let x = y;` + if let PatKind::Binding(BindingAnnotation::Unannotated, id, _, None) = l.pat.kind { + self.bindings.insert(id, args_idx); + } else { + set_skip_flag(); + } + }, + Some((Node::Expr(e), child_id)) => match e.kind { + ExprKind::Call(f, expr_args) => { + let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0); + if expr_sig(self.cx, f) + .map(|sig| sig.input(i).skip_binder().peel_refs()) + .map_or(true, |ty| match *ty.kind() { + ty::Param(_) => true, + ty::Adt(def, _) => def.did == args.ty_did, + _ => false, + }) + { + // Passed to a function taking the non-dereferenced type. + set_skip_flag(); + } + }, + ExprKind::MethodCall(name, expr_args @ [self_arg, ..], _) => { + let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0); + if i == 0 { + // Check if the method can be renamed. + let name = name.ident.as_str(); + if let Some((_, replacement)) = args.method_renames.iter().find(|&&(x, _)| x == name) { + result.replacements.push(PtrArgReplacement { + expr_span: e.span, + self_span: self_arg.span, + replacement, + }); + return; + } + } + + let id = if let Some(x) = self.cx.typeck_results().type_dependent_def_id(e.hir_id) { + x + } else { + set_skip_flag(); + return; + }; + + match *self.cx.tcx.fn_sig(id).skip_binder().inputs()[i].peel_refs().kind() { + ty::Param(_) => { + set_skip_flag(); + }, + // If the types match check for methods which exist on both types. e.g. `Vec::len` and + // `slice::len` + ty::Adt(def, _) + if def.did == args.ty_did + && (i != 0 + || self.cx.tcx.trait_of_item(id).is_some() + || !args.deref_assoc_items.map_or(false, |(id, items)| { + items + .find_by_name_and_kind(self.cx.tcx, name.ident, AssocKind::Fn, id) + .is_some() + })) => + { + set_skip_flag(); + }, + _ => (), + } + }, + // Indexing is fine for currently supported types. + ExprKind::Index(e, _) if e.hir_id == child_id => (), + _ => set_skip_flag(), + }, + _ => set_skip_flag(), + } } } + + let mut skip_count = 0; + let mut results = args.iter().map(|_| PtrArgResult::default()).collect::<Vec<_>>(); + let mut v = V { + cx, + bindings: args + .iter() + .enumerate() + .filter_map(|(i, arg)| { + let param = &body.params[arg.idx]; + match param.pat.kind { + PatKind::Binding(BindingAnnotation::Unannotated, id, _, None) + if !is_lint_allowed(cx, PTR_ARG, param.hir_id) => + { + Some((id, i)) + }, + _ => { + skip_count += 1; + results[arg.idx].skip = true; + None + }, + } + }) + .collect(), + args, + results, + skip_count, + }; + v.visit_expr(&body.value); + v.results } -fn get_rptr_lm<'tcx>(ty: &'tcx Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> { +fn get_rptr_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> { if let TyKind::Rptr(ref lt, ref m) = ty.kind { Some((lt, m.mutbl, ty.span)) } else { diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index 52d47e6d978..027ab70014f 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -8,7 +8,7 @@ use if_chain::if_chain; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, QPath}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index 0c77cf5e77d..5a25008e95e 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit as hir_visit; use rustc_hir::intravisit::Visitor as HirVisitor; -use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -62,7 +62,7 @@ impl<'ast> ast_visit::Visitor<'ast> for ReturnVisitor { impl EarlyLintPass for RedundantClosureCall { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { - if in_external_macro(cx.sess, expr.span) { + if in_external_macro(cx.sess(), expr.span) { return; } if_chain! { diff --git a/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs index 93dbe936d58..73088ce1a87 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_else.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_else.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_ast::visit::{walk_expr, Visitor}; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -46,7 +46,7 @@ declare_lint_pass!(RedundantElse => [REDUNDANT_ELSE]); impl EarlyLintPass for RedundantElse { fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &Stmt) { - if in_external_macro(cx.sess, stmt.span) { + if in_external_macro(cx.sess(), stmt.span) { return; } // Only look at expressions that are a whole statement diff --git a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs index 0dea4a784b2..40a62fd6d20 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{meets_msrv, msrvs}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -55,7 +55,7 @@ impl EarlyLintPass for RedundantFieldNames { return; } - if in_external_macro(cx.sess, expr.span) { + if in_external_macro(cx.sess(), expr.span) { return; } if let ExprKind::Struct(ref se) = expr.kind { diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs index b2448372370..811a7bb9c15 100644 --- a/src/tools/clippy/clippy_lints/src/reference.rs +++ b/src/tools/clippy/clippy_lints/src/reference.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet_opt, snippet_with_applicability}; -use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; use rustc_errors::Applicability; @@ -104,59 +103,3 @@ impl EarlyLintPass for DerefAddrOf { } } } - -declare_clippy_lint! { - /// ### What it does - /// Checks for references in expressions that use - /// auto dereference. - /// - /// ### Why is this bad? - /// The reference is a no-op and is automatically - /// dereferenced by the compiler and makes the code less clear. - /// - /// ### Example - /// ```rust - /// struct Point(u32, u32); - /// let point = Point(30, 20); - /// let x = (&point).0; - /// ``` - /// Use instead: - /// ```rust - /// # struct Point(u32, u32); - /// # let point = Point(30, 20); - /// let x = point.0; - /// ``` - #[clippy::version = "pre 1.29.0"] - pub REF_IN_DEREF, - complexity, - "Use of reference in auto dereference expression." -} - -declare_lint_pass!(RefInDeref => [REF_IN_DEREF]); - -impl EarlyLintPass for RefInDeref { - fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { - if_chain! { - if let ExprKind::Field(ref object, _) = e.kind; - if let ExprKind::Paren(ref parened) = object.kind; - if let ExprKind::AddrOf(_, _, ref inner) = parened.kind; - then { - let applicability = if inner.span.from_expansion() { - Applicability::MaybeIncorrect - } else { - Applicability::MachineApplicable - }; - let sugg = Sugg::ast(cx, inner, "_").maybe_par(); - span_lint_and_sugg( - cx, - REF_IN_DEREF, - object.span, - "creating a reference that is immediately dereferenced", - "try this", - sugg.to_string(), - applicability, - ); - } - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs index 1bbaa104e60..22b45896955 100644 --- a/src/tools/clippy/clippy_lints/src/same_name_method.rs +++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs @@ -87,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { .filter(|assoc_item| { matches!(assoc_item.kind, AssocKind::Fn) }) - .map(|assoc_item| assoc_item.ident.name) + .map(|assoc_item| assoc_item.name) .collect() }else{ BTreeSet::new() diff --git a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs index ee82666b5af..aa306a630c4 100644 --- a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs +++ b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{GenericParam, GenericParamKind}; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -43,7 +43,7 @@ declare_lint_pass!(SingleCharLifetimeNames => [SINGLE_CHAR_LIFETIME_NAMES]); impl EarlyLintPass for SingleCharLifetimeNames { fn check_generic_param(&mut self, ctx: &EarlyContext<'_>, param: &GenericParam) { - if in_external_macro(ctx.sess, param.ident.span) { + if in_external_macro(ctx.sess(), param.ident.span) { return; } diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs index 28d32203da9..961cdb317e7 100644 --- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs +++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use rustc_ast::{ptr::P, Crate, Item, ItemKind, MacroDef, ModKind, UseTreeKind, VisibilityKind}; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{edition::Edition, symbol::kw, Span, Symbol}; @@ -37,7 +37,7 @@ declare_lint_pass!(SingleComponentPathImports => [SINGLE_COMPONENT_PATH_IMPORTS] impl EarlyLintPass for SingleComponentPathImports { fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) { - if cx.sess.opts.edition < Edition::Edition2018 { + if cx.sess().opts.edition < Edition::Edition2018 { return; } check_mod(cx, &krate.items); diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 6369aafe3f9..5257f5302cd 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -3,7 +3,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::{SpanlessEq, SpanlessHash}; use core::hash::{Hash, Hasher}; use if_chain::if_chain; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unhash::UnhashMap; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -91,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) { let Generics { where_clause, .. } = &item.generics; - let mut self_bounds_set = FxHashSet::default(); + let mut self_bounds_map = FxHashMap::default(); for predicate in where_clause.predicates { if_chain! { @@ -108,27 +108,29 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { ) ) = cx.tcx.hir().get_if_local(*def_id); then { - if self_bounds_set.is_empty() { + if self_bounds_map.is_empty() { for bound in self_bounds.iter() { - let Some((self_res, _)) = get_trait_res_span_from_bound(bound) else { continue }; - self_bounds_set.insert(self_res); + let Some((self_res, self_segments, _)) = get_trait_info_from_bound(bound) else { continue }; + self_bounds_map.insert(self_res, self_segments); } } bound_predicate .bounds .iter() - .filter_map(get_trait_res_span_from_bound) - .for_each(|(trait_item_res, span)| { - if self_bounds_set.get(&trait_item_res).is_some() { - span_lint_and_help( - cx, - TRAIT_DUPLICATION_IN_BOUNDS, - span, - "this trait bound is already specified in trait declaration", - None, - "consider removing this trait bound", - ); + .filter_map(get_trait_info_from_bound) + .for_each(|(trait_item_res, trait_item_segments, span)| { + if let Some(self_segments) = self_bounds_map.get(&trait_item_res) { + if SpanlessEq::new(cx).eq_path_segments(self_segments, trait_item_segments) { + span_lint_and_help( + cx, + TRAIT_DUPLICATION_IN_BOUNDS, + span, + "this trait bound is already specified in trait declaration", + None, + "consider removing this trait bound", + ); + } } }); } @@ -137,14 +139,6 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { } } -fn get_trait_res_span_from_bound(bound: &GenericBound<'_>) -> Option<(Res, Span)> { - if let GenericBound::Trait(t, _) = bound { - Some((t.trait_ref.path.res, t.span)) - } else { - None - } -} - impl TraitBounds { fn check_type_repetition<'tcx>(self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) { struct SpanlessTy<'cx, 'tcx> { @@ -231,7 +225,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { let res = param .bounds .iter() - .filter_map(get_trait_res_span_from_bound) + .filter_map(get_trait_info_from_bound) .collect::<Vec<_>>(); map.insert(*ident, res); } @@ -245,10 +239,10 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { if let Some(segment) = segments.first(); if let Some(trait_resolutions_direct) = map.get(&segment.ident); then { - for (res_where, _) in bound_predicate.bounds.iter().filter_map(get_trait_res_span_from_bound) { - if let Some((_, span_direct)) = trait_resolutions_direct + for (res_where, _, _) in bound_predicate.bounds.iter().filter_map(get_trait_info_from_bound) { + if let Some((_, _, span_direct)) = trait_resolutions_direct .iter() - .find(|(res_direct, _)| *res_direct == res_where) { + .find(|(res_direct, _, _)| *res_direct == res_where) { span_lint_and_help( cx, TRAIT_DUPLICATION_IN_BOUNDS, @@ -263,3 +257,11 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { } } } + +fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'a [PathSegment<'a>], Span)> { + if let GenericBound::Trait(t, _) = bound { + Some((t.trait_ref.path.res, t.trait_ref.path.segments, t.span)) + } else { + None + } +} diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs index 141f2604872..eee1229e1ef 100644 --- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs +++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs @@ -98,10 +98,11 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve if trait_pred.self_ty() == inp; if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred); then { - if ord_preds.iter().any(|ord| Some(ord.self_ty()) == - return_ty_pred.term.ty()) { + if ord_preds.iter().any(|ord| Some(ord.self_ty()) == return_ty_pred.term.ty()) { args_to_check.push((i, "Ord".to_string())); - } else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.term.ty().unwrap()) { + } else if partial_ord_preds.iter().any(|pord| { + pord.self_ty() == return_ty_pred.term.ty().unwrap() + }) { args_to_check.push((i, "PartialOrd".to_string())); } } diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 0bd151fed91..1d4fe9cfd3c 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -291,7 +291,7 @@ fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize) fn extend_with_struct_pat( qself1: &Option<ast::QSelf>, path1: &ast::Path, - fps1: &mut Vec<ast::PatField>, + fps1: &mut [ast::PatField], rest1: bool, start: usize, alternatives: &mut Vec<P<Pat>>, @@ -332,7 +332,7 @@ fn extend_with_struct_pat( /// while also requiring `ps1[..n] ~ ps2[..n]` (pre) and `ps1[n + 1..] ~ ps2[n + 1..]` (post), /// where `~` denotes semantic equality. fn extend_with_matching_product( - targets: &mut Vec<P<Pat>>, + targets: &mut [P<Pat>], start: usize, alternatives: &mut Vec<P<Pat>>, predicate: impl Fn(&PatKind, &[P<Pat>], usize) -> bool, diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index 6c5a5fe1434..be20282b3b8 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -11,7 +11,7 @@ use rustc_hir::{ intravisit::{walk_inf, walk_ty, Visitor}, Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Path, QPath, TyKind, }; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs index d6deb50cc90..c9d99617c1e 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs @@ -156,7 +156,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS. /// /// The minimum rust version that the project supports (msrv: Option<String> = None), diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs index ec1b5a499d4..f170ff69154 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs @@ -23,6 +23,7 @@ use rustc_hir::{ UnOp, }; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; +use rustc_middle::hir::nested_filter; use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty; use rustc_semver::RustcVersion; diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 5ee3146eaab..3547f0b4e0a 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -19,7 +19,9 @@ use rustc_hir::{ self as hir, def::DefKind, intravisit, intravisit::Visitor, ExprKind, Item, ItemKind, Mutability, QPath, }; use rustc_lint::{CheckLintNameResult, LateContext, LateLintPass, LintContext, LintId}; +use rustc_middle::hir::nested_filter; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::symbol::Ident; use rustc_span::{sym, Loc, Span, Symbol}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::collections::BinaryHeap; @@ -578,9 +580,11 @@ fn get_lint_group_and_level_or_lint( lint_name: &str, item: &Item<'_>, ) -> Option<(String, &'static str)> { - let result = cx - .lint_store - .check_lint_name(cx.sess(), lint_name, Some(sym::clippy), &[]); + let result = cx.lint_store.check_lint_name( + lint_name, + Some(sym::clippy), + &[Ident::with_dummy_span(sym::clippy)].into_iter().collect(), + ); if let CheckLintNameResult::Tool(Ok(lint_lst)) = result { if let Some(group) = get_lint_group(cx, lint_lst[0]) { if EXCLUDED_LINT_GROUPS.contains(&group.as_str()) { diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index f9add927b49..b0044695ea8 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -9,7 +9,7 @@ use rustc_ast::token::{self, LitKind}; use rustc_ast::tokenstream::TokenStream; use rustc_errors::Applicability; use rustc_lexer::unescape::{self, EscapeError}; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_parse::parser; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::{kw, Symbol}; @@ -290,7 +290,7 @@ impl EarlyLintPass for Write { fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) { fn is_build_script(cx: &EarlyContext<'_>) -> bool { // Cargo sets the crate name for build scripts to `build_script_build` - cx.sess + cx.sess() .opts .crate_name .as_ref() @@ -529,7 +529,7 @@ impl Write { /// ``` #[allow(clippy::too_many_lines)] fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool) -> (Option<StrLit>, Option<Expr>) { - let mut parser = parser::Parser::new(&cx.sess.parse_sess, tts, false, None); + let mut parser = parser::Parser::new(&cx.sess().parse_sess, tts, false, None); let expr = if is_write { match parser .parse_expr() diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 604c95d2bc8..3f4043ad052 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -646,11 +646,11 @@ pub fn eq_generic_bound(l: &GenericBound, r: &GenericBound) -> bool { } fn eq_term(l: &Term, r: &Term) -> bool { - match (l, r) { - (Term::Ty(l), Term::Ty(r)) => eq_ty(l,r), - (Term::Const(l), Term::Const(r)) => eq_anon_const(l,r), - _ => false, - } + match (l, r) { + (Term::Ty(l), Term::Ty(r)) => eq_ty(l, r), + (Term::Const(l), Term::Const(r)) => eq_anon_const(l, r), + _ => false, + } } pub fn eq_assoc_constraint(l: &AssocConstraint, r: &AssocConstraint) -> bool { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 8386aaeaf44..a2f1f469651 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -117,25 +117,15 @@ pub fn meets_msrv(msrv: Option<&RustcVersion>, lint_msrv: &RustcVersion) -> bool #[macro_export] macro_rules! extract_msrv_attr { - (LateContext) => { - extract_msrv_attr!(@LateContext, ()); - }; - (EarlyContext) => { - extract_msrv_attr!(@EarlyContext); - }; - (@$context:ident$(, $call:tt)?) => { + ($context:ident) => { fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) { - use $crate::get_unique_inner_attr; - match get_unique_inner_attr(cx.sess$($call)?, attrs, "msrv") { + let sess = rustc_lint::LintContext::sess(cx); + match $crate::get_unique_inner_attr(sess, attrs, "msrv") { Some(msrv_attr) => { if let Some(msrv) = msrv_attr.value_str() { - self.msrv = $crate::parse_msrv( - &msrv.to_string(), - Some(cx.sess$($call)?), - Some(msrv_attr.span), - ); + self.msrv = $crate::parse_msrv(&msrv.to_string(), Some(sess), Some(msrv_attr.span)); } else { - cx.sess$($call)?.span_err(msrv_attr.span, "bad clippy attribute"); + sess.span_err(msrv_attr.span, "bad clippy attribute"); } }, _ => (), @@ -1837,7 +1827,8 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool } /// Gets the node where an expression is either used, or it's type is unified with another branch. -pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<Node<'tcx>> { +/// Returns both the node and the `HirId` of the closest child node. +pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<(Node<'tcx>, HirId)> { let mut child_id = expr.hir_id; let mut iter = tcx.hir().parent_iter(child_id); loop { @@ -1849,9 +1840,9 @@ pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_> ExprKind::Match(_, [arm], _) if arm.hir_id == child_id => child_id = expr.hir_id, ExprKind::Block(..) | ExprKind::DropTemps(_) => child_id = expr.hir_id, ExprKind::If(_, then_expr, None) if then_expr.hir_id == child_id => break None, - _ => break Some(Node::Expr(expr)), + _ => break Some((Node::Expr(expr), child_id)), }, - Some((_, node)) => break Some(node), + Some((_, node)) => break Some((node, child_id)), } } } @@ -1860,18 +1851,21 @@ pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_> pub fn is_expr_used_or_unified(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { !matches!( get_expr_use_or_unification_node(tcx, expr), - None | Some(Node::Stmt(Stmt { - kind: StmtKind::Expr(_) - | StmtKind::Semi(_) - | StmtKind::Local(Local { - pat: Pat { - kind: PatKind::Wild, + None | Some(( + Node::Stmt(Stmt { + kind: StmtKind::Expr(_) + | StmtKind::Semi(_) + | StmtKind::Local(Local { + pat: Pat { + kind: PatKind::Wild, + .. + }, .. - }, - .. - }), - .. - })) + }), + .. + }), + _ + )) ) } diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index b7a242cf90a..a75f6b86a9b 100644 --- a/src/tools/clippy/clippy_utils/src/macros.rs +++ b/src/tools/clippy/clippy_utils/src/macros.rs @@ -339,15 +339,13 @@ impl<'tcx> FormatArgsExpn<'tcx> { expr_visitor_no_bodies(|e| { // if we're still inside of the macro definition... if e.span.ctxt() == expr.span.ctxt() { - // ArgumnetV1::new(<value>, <format_trait>::fmt) + // ArgumnetV1::new_<format_trait>(<value>) if_chain! { - if let ExprKind::Call(callee, [val, fmt_path]) = e.kind; + if let ExprKind::Call(callee, [val]) = e.kind; if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind; - if seg.ident.name == sym::new; if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind; if path.segments.last().unwrap().ident.name == sym::ArgumentV1; - if let ExprKind::Path(QPath::Resolved(_, path)) = fmt_path.kind; - if let [.., fmt_trait, _fmt] = path.segments; + if seg.ident.name.as_str().starts_with("new_"); then { let val_idx = if_chain! { if val.span.ctxt() == expr.span.ctxt(); @@ -361,7 +359,19 @@ impl<'tcx> FormatArgsExpn<'tcx> { formatters.len() } }; - formatters.push((val_idx, fmt_trait.ident.name)); + let fmt_trait = match seg.ident.name.as_str() { + "new_display" => "Display", + "new_debug" => "Debug", + "new_lower_exp" => "LowerExp", + "new_upper_exp" => "UpperExp", + "new_octal" => "Octal", + "new_pointer" => "Pointer", + "new_binary" => "Binary", + "new_lower_hex" => "LowerHex", + "new_upper_hex" => "UpperHex", + _ => unreachable!(), + }; + formatters.push((val_idx, Symbol::intern(fmt_trait))); } } if let ExprKind::Struct(QPath::Resolved(_, path), ..) = e.kind { diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs index 68dd1b29845..908ff822712 100644 --- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs +++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs @@ -51,7 +51,14 @@ impl<'a> NumericLiteral<'a> { } pub fn from_lit_kind(src: &'a str, lit_kind: &LitKind) -> Option<NumericLiteral<'a>> { - if lit_kind.is_numeric() && src.chars().next().map_or(false, |c| c.is_digit(10)) { + let unsigned_src = src.strip_prefix('-').map_or(src, |s| s); + if lit_kind.is_numeric() + && unsigned_src + .trim_start() + .chars() + .next() + .map_or(false, |c| c.is_digit(10)) + { let (unsuffixed, suffix) = split_suffix(src, lit_kind); let float = matches!(lit_kind, LitKind::Float(..)); Some(NumericLiteral::new(unsuffixed, suffix, float)) diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 48525f9a572..fa63ddff253 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -386,7 +386,7 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String { } /// Return `true` if `sugg` is enclosed in parenthesis. -fn has_enclosing_paren(sugg: impl AsRef<str>) -> bool { +pub fn has_enclosing_paren(sugg: impl AsRef<str>) -> bool { let mut chars = sugg.as_ref().chars(); if chars.next() == Some('(') { let mut depth = 1; diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index f109b7845b4..d057da73302 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -5,19 +5,22 @@ use rustc_ast::ast::Mutability; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; +use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::{TyKind, Unsafety}; +use rustc_hir::{Expr, TyKind, Unsafety}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; -use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, AdtDef, IntTy, Predicate, Ty, TyCtxt, TypeFoldable, UintTy}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; +use rustc_middle::ty::{ + self, AdtDef, Binder, FnSig, IntTy, Predicate, PredicateKind, Ty, TyCtxt, TypeFoldable, UintTy, +}; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::query::normalize::AtExt; use std::iter; -use crate::{match_def_path, must_use_attr}; +use crate::{expr_path_res, match_def_path, must_use_attr}; // Checks if the given type implements copy. pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { @@ -410,3 +413,105 @@ pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator<Item = &(P }) .flatten() } + +/// A signature for a function like type. +#[derive(Clone, Copy)] +pub enum ExprFnSig<'tcx> { + Sig(Binder<'tcx, FnSig<'tcx>>), + Closure(Binder<'tcx, FnSig<'tcx>>), + Trait(Binder<'tcx, Ty<'tcx>>, Option<Binder<'tcx, Ty<'tcx>>>), +} +impl<'tcx> ExprFnSig<'tcx> { + /// Gets the argument type at the given offset. + pub fn input(self, i: usize) -> Binder<'tcx, Ty<'tcx>> { + match self { + Self::Sig(sig) => sig.input(i), + Self::Closure(sig) => sig.input(0).map_bound(|ty| ty.tuple_element_ty(i).unwrap()), + Self::Trait(inputs, _) => inputs.map_bound(|ty| ty.tuple_element_ty(i).unwrap()), + } + } + + /// Gets the result type, if one could be found. Note that the result type of a trait may not be + /// specified. + pub fn output(self) -> Option<Binder<'tcx, Ty<'tcx>>> { + match self { + Self::Sig(sig) | Self::Closure(sig) => Some(sig.output()), + Self::Trait(_, output) => output, + } + } +} + +/// If the expression is function like, get the signature for it. +pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnSig<'tcx>> { + if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = expr_path_res(cx, expr) { + Some(ExprFnSig::Sig(cx.tcx.fn_sig(id))) + } else { + let ty = cx.typeck_results().expr_ty_adjusted(expr).peel_refs(); + match *ty.kind() { + ty::Closure(_, subs) => Some(ExprFnSig::Closure(subs.as_closure().sig())), + ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).subst(cx.tcx, subs))), + ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig)), + ty::Dynamic(bounds, _) => { + let lang_items = cx.tcx.lang_items(); + match bounds.principal() { + Some(bound) + if Some(bound.def_id()) == lang_items.fn_trait() + || Some(bound.def_id()) == lang_items.fn_once_trait() + || Some(bound.def_id()) == lang_items.fn_mut_trait() => + { + let output = bounds + .projection_bounds() + .find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id())) + .map(|p| p.map_bound(|p| p.term.ty().expect("return type was a const"))); + Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output)) + }, + _ => None, + } + }, + ty::Param(_) | ty::Projection(..) => { + let mut inputs = None; + let mut output = None; + let lang_items = cx.tcx.lang_items(); + + for (pred, _) in all_predicates_of(cx.tcx, cx.typeck_results().hir_owner.to_def_id()) { + let mut is_input = false; + if let Some(ty) = pred + .kind() + .map_bound(|pred| match pred { + PredicateKind::Trait(p) + if (lang_items.fn_trait() == Some(p.def_id()) + || lang_items.fn_mut_trait() == Some(p.def_id()) + || lang_items.fn_once_trait() == Some(p.def_id())) + && p.self_ty() == ty => + { + is_input = true; + Some(p.trait_ref.substs.type_at(1)) + }, + PredicateKind::Projection(p) + if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() + && p.projection_ty.self_ty() == ty => + { + is_input = false; + p.term.ty() + }, + _ => None, + }) + .transpose() + { + if is_input && inputs.is_none() { + inputs = Some(ty); + } else if !is_input && output.is_none() { + output = Some(ty); + } else { + // Multiple different fn trait impls. Is this even allowed? + return None; + } + } + } + + inputs.map(|ty| ExprFnSig::Trait(ty, output)) + }, + _ => None, + } + } +} diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index e6a58e92072..e23dc73ab08 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-01-13" +channel = "nightly-2022-01-27" components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index a8aa3a76abc..8f8f1140a3d 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -331,11 +331,10 @@ pub fn main() { // - IF Clippy is run on the main crate, not on deps (`!cap_lints_allow`) THEN // - IF `--no-deps` is not set (`!no_deps`) OR // - IF `--no-deps` is set and Clippy is run on the specified primary package - let clippy_tests_set = env::var("__CLIPPY_INTERNAL_TESTS").map_or(false, |val| val == "true"); let cap_lints_allow = arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_some(); let in_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok(); - let clippy_enabled = clippy_tests_set || (!cap_lints_allow && (!no_deps || in_primary_package)); + let clippy_enabled = !cap_lints_allow && (!no_deps || in_primary_package); if clippy_enabled { args.extend(clippy_args); } diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 531890c863f..6505028db9f 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -328,15 +328,9 @@ fn run_ui_cargo(config: &mut compiletest::Config) { } } -fn prepare_env() { - set_var("CLIPPY_DISABLE_DOCS_LINKS", "true"); - set_var("__CLIPPY_INTERNAL_TESTS", "true"); - //set_var("RUST_BACKTRACE", "0"); -} - #[test] fn compile_test() { - prepare_env(); + set_var("CLIPPY_DISABLE_DOCS_LINKS", "true"); let mut config = default_config(); run_ui(&mut config); run_ui_test(&mut config); diff --git a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs index 8e104926524..1e3ec123a3c 100644 --- a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs +++ b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs @@ -1,6 +1,7 @@ -#![allow(clippy::redundant_clone)] -#![warn(clippy::manual_non_exhaustive)] +#![allow(clippy::redundant_clone, clippy::unnecessary_operation)] +#![warn(clippy::manual_non_exhaustive, clippy::borrow_as_ptr, clippy::manual_bits)] +use std::mem::{size_of, size_of_val}; use std::ops::Deref; mod enums { @@ -68,6 +69,24 @@ fn check_index_refutable_slice() { } } +fn map_clone_suggest_copied() { + // This should still trigger the lint but suggest `cloned()` instead of `copied()` + let _: Option<u64> = Some(&16).map(|b| *b); +} + +fn borrow_as_ptr() { + let val = 1; + let _p = &val as *const i32; + + let mut val_mut = 1; + let _p_mut = &mut val_mut as *mut i32; +} + +fn manual_bits() { + size_of::<i8>() * 8; + size_of_val(&0u32) * 8; +} + fn main() { option_as_ref_deref(); match_like_matches(); @@ -75,4 +94,5 @@ fn main() { match_same_arms2(); manual_strip_msrv(); check_index_refutable_slice(); + borrow_as_ptr(); } diff --git a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.stderr b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.stderr new file mode 100644 index 00000000000..a1e7361c0cb --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.stderr @@ -0,0 +1,10 @@ +error: you are using an explicit closure for copying elements + --> $DIR/min_rust_version.rs:74:26 + | +LL | let _: Option<u64> = Some(&16).map(|b| *b); + | ^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `Some(&16).cloned()` + | + = note: `-D clippy::map-clone` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs index 4327f12c37c..eefeb1decb6 100644 --- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs @@ -1,9 +1,5 @@ #![warn(clippy::borrow_interior_mutable_const)] -#![allow( - clippy::declare_interior_mutable_const, - clippy::ref_in_deref, - clippy::needless_borrow -)] +#![allow(clippy::declare_interior_mutable_const, clippy::needless_borrow)] #![allow(const_item_mutation)] use std::borrow::Cow; diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr index f146b97cf61..9a908cf30e9 100644 --- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr @@ -1,5 +1,5 @@ error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:58:5 + --> $DIR/others.rs:54:5 | LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^ @@ -8,7 +8,7 @@ LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:59:16 + --> $DIR/others.rs:55:16 | LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability | ^^^^^^ @@ -16,7 +16,7 @@ LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:62:22 + --> $DIR/others.rs:58:22 | LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -24,7 +24,7 @@ LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:63:25 + --> $DIR/others.rs:59:25 | LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -32,7 +32,7 @@ LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:64:27 + --> $DIR/others.rs:60:27 | LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -40,7 +40,7 @@ LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:65:26 + --> $DIR/others.rs:61:26 | LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -48,7 +48,7 @@ LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:76:14 + --> $DIR/others.rs:72:14 | LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:77:14 + --> $DIR/others.rs:73:14 | LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:78:19 + --> $DIR/others.rs:74:19 | LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:79:14 + --> $DIR/others.rs:75:14 | LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:80:13 + --> $DIR/others.rs:76:13 | LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:86:13 + --> $DIR/others.rs:82:13 | LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:91:5 + --> $DIR/others.rs:87:5 | LL | CELL.set(2); //~ ERROR interior mutability | ^^^^ @@ -104,7 +104,7 @@ LL | CELL.set(2); //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:92:16 + --> $DIR/others.rs:88:16 | LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability | ^^^^ diff --git a/src/tools/clippy/tests/ui/bytecount.rs b/src/tools/clippy/tests/ui/bytecount.rs index c724ee21be3..d3ad26921bf 100644 --- a/src/tools/clippy/tests/ui/bytecount.rs +++ b/src/tools/clippy/tests/ui/bytecount.rs @@ -1,3 +1,5 @@ +#![allow(clippy::needless_borrow)] + #[deny(clippy::naive_bytecount)] fn main() { let x = vec![0_u8; 16]; diff --git a/src/tools/clippy/tests/ui/bytecount.stderr b/src/tools/clippy/tests/ui/bytecount.stderr index 1dc37fc8b25..68d838c1f82 100644 --- a/src/tools/clippy/tests/ui/bytecount.stderr +++ b/src/tools/clippy/tests/ui/bytecount.stderr @@ -1,23 +1,23 @@ error: you appear to be counting bytes the naive way - --> $DIR/bytecount.rs:5:13 + --> $DIR/bytecount.rs:7:13 | LL | let _ = x.iter().filter(|&&a| a == 0).count(); // naive byte count | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the bytecount crate: `bytecount::count(x, 0)` | note: the lint level is defined here - --> $DIR/bytecount.rs:1:8 + --> $DIR/bytecount.rs:3:8 | LL | #[deny(clippy::naive_bytecount)] | ^^^^^^^^^^^^^^^^^^^^^^^ error: you appear to be counting bytes the naive way - --> $DIR/bytecount.rs:7:13 + --> $DIR/bytecount.rs:9:13 | LL | let _ = (&x[..]).iter().filter(|&a| *a == 0).count(); // naive byte count | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the bytecount crate: `bytecount::count((&x[..]), 0)` error: you appear to be counting bytes the naive way - --> $DIR/bytecount.rs:19:13 + --> $DIR/bytecount.rs:21:13 | LL | let _ = x.iter().filter(|a| b + 1 == **a).count(); // naive byte count | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the bytecount crate: `bytecount::count(x, b + 1)` diff --git a/src/tools/clippy/tests/ui/clone_on_copy.fixed b/src/tools/clippy/tests/ui/clone_on_copy.fixed index 8d43f64768d..dc062762604 100644 --- a/src/tools/clippy/tests/ui/clone_on_copy.fixed +++ b/src/tools/clippy/tests/ui/clone_on_copy.fixed @@ -7,7 +7,8 @@ clippy::no_effect, clippy::unnecessary_operation, clippy::vec_init_then_push, - clippy::toplevel_ref_arg + clippy::toplevel_ref_arg, + clippy::needless_borrow )] use std::cell::RefCell; diff --git a/src/tools/clippy/tests/ui/clone_on_copy.rs b/src/tools/clippy/tests/ui/clone_on_copy.rs index f15501f7184..8c39d0d55dd 100644 --- a/src/tools/clippy/tests/ui/clone_on_copy.rs +++ b/src/tools/clippy/tests/ui/clone_on_copy.rs @@ -7,7 +7,8 @@ clippy::no_effect, clippy::unnecessary_operation, clippy::vec_init_then_push, - clippy::toplevel_ref_arg + clippy::toplevel_ref_arg, + clippy::needless_borrow )] use std::cell::RefCell; diff --git a/src/tools/clippy/tests/ui/clone_on_copy.stderr b/src/tools/clippy/tests/ui/clone_on_copy.stderr index e7d28b4320b..861543d0aa9 100644 --- a/src/tools/clippy/tests/ui/clone_on_copy.stderr +++ b/src/tools/clippy/tests/ui/clone_on_copy.stderr @@ -1,5 +1,5 @@ error: using `clone` on type `i32` which implements the `Copy` trait - --> $DIR/clone_on_copy.rs:24:5 + --> $DIR/clone_on_copy.rs:25:5 | LL | 42.clone(); | ^^^^^^^^^^ help: try removing the `clone` call: `42` @@ -7,43 +7,43 @@ LL | 42.clone(); = note: `-D clippy::clone-on-copy` implied by `-D warnings` error: using `clone` on type `i32` which implements the `Copy` trait - --> $DIR/clone_on_copy.rs:28:5 + --> $DIR/clone_on_copy.rs:29:5 | LL | (&42).clone(); | ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)` error: using `clone` on type `i32` which implements the `Copy` trait - --> $DIR/clone_on_copy.rs:31:5 + --> $DIR/clone_on_copy.rs:32:5 | LL | rc.borrow().clone(); | ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()` error: using `clone` on type `u32` which implements the `Copy` trait - --> $DIR/clone_on_copy.rs:34:5 + --> $DIR/clone_on_copy.rs:35:5 | LL | x.clone().rotate_left(1); | ^^^^^^^^^ help: try removing the `clone` call: `x` error: using `clone` on type `i32` which implements the `Copy` trait - --> $DIR/clone_on_copy.rs:48:5 + --> $DIR/clone_on_copy.rs:49:5 | LL | m!(42).clone(); | ^^^^^^^^^^^^^^ help: try removing the `clone` call: `m!(42)` error: using `clone` on type `[u32; 2]` which implements the `Copy` trait - --> $DIR/clone_on_copy.rs:58:5 + --> $DIR/clone_on_copy.rs:59:5 | LL | x.clone()[0]; | ^^^^^^^^^ help: try dereferencing it: `(*x)` error: using `clone` on type `char` which implements the `Copy` trait - --> $DIR/clone_on_copy.rs:68:14 + --> $DIR/clone_on_copy.rs:69:14 | LL | is_ascii('z'.clone()); | ^^^^^^^^^^^ help: try removing the `clone` call: `'z'` error: using `clone` on type `i32` which implements the `Copy` trait - --> $DIR/clone_on_copy.rs:72:14 + --> $DIR/clone_on_copy.rs:73:14 | LL | vec.push(42.clone()); | ^^^^^^^^^^ help: try removing the `clone` call: `42` diff --git a/src/tools/clippy/tests/ui/duration_subsec.fixed b/src/tools/clippy/tests/ui/duration_subsec.fixed index ee5c7863eff..d92b8998e88 100644 --- a/src/tools/clippy/tests/ui/duration_subsec.fixed +++ b/src/tools/clippy/tests/ui/duration_subsec.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![allow(dead_code)] +#![allow(dead_code, clippy::needless_borrow)] #![warn(clippy::duration_subsec)] use std::time::Duration; diff --git a/src/tools/clippy/tests/ui/duration_subsec.rs b/src/tools/clippy/tests/ui/duration_subsec.rs index 3c9d2a28621..08da804996d 100644 --- a/src/tools/clippy/tests/ui/duration_subsec.rs +++ b/src/tools/clippy/tests/ui/duration_subsec.rs @@ -1,5 +1,5 @@ // run-rustfix -#![allow(dead_code)] +#![allow(dead_code, clippy::needless_borrow)] #![warn(clippy::duration_subsec)] use std::time::Duration; diff --git a/src/tools/clippy/tests/ui/enum_variants.rs b/src/tools/clippy/tests/ui/enum_variants.rs index d3662a0a213..b2bf7c4e360 100644 --- a/src/tools/clippy/tests/ui/enum_variants.rs +++ b/src/tools/clippy/tests/ui/enum_variants.rs @@ -151,4 +151,11 @@ enum North { NoRight, } +// #8324 +enum Phase { + PreLookup, + Lookup, + PostLookup, +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed index f938f710688..618f80cdcf8 100644 --- a/src/tools/clippy/tests/ui/eta.fixed +++ b/src/tools/clippy/tests/ui/eta.fixed @@ -5,13 +5,10 @@ clippy::no_effect, clippy::redundant_closure_call, clippy::needless_pass_by_value, - clippy::option_map_unit_fn -)] -#![warn( - clippy::redundant_closure, - clippy::redundant_closure_for_method_calls, + clippy::option_map_unit_fn, clippy::needless_borrow )] +#![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)] use std::path::{Path, PathBuf}; @@ -34,7 +31,7 @@ fn main() { Some(1).map(closure_mac!()); // don't lint closure in macro expansion let _: Option<Vec<u8>> = true.then(std::vec::Vec::new); // special case vec! let d = Some(1u8).map(|a| foo(foo2(a))); //is adjusted? - all(&[1, 2, 3], &2, below); //is adjusted + all(&[1, 2, 3], &&2, below); //is adjusted unsafe { Some(1u8).map(|a| unsafe_fn(a)); // unsafe fn } diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs index 075bbc74922..a759e6eb514 100644 --- a/src/tools/clippy/tests/ui/eta.rs +++ b/src/tools/clippy/tests/ui/eta.rs @@ -5,13 +5,10 @@ clippy::no_effect, clippy::redundant_closure_call, clippy::needless_pass_by_value, - clippy::option_map_unit_fn -)] -#![warn( - clippy::redundant_closure, - clippy::redundant_closure_for_method_calls, + clippy::option_map_unit_fn, clippy::needless_borrow )] +#![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)] use std::path::{Path, PathBuf}; diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr index 8092f04c3fc..cda84982c9b 100644 --- a/src/tools/clippy/tests/ui/eta.stderr +++ b/src/tools/clippy/tests/ui/eta.stderr @@ -1,5 +1,5 @@ error: redundant closure - --> $DIR/eta.rs:31:27 + --> $DIR/eta.rs:28:27 | LL | let a = Some(1u8).map(|a| foo(a)); | ^^^^^^^^^^ help: replace the closure with the function itself: `foo` @@ -7,45 +7,37 @@ LL | let a = Some(1u8).map(|a| foo(a)); = note: `-D clippy::redundant-closure` implied by `-D warnings` error: redundant closure - --> $DIR/eta.rs:35:40 + --> $DIR/eta.rs:32:40 | LL | let _: Option<Vec<u8>> = true.then(|| vec![]); // special case vec! | ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new` error: redundant closure - --> $DIR/eta.rs:36:35 + --> $DIR/eta.rs:33:35 | LL | let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted? | ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2` -error: this expression borrows a reference (`&u8`) that is immediately dereferenced by the compiler - --> $DIR/eta.rs:37:21 - | -LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted - | ^^^ help: change this to: `&2` - | - = note: `-D clippy::needless-borrow` implied by `-D warnings` - error: redundant closure - --> $DIR/eta.rs:37:26 + --> $DIR/eta.rs:34:26 | LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted | ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below` error: redundant closure - --> $DIR/eta.rs:43:27 + --> $DIR/eta.rs:40:27 | LL | let e = Some(1u8).map(|a| divergent(a)); | ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `divergent` error: redundant closure - --> $DIR/eta.rs:44:27 + --> $DIR/eta.rs:41:27 | LL | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic` error: redundant closure - --> $DIR/eta.rs:90:51 + --> $DIR/eta.rs:87:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo` @@ -53,82 +45,82 @@ LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); = note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings` error: redundant closure - --> $DIR/eta.rs:91:51 + --> $DIR/eta.rs:88:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo` error: redundant closure - --> $DIR/eta.rs:93:42 + --> $DIR/eta.rs:90:42 | LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear()); | ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear` error: redundant closure - --> $DIR/eta.rs:97:29 + --> $DIR/eta.rs:94:29 | LL | let e = Some("str").map(|s| s.to_string()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string` error: redundant closure - --> $DIR/eta.rs:98:27 + --> $DIR/eta.rs:95:27 | LL | let e = Some('a').map(|s| s.to_uppercase()); | ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase` error: redundant closure - --> $DIR/eta.rs:100:65 + --> $DIR/eta.rs:97:65 | LL | let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase` error: redundant closure - --> $DIR/eta.rs:163:22 + --> $DIR/eta.rs:160:22 | LL | requires_fn_once(|| x()); | ^^^^^^ help: replace the closure with the function itself: `x` error: redundant closure - --> $DIR/eta.rs:170:27 + --> $DIR/eta.rs:167:27 | LL | let a = Some(1u8).map(|a| foo_ptr(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr` error: redundant closure - --> $DIR/eta.rs:175:27 + --> $DIR/eta.rs:172:27 | LL | let a = Some(1u8).map(|a| closure(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure` error: redundant closure - --> $DIR/eta.rs:207:28 + --> $DIR/eta.rs:204:28 | LL | x.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> $DIR/eta.rs:208:28 + --> $DIR/eta.rs:205:28 | LL | y.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> $DIR/eta.rs:209:28 + --> $DIR/eta.rs:206:28 | LL | z.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res` error: redundant closure - --> $DIR/eta.rs:216:21 + --> $DIR/eta.rs:213:21 | LL | Some(1).map(|n| closure(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure` error: redundant closure - --> $DIR/eta.rs:235:21 + --> $DIR/eta.rs:232:21 | LL | map_str_to_path(|s| s.as_ref()); | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::convert::AsRef::as_ref` -error: aborting due to 21 previous errors +error: aborting due to 20 previous errors diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed index 48e2aae75d0..3de2a51ffa5 100644 --- a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed +++ b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused_variables, clippy::clone_double_ref)] +#![allow(unused_variables, clippy::clone_double_ref, clippy::needless_borrow)] #![warn(clippy::explicit_deref_methods)] use std::ops::{Deref, DerefMut}; diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.rs b/src/tools/clippy/tests/ui/explicit_deref_methods.rs index d8c8c0c5ca3..a08d7596422 100644 --- a/src/tools/clippy/tests/ui/explicit_deref_methods.rs +++ b/src/tools/clippy/tests/ui/explicit_deref_methods.rs @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused_variables, clippy::clone_double_ref)] +#![allow(unused_variables, clippy::clone_double_ref, clippy::needless_borrow)] #![warn(clippy::explicit_deref_methods)] use std::ops::{Deref, DerefMut}; diff --git a/src/tools/clippy/tests/ui/for_loop_fixable.fixed b/src/tools/clippy/tests/ui/for_loop_fixable.fixed index f373e905d05..aa69781d15a 100644 --- a/src/tools/clippy/tests/ui/for_loop_fixable.fixed +++ b/src/tools/clippy/tests/ui/for_loop_fixable.fixed @@ -23,7 +23,12 @@ impl Unrelated { clippy::iter_next_loop, clippy::for_kv_map )] -#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)] +#[allow( + clippy::linkedlist, + clippy::unnecessary_mut_passed, + clippy::similar_names, + clippy::needless_borrow +)] #[allow(unused_variables)] fn main() { let mut vec = vec![1, 2, 3, 4]; diff --git a/src/tools/clippy/tests/ui/for_loop_fixable.rs b/src/tools/clippy/tests/ui/for_loop_fixable.rs index 3814583bb6e..7c063d99511 100644 --- a/src/tools/clippy/tests/ui/for_loop_fixable.rs +++ b/src/tools/clippy/tests/ui/for_loop_fixable.rs @@ -23,7 +23,12 @@ impl Unrelated { clippy::iter_next_loop, clippy::for_kv_map )] -#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)] +#[allow( + clippy::linkedlist, + clippy::unnecessary_mut_passed, + clippy::similar_names, + clippy::needless_borrow +)] #[allow(unused_variables)] fn main() { let mut vec = vec![1, 2, 3, 4]; diff --git a/src/tools/clippy/tests/ui/for_loop_fixable.stderr b/src/tools/clippy/tests/ui/for_loop_fixable.stderr index 009dbe1a0bf..ddfe66d675f 100644 --- a/src/tools/clippy/tests/ui/for_loop_fixable.stderr +++ b/src/tools/clippy/tests/ui/for_loop_fixable.stderr @@ -1,5 +1,5 @@ error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:38:15 + --> $DIR/for_loop_fixable.rs:43:15 | LL | for _v in vec.iter() {} | ^^^^^^^^^^ help: to write this more concisely, try: `&vec` @@ -7,13 +7,13 @@ LL | for _v in vec.iter() {} = note: `-D clippy::explicit-iter-loop` implied by `-D warnings` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:40:15 + --> $DIR/for_loop_fixable.rs:45:15 | LL | for _v in vec.iter_mut() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:43:15 + --> $DIR/for_loop_fixable.rs:48:15 | LL | for _v in out_vec.into_iter() {} | ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `out_vec` @@ -21,73 +21,73 @@ LL | for _v in out_vec.into_iter() {} = note: `-D clippy::explicit-into-iter-loop` implied by `-D warnings` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:48:15 + --> $DIR/for_loop_fixable.rs:53:15 | LL | for _v in [1, 2, 3].iter() {} | ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:52:15 + --> $DIR/for_loop_fixable.rs:57:15 | LL | for _v in [0; 32].iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:57:15 + --> $DIR/for_loop_fixable.rs:62:15 | LL | for _v in ll.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&ll` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:60:15 + --> $DIR/for_loop_fixable.rs:65:15 | LL | for _v in vd.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&vd` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:63:15 + --> $DIR/for_loop_fixable.rs:68:15 | LL | for _v in bh.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bh` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:66:15 + --> $DIR/for_loop_fixable.rs:71:15 | LL | for _v in hm.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hm` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:69:15 + --> $DIR/for_loop_fixable.rs:74:15 | LL | for _v in bt.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bt` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:72:15 + --> $DIR/for_loop_fixable.rs:77:15 | LL | for _v in hs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hs` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:75:15 + --> $DIR/for_loop_fixable.rs:80:15 | LL | for _v in bs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bs` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:250:18 + --> $DIR/for_loop_fixable.rs:255:18 | LL | for i in iterator.into_iter() { | ^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `iterator` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:270:18 + --> $DIR/for_loop_fixable.rs:275:18 | LL | for _ in t.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `&t` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:272:18 + --> $DIR/for_loop_fixable.rs:277:18 | LL | for _ in r.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `r` diff --git a/src/tools/clippy/tests/ui/format.fixed b/src/tools/clippy/tests/ui/format.fixed index 78d2bfd474e..d08f8f52495 100644 --- a/src/tools/clippy/tests/ui/format.fixed +++ b/src/tools/clippy/tests/ui/format.fixed @@ -1,6 +1,11 @@ // run-rustfix -#![allow(clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args)] +#![allow( + clippy::print_literal, + clippy::redundant_clone, + clippy::to_string_in_format_args, + clippy::needless_borrow +)] #![warn(clippy::useless_format)] struct Foo(pub String); diff --git a/src/tools/clippy/tests/ui/format.rs b/src/tools/clippy/tests/ui/format.rs index 009c1aa216f..4a10b580d26 100644 --- a/src/tools/clippy/tests/ui/format.rs +++ b/src/tools/clippy/tests/ui/format.rs @@ -1,6 +1,11 @@ // run-rustfix -#![allow(clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args)] +#![allow( + clippy::print_literal, + clippy::redundant_clone, + clippy::to_string_in_format_args, + clippy::needless_borrow +)] #![warn(clippy::useless_format)] struct Foo(pub String); diff --git a/src/tools/clippy/tests/ui/format.stderr b/src/tools/clippy/tests/ui/format.stderr index 660be57585e..f25c7fb1ff1 100644 --- a/src/tools/clippy/tests/ui/format.stderr +++ b/src/tools/clippy/tests/ui/format.stderr @@ -1,5 +1,5 @@ error: useless use of `format!` - --> $DIR/format.rs:13:5 + --> $DIR/format.rs:18:5 | LL | format!("foo"); | ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` @@ -7,19 +7,19 @@ LL | format!("foo"); = note: `-D clippy::useless-format` implied by `-D warnings` error: useless use of `format!` - --> $DIR/format.rs:14:5 + --> $DIR/format.rs:19:5 | LL | format!("{{}}"); | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()` error: useless use of `format!` - --> $DIR/format.rs:15:5 + --> $DIR/format.rs:20:5 | LL | format!("{{}} abc {{}}"); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()` error: useless use of `format!` - --> $DIR/format.rs:16:5 + --> $DIR/format.rs:21:5 | LL | / format!( LL | | r##"foo {{}} @@ -34,79 +34,79 @@ LL ~ " bar"##.to_string(); | error: useless use of `format!` - --> $DIR/format.rs:21:13 + --> $DIR/format.rs:26:13 | LL | let _ = format!(""); | ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()` error: useless use of `format!` - --> $DIR/format.rs:23:5 + --> $DIR/format.rs:28:5 | LL | format!("{}", "foo"); | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` - --> $DIR/format.rs:27:5 + --> $DIR/format.rs:32:5 | LL | format!("{:+}", "foo"); // Warn when the format makes no difference. | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` - --> $DIR/format.rs:28:5 + --> $DIR/format.rs:33:5 | LL | format!("{:<}", "foo"); // Warn when the format makes no difference. | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` - --> $DIR/format.rs:33:5 + --> $DIR/format.rs:38:5 | LL | format!("{}", arg); | ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` - --> $DIR/format.rs:37:5 + --> $DIR/format.rs:42:5 | LL | format!("{:+}", arg); // Warn when the format makes no difference. | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` - --> $DIR/format.rs:38:5 + --> $DIR/format.rs:43:5 | LL | format!("{:<}", arg); // Warn when the format makes no difference. | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` - --> $DIR/format.rs:65:5 + --> $DIR/format.rs:70:5 | LL | format!("{}", 42.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()` error: useless use of `format!` - --> $DIR/format.rs:67:5 + --> $DIR/format.rs:72:5 | LL | format!("{}", x.display().to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()` error: useless use of `format!` - --> $DIR/format.rs:71:18 + --> $DIR/format.rs:76:18 | LL | let _ = Some(format!("{}", a + "bar")); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"` error: useless use of `format!` - --> $DIR/format.rs:75:22 + --> $DIR/format.rs:80:22 | LL | let _s: String = format!("{}", &*v.join("/n")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()` error: useless use of `format!` - --> $DIR/format.rs:81:13 + --> $DIR/format.rs:86:13 | LL | let _ = format!("{x}"); | ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()` error: useless use of `format!` - --> $DIR/format.rs:83:13 + --> $DIR/format.rs:88:13 | LL | let _ = format!("{y}", y = x); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()` diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed index 9e37fb92559..b856f1375d3 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.fixed +++ b/src/tools/clippy/tests/ui/needless_borrow.fixed @@ -45,6 +45,33 @@ fn main() { let b = &mut b; x(b); } + + // Issue #8191 + let mut x = 5; + let mut x = &mut x; + + mut_ref(x); + mut_ref(x); + let y: &mut i32 = x; + let y: &mut i32 = x; + + let y = match 0 { + // Don't lint. Removing the borrow would move 'x' + 0 => &mut x, + _ => &mut *x, + }; + + *x = 5; + + let s = String::new(); + let _ = s.len(); + let _ = s.capacity(); + let _ = s.capacity(); + + let x = (1, 2); + let _ = x.0; + let x = &x as *const (i32, i32); + let _ = unsafe { (*x).0 }; } #[allow(clippy::needless_borrowed_reference)] diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs index 093277784be..0bfe222a3dc 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.rs +++ b/src/tools/clippy/tests/ui/needless_borrow.rs @@ -45,6 +45,33 @@ fn main() { let b = &mut b; x(&b); } + + // Issue #8191 + let mut x = 5; + let mut x = &mut x; + + mut_ref(&mut x); + mut_ref(&mut &mut x); + let y: &mut i32 = &mut x; + let y: &mut i32 = &mut &mut x; + + let y = match 0 { + // Don't lint. Removing the borrow would move 'x' + 0 => &mut x, + _ => &mut *x, + }; + + *x = 5; + + let s = String::new(); + let _ = (&s).len(); + let _ = (&s).capacity(); + let _ = (&&s).capacity(); + + let x = (1, 2); + let _ = (&x).0; + let x = &x as *const (i32, i32); + let _ = unsafe { (&*x).0 }; } #[allow(clippy::needless_borrowed_reference)] diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr index 03a5b3d260e..b90e8448db0 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.stderr +++ b/src/tools/clippy/tests/ui/needless_borrow.stderr @@ -1,4 +1,4 @@ -error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler +error: this expression creates a reference which is immediately dereferenced by the compiler --> $DIR/needless_borrow.rs:9:15 | LL | let _ = x(&&a); // warn @@ -6,59 +6,113 @@ LL | let _ = x(&&a); // warn | = note: `-D clippy::needless-borrow` implied by `-D warnings` -error: this expression borrows a reference (`&mut i32`) that is immediately dereferenced by the compiler +error: this expression creates a reference which is immediately dereferenced by the compiler --> $DIR/needless_borrow.rs:13:13 | LL | mut_ref(&mut &mut b); // warn | ^^^^^^^^^^^ help: change this to: `&mut b` -error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler +error: this expression creates a reference which is immediately dereferenced by the compiler --> $DIR/needless_borrow.rs:25:13 | LL | &&a | ^^^ help: change this to: `&a` -error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler +error: this expression creates a reference which is immediately dereferenced by the compiler --> $DIR/needless_borrow.rs:27:15 | LL | 46 => &&a, | ^^^ help: change this to: `&a` -error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler +error: this expression creates a reference which is immediately dereferenced by the compiler --> $DIR/needless_borrow.rs:33:27 | LL | break &ref_a; | ^^^^^^ help: change this to: `ref_a` -error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler +error: this expression creates a reference which is immediately dereferenced by the compiler --> $DIR/needless_borrow.rs:40:15 | LL | let _ = x(&&&a); | ^^^^ help: change this to: `&a` -error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler +error: this expression creates a reference which is immediately dereferenced by the compiler --> $DIR/needless_borrow.rs:41:15 | LL | let _ = x(&mut &&a); | ^^^^^^^^ help: change this to: `&a` -error: this expression borrows a reference (`&mut i32`) that is immediately dereferenced by the compiler +error: this expression creates a reference which is immediately dereferenced by the compiler --> $DIR/needless_borrow.rs:42:15 | LL | let _ = x(&&&mut b); | ^^^^^^^^ help: change this to: `&mut b` -error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler +error: this expression creates a reference which is immediately dereferenced by the compiler --> $DIR/needless_borrow.rs:43:15 | LL | let _ = x(&&ref_a); | ^^^^^^^ help: change this to: `ref_a` -error: this expression borrows a reference (`&mut i32`) that is immediately dereferenced by the compiler +error: this expression creates a reference which is immediately dereferenced by the compiler --> $DIR/needless_borrow.rs:46:11 | LL | x(&b); | ^^ help: change this to: `b` -error: aborting due to 10 previous errors +error: this expression creates a reference which is immediately dereferenced by the compiler + --> $DIR/needless_borrow.rs:53:13 + | +LL | mut_ref(&mut x); + | ^^^^^^ help: change this to: `x` + +error: this expression creates a reference which is immediately dereferenced by the compiler + --> $DIR/needless_borrow.rs:54:13 + | +LL | mut_ref(&mut &mut x); + | ^^^^^^^^^^^ help: change this to: `x` + +error: this expression creates a reference which is immediately dereferenced by the compiler + --> $DIR/needless_borrow.rs:55:23 + | +LL | let y: &mut i32 = &mut x; + | ^^^^^^ help: change this to: `x` + +error: this expression creates a reference which is immediately dereferenced by the compiler + --> $DIR/needless_borrow.rs:56:23 + | +LL | let y: &mut i32 = &mut &mut x; + | ^^^^^^^^^^^ help: change this to: `x` + +error: this expression borrows a value the compiler would automatically borrow + --> $DIR/needless_borrow.rs:67:13 + | +LL | let _ = (&s).len(); + | ^^^^ help: change this to: `s` + +error: this expression borrows a value the compiler would automatically borrow + --> $DIR/needless_borrow.rs:68:13 + | +LL | let _ = (&s).capacity(); + | ^^^^ help: change this to: `s` + +error: this expression creates a reference which is immediately dereferenced by the compiler + --> $DIR/needless_borrow.rs:69:13 + | +LL | let _ = (&&s).capacity(); + | ^^^^^ help: change this to: `s` + +error: this expression borrows a value the compiler would automatically borrow + --> $DIR/needless_borrow.rs:72:13 + | +LL | let _ = (&x).0; + | ^^^^ help: change this to: `x` + +error: this expression borrows a value the compiler would automatically borrow + --> $DIR/needless_borrow.rs:74:22 + | +LL | let _ = unsafe { (&*x).0 }; + | ^^^^^ help: change this to: `(*x)` + +error: aborting due to 19 previous errors diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs index b07c4a23810..f3eafe8e927 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.rs +++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs @@ -1,5 +1,11 @@ #![warn(clippy::needless_lifetimes)] -#![allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wraps, dyn_drop)] +#![allow( + dead_code, + clippy::boxed_local, + clippy::needless_pass_by_value, + clippy::unnecessary_wraps, + dyn_drop +)] fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} @@ -369,4 +375,47 @@ mod issue6159 { } } +mod issue7296 { + use std::rc::Rc; + use std::sync::Arc; + + struct Foo; + impl Foo { + fn implicit<'a>(&'a self) -> &'a () { + &() + } + fn implicit_mut<'a>(&'a mut self) -> &'a () { + &() + } + + fn explicit<'a>(self: &'a Arc<Self>) -> &'a () { + &() + } + fn explicit_mut<'a>(self: &'a mut Rc<Self>) -> &'a () { + &() + } + + fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () { + &() + } + } + + trait Bar { + fn implicit<'a>(&'a self) -> &'a (); + fn implicit_provided<'a>(&'a self) -> &'a () { + &() + } + + fn explicit<'a>(self: &'a Arc<Self>) -> &'a (); + fn explicit_provided<'a>(self: &'a Arc<Self>) -> &'a () { + &() + } + + fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a (); + fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () { + &() + } + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.stderr b/src/tools/clippy/tests/ui/needless_lifetimes.stderr index 4114e6f1832..ffa152427a9 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.stderr +++ b/src/tools/clippy/tests/ui/needless_lifetimes.stderr @@ -1,5 +1,5 @@ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:4:1 + --> $DIR/needless_lifetimes.rs:10:1 | LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,148 +7,190 @@ LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} = note: `-D clippy::needless-lifetimes` implied by `-D warnings` error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:6:1 + --> $DIR/needless_lifetimes.rs:12:1 | LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:16:1 + --> $DIR/needless_lifetimes.rs:22:1 | LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:50:1 + --> $DIR/needless_lifetimes.rs:56:1 | LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:55:1 + --> $DIR/needless_lifetimes.rs:61:1 | LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:67:1 + --> $DIR/needless_lifetimes.rs:73:1 | LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:91:1 + --> $DIR/needless_lifetimes.rs:97:1 | LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:121:5 + --> $DIR/needless_lifetimes.rs:127:5 | LL | fn self_and_out<'s>(&'s self) -> &'s u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:130:5 + --> $DIR/needless_lifetimes.rs:136:5 | LL | fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:149:1 + --> $DIR/needless_lifetimes.rs:155:1 | LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:179:1 + --> $DIR/needless_lifetimes.rs:185:1 | LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:185:1 + --> $DIR/needless_lifetimes.rs:191:1 | LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:204:1 + --> $DIR/needless_lifetimes.rs:210:1 | LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:212:1 + --> $DIR/needless_lifetimes.rs:218:1 | LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:248:1 + --> $DIR/needless_lifetimes.rs:254:1 | LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:255:9 + --> $DIR/needless_lifetimes.rs:261:9 | LL | fn needless_lt<'a>(x: &'a u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:259:9 + --> $DIR/needless_lifetimes.rs:265:9 | LL | fn needless_lt<'a>(_x: &'a u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:272:9 + --> $DIR/needless_lifetimes.rs:278:9 | LL | fn baz<'a>(&'a self) -> impl Foo + 'a { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:301:5 + --> $DIR/needless_lifetimes.rs:307:5 | LL | fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:304:5 + --> $DIR/needless_lifetimes.rs:310:5 | LL | fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:313:5 + --> $DIR/needless_lifetimes.rs:319:5 | LL | fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:325:5 + --> $DIR/needless_lifetimes.rs:331:5 | LL | fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:340:5 + --> $DIR/needless_lifetimes.rs:346:5 | LL | fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:353:5 + --> $DIR/needless_lifetimes.rs:359:5 | LL | fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:356:5 + --> $DIR/needless_lifetimes.rs:362:5 | LL | fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 25 previous errors +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:384:9 + | +LL | fn implicit<'a>(&'a self) -> &'a () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:387:9 + | +LL | fn implicit_mut<'a>(&'a mut self) -> &'a () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:398:9 + | +LL | fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:404:9 + | +LL | fn implicit<'a>(&'a self) -> &'a (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:405:9 + | +LL | fn implicit_provided<'a>(&'a self) -> &'a () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:414:9 + | +LL | fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:415:9 + | +LL | fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 32 previous errors diff --git a/src/tools/clippy/tests/ui/needless_question_mark.fixed b/src/tools/clippy/tests/ui/needless_question_mark.fixed index f1fc81aa12b..ba9d15e59d0 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.fixed +++ b/src/tools/clippy/tests/ui/needless_question_mark.fixed @@ -125,3 +125,16 @@ pub fn test2() { let x = Some(3); let _x = some_and_qmark_in_macro!(x?); } + +async fn async_option_bad(to: TO) -> Option<usize> { + let _ = Some(3); + to.magic +} + +async fn async_deref_ref(s: Option<&String>) -> Option<&str> { + Some(s?) +} + +async fn async_result_bad(s: TR) -> Result<usize, bool> { + s.magic +} diff --git a/src/tools/clippy/tests/ui/needless_question_mark.rs b/src/tools/clippy/tests/ui/needless_question_mark.rs index 44a0c5f61b5..3a6523e8fe8 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.rs +++ b/src/tools/clippy/tests/ui/needless_question_mark.rs @@ -125,3 +125,16 @@ pub fn test2() { let x = Some(3); let _x = some_and_qmark_in_macro!(x?); } + +async fn async_option_bad(to: TO) -> Option<usize> { + let _ = Some(3); + Some(to.magic?) +} + +async fn async_deref_ref(s: Option<&String>) -> Option<&str> { + Some(s?) +} + +async fn async_result_bad(s: TR) -> Result<usize, bool> { + Ok(s.magic?) +} diff --git a/src/tools/clippy/tests/ui/needless_question_mark.stderr b/src/tools/clippy/tests/ui/needless_question_mark.stderr index 57c3d48c761..f8308e24e77 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.stderr +++ b/src/tools/clippy/tests/ui/needless_question_mark.stderr @@ -77,5 +77,17 @@ LL | let _x = some_and_qmark_in_macro!(x?); | = note: this error originates in the macro `some_and_qmark_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 12 previous errors +error: question mark operator is useless here + --> $DIR/needless_question_mark.rs:131:5 + | +LL | Some(to.magic?) + | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic` + +error: question mark operator is useless here + --> $DIR/needless_question_mark.rs:139:5 + | +LL | Ok(s.magic?) + | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `s.magic` + +error: aborting due to 14 previous errors diff --git a/src/tools/clippy/tests/ui/op_ref.rs b/src/tools/clippy/tests/ui/op_ref.rs index ab9c4d34c88..d8bf66603d9 100644 --- a/src/tools/clippy/tests/ui/op_ref.rs +++ b/src/tools/clippy/tests/ui/op_ref.rs @@ -1,7 +1,7 @@ #![allow(unused_variables, clippy::blacklisted_name)] #![warn(clippy::op_ref)] use std::collections::HashSet; -use std::ops::BitAnd; +use std::ops::{BitAnd, Mul}; fn main() { let tracked_fds: HashSet<i32> = HashSet::new(); @@ -55,3 +55,40 @@ fn main() { let y = Y(2); let z = x & &y; } + +#[derive(Clone, Copy)] +struct A(i32); +#[derive(Clone, Copy)] +struct B(i32); + +impl Mul<&A> for B { + type Output = i32; + fn mul(self, rhs: &A) -> Self::Output { + self.0 * rhs.0 + } +} +impl Mul<A> for B { + type Output = i32; + fn mul(self, rhs: A) -> Self::Output { + // Should not lint because removing the reference would lead to unconditional recursion + self * &rhs + } +} +impl Mul<&A> for A { + type Output = i32; + fn mul(self, rhs: &A) -> Self::Output { + self.0 * rhs.0 + } +} +impl Mul<A> for A { + type Output = i32; + fn mul(self, rhs: A) -> Self::Output { + let one = B(1); + let two = 2; + let three = 3; + let _ = one * &self; + let _ = two + &three; + // Removing the reference would lead to unconditional recursion + self * &rhs + } +} diff --git a/src/tools/clippy/tests/ui/op_ref.stderr b/src/tools/clippy/tests/ui/op_ref.stderr index 992417084bd..fe36c01166f 100644 --- a/src/tools/clippy/tests/ui/op_ref.stderr +++ b/src/tools/clippy/tests/ui/op_ref.stderr @@ -18,5 +18,21 @@ LL | let z = x & &y; | | | help: use the right value directly: `y` -error: aborting due to 2 previous errors +error: taken reference of right operand + --> $DIR/op_ref.rs:89:17 + | +LL | let _ = one * &self; + | ^^^^^^----- + | | + | help: use the right value directly: `self` + +error: taken reference of right operand + --> $DIR/op_ref.rs:90:17 + | +LL | let _ = two + &three; + | ^^^^^^------ + | | + | help: use the right value directly: `three` + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs index 67bfef06a05..ed724237808 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.rs +++ b/src/tools/clippy/tests/ui/ptr_arg.rs @@ -9,7 +9,6 @@ fn do_vec(x: &Vec<i64>) { } fn do_vec_mut(x: &mut Vec<i64>) { - // no error here //Nothing here } @@ -18,7 +17,6 @@ fn do_str(x: &String) { } fn do_str_mut(x: &mut String) { - // no error here //Nothing here either } @@ -27,7 +25,6 @@ fn do_path(x: &PathBuf) { } fn do_path_mut(x: &mut PathBuf) { - // no error here //Nothing here either } @@ -52,7 +49,7 @@ fn cloned(x: &Vec<u8>) -> Vec<u8> { let e = x.clone(); let f = e.clone(); // OK let g = x; - let h = g.clone(); // Alas, we cannot reliably detect this without following data. + let h = g.clone(); let i = (e).clone(); x.clone() } @@ -156,6 +153,30 @@ mod issue6509 { } } +fn mut_vec_slice_methods(v: &mut Vec<u32>) { + v.copy_within(1..5, 10); +} + +fn mut_vec_vec_methods(v: &mut Vec<u32>) { + v.clear(); +} + +fn vec_contains(v: &Vec<u32>) -> bool { + [vec![], vec![0]].as_slice().contains(v) +} + +fn fn_requires_vec(v: &Vec<u32>) -> bool { + vec_contains(v) +} + +fn impl_fn_requires_vec(v: &Vec<u32>, f: impl Fn(&Vec<u32>)) { + f(v); +} + +fn dyn_fn_requires_vec(v: &Vec<u32>, f: &dyn Fn(&Vec<u32>)) { + f(v); +} + // No error for types behind an alias (#7699) type A = Vec<u8>; fn aliased(a: &A) {} diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr index 64594eb870c..a9613daadde 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.stderr +++ b/src/tools/clippy/tests/ui/ptr_arg.stderr @@ -1,4 +1,4 @@ -error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices +error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do --> $DIR/ptr_arg.rs:7:14 | LL | fn do_vec(x: &Vec<i64>) { @@ -6,170 +6,154 @@ LL | fn do_vec(x: &Vec<i64>) { | = note: `-D clippy::ptr-arg` implied by `-D warnings` +error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do + --> $DIR/ptr_arg.rs:11:18 + | +LL | fn do_vec_mut(x: &mut Vec<i64>) { + | ^^^^^^^^^^^^^ help: change this to: `&mut [i64]` + error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:16:14 + --> $DIR/ptr_arg.rs:15:14 | LL | fn do_str(x: &String) { | ^^^^^^^ help: change this to: `&str` +error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do + --> $DIR/ptr_arg.rs:19:18 + | +LL | fn do_str_mut(x: &mut String) { + | ^^^^^^^^^^^ help: change this to: `&mut str` + error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:25:15 + --> $DIR/ptr_arg.rs:23:15 | LL | fn do_path(x: &PathBuf) { | ^^^^^^^^ help: change this to: `&Path` -error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices - --> $DIR/ptr_arg.rs:38:18 +error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do + --> $DIR/ptr_arg.rs:27:19 + | +LL | fn do_path_mut(x: &mut PathBuf) { + | ^^^^^^^^^^^^ help: change this to: `&mut Path` + +error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do + --> $DIR/ptr_arg.rs:35:18 | LL | fn do_vec(x: &Vec<i64>); | ^^^^^^^^^ help: change this to: `&[i64]` -error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices - --> $DIR/ptr_arg.rs:51:14 +error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do + --> $DIR/ptr_arg.rs:48:14 | LL | fn cloned(x: &Vec<u8>) -> Vec<u8> { | ^^^^^^^^ | help: change this to | -LL | fn cloned(x: &[u8]) -> Vec<u8> { - | ~~~~~ -help: change `x.clone()` to - | -LL | let e = x.to_owned(); - | ~~~~~~~~~~~~ -help: change `x.clone()` to - | -LL | x.to_owned() - | +LL ~ fn cloned(x: &[u8]) -> Vec<u8> { +LL ~ let e = x.to_owned(); +LL | let f = e.clone(); // OK +LL | let g = x; +LL ~ let h = g.to_owned(); +LL | let i = (e).clone(); + ... error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:60:18 + --> $DIR/ptr_arg.rs:57:18 | LL | fn str_cloned(x: &String) -> String { | ^^^^^^^ | help: change this to | -LL | fn str_cloned(x: &str) -> String { - | ~~~~ -help: change `x.clone()` to - | -LL | let a = x.to_string(); - | ~~~~~~~~~~~~~ -help: change `x.clone()` to - | -LL | let b = x.to_string(); - | ~~~~~~~~~~~~~ -help: change `x.clone()` to - | -LL | x.to_string() +LL ~ fn str_cloned(x: &str) -> String { +LL ~ let a = x.to_owned(); +LL ~ let b = x.to_owned(); +LL | let c = b.clone(); +LL | let d = a.clone().clone().clone(); +LL ~ x.to_owned() | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:68:19 + --> $DIR/ptr_arg.rs:65:19 | LL | fn path_cloned(x: &PathBuf) -> PathBuf { | ^^^^^^^^ | help: change this to | -LL | fn path_cloned(x: &Path) -> PathBuf { - | ~~~~~ -help: change `x.clone()` to - | -LL | let a = x.to_path_buf(); - | ~~~~~~~~~~~~~~~ -help: change `x.clone()` to - | -LL | let b = x.to_path_buf(); - | ~~~~~~~~~~~~~~~ -help: change `x.clone()` to - | -LL | x.to_path_buf() +LL ~ fn path_cloned(x: &Path) -> PathBuf { +LL ~ let a = x.to_path_buf(); +LL ~ let b = x.to_path_buf(); +LL | let c = b.clone(); +LL | let d = a.clone().clone().clone(); +LL ~ x.to_path_buf() | error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:76:44 + --> $DIR/ptr_arg.rs:73:44 | LL | fn false_positive_capacity(x: &Vec<u8>, y: &String) { | ^^^^^^^ | help: change this to | -LL | fn false_positive_capacity(x: &Vec<u8>, y: &str) { - | ~~~~ -help: change `y.clone()` to +LL ~ fn false_positive_capacity(x: &Vec<u8>, y: &str) { +LL | let a = x.capacity(); +LL ~ let b = y.to_owned(); +LL ~ let c = y; | -LL | let b = y.to_string(); - | ~~~~~~~~~~~~~ -help: change `y.as_str()` to - | -LL | let c = y; - | ~ error: using a reference to `Cow` is not recommended - --> $DIR/ptr_arg.rs:90:25 + --> $DIR/ptr_arg.rs:87:25 | LL | fn test_cow_with_ref(c: &Cow<[i32]>) {} | ^^^^^^^^^^^ help: change this to: `&[i32]` -error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices - --> $DIR/ptr_arg.rs:143:21 +error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do + --> $DIR/ptr_arg.rs:140:21 | LL | fn foo_vec(vec: &Vec<u8>) { | ^^^^^^^^ | help: change this to | -LL | fn foo_vec(vec: &[u8]) { - | ~~~~~ -help: change `vec.clone()` to - | -LL | let _ = vec.to_owned().pop(); - | ~~~~~~~~~~~~~~ -help: change `vec.clone()` to +LL ~ fn foo_vec(vec: &[u8]) { +LL ~ let _ = vec.to_owned().pop(); +LL ~ let _ = vec.to_owned().clone(); | -LL | let _ = vec.to_owned().clone(); - | ~~~~~~~~~~~~~~ error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:148:23 + --> $DIR/ptr_arg.rs:145:23 | LL | fn foo_path(path: &PathBuf) { | ^^^^^^^^ | help: change this to | -LL | fn foo_path(path: &Path) { - | ~~~~~ -help: change `path.clone()` to +LL ~ fn foo_path(path: &Path) { +LL ~ let _ = path.to_path_buf().pop(); +LL ~ let _ = path.to_path_buf().clone(); | -LL | let _ = path.to_path_buf().pop(); - | ~~~~~~~~~~~~~~~~~~ -help: change `path.clone()` to - | -LL | let _ = path.to_path_buf().clone(); - | ~~~~~~~~~~~~~~~~~~ error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:153:21 + --> $DIR/ptr_arg.rs:150:21 | LL | fn foo_str(str: &PathBuf) { | ^^^^^^^^ | help: change this to | -LL | fn foo_str(str: &Path) { - | ~~~~~ -help: change `str.clone()` to +LL ~ fn foo_str(str: &Path) { +LL ~ let _ = str.to_path_buf().pop(); +LL ~ let _ = str.to_path_buf().clone(); | -LL | let _ = str.to_path_buf().pop(); - | ~~~~~~~~~~~~~~~~~ -help: change `str.clone()` to + +error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do + --> $DIR/ptr_arg.rs:156:29 | -LL | let _ = str.to_path_buf().clone(); - | ~~~~~~~~~~~~~~~~~ +LL | fn mut_vec_slice_methods(v: &mut Vec<u32>) { + | ^^^^^^^^^^^^^ help: change this to: `&mut [u32]` -error: aborting due to 12 previous errors +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed index cc93859269c..a89845c1dd3 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed @@ -81,7 +81,7 @@ const fn issue6067() { None::<()>.is_none(); } -#[allow(clippy::deref_addrof, dead_code)] +#[allow(clippy::deref_addrof, dead_code, clippy::needless_borrow)] fn issue7921() { if (&None::<()>).is_none() {} if (&None::<()>).is_none() {} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs index 280dca40c01..d6f44403487 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs @@ -96,7 +96,7 @@ const fn issue6067() { }; } -#[allow(clippy::deref_addrof, dead_code)] +#[allow(clippy::deref_addrof, dead_code, clippy::needless_borrow)] fn issue7921() { if let None = *(&None::<()>) {} if let None = *&None::<()> {} diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index b9425733a8b..8bddec576ed 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -54,6 +54,7 @@ #![warn(clippy::match_result_ok)] #![warn(clippy::disallowed_types)] #![warn(clippy::disallowed_methods)] +#![warn(clippy::needless_borrow)] // uplifted lints #![warn(invalid_value)] #![warn(array_into_iter)] diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs index 341c003b9df..d2010d71d2c 100644 --- a/src/tools/clippy/tests/ui/rename.rs +++ b/src/tools/clippy/tests/ui/rename.rs @@ -54,6 +54,7 @@ #![warn(clippy::if_let_some_result)] #![warn(clippy::disallowed_type)] #![warn(clippy::disallowed_method)] +#![warn(clippy::ref_in_deref)] // uplifted lints #![warn(clippy::invalid_ref)] #![warn(clippy::into_iter_on_array)] diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index cdec2808f1d..45cb8b786f5 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -138,59 +138,65 @@ error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_ LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` +error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` + --> $DIR/rename.rs:57:9 + | +LL | #![warn(clippy::ref_in_deref)] + | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` + error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` -error: aborting due to 32 previous errors +error: aborting due to 33 previous errors diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs b/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs index 778f4f6fa25..767518ab0c0 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs @@ -189,7 +189,7 @@ mod issue7392 { let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none(); } - fn test_string_1(s: &String) -> bool { + fn test_string_1(s: &str) -> bool { s.is_empty() } diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr index 7c5e5eb589c..933ce5cf42d 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr @@ -251,14 +251,6 @@ error: called `is_none()` after searching an `Iterator` with `find` LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)` -error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/search_is_some_fixable_none.rs:192:25 - | -LL | fn test_string_1(s: &String) -> bool { - | ^^^^^^^ help: change this to: `&str` - | - = note: `-D clippy::ptr-arg` implied by `-D warnings` - error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:208:17 | @@ -289,5 +281,5 @@ error: called `is_none()` after searching an `Iterator` with `find` LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|fp| test_u32_2(*fp.field))` -error: aborting due to 44 previous errors +error: aborting due to 43 previous errors diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs b/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs index 241641fceae..77fd52e4ce7 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs @@ -188,7 +188,7 @@ mod issue7392 { let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some(); } - fn test_string_1(s: &String) -> bool { + fn test_string_1(s: &str) -> bool { s.is_empty() } diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr index 9212c6e71ff..8b424f18ef5 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr @@ -234,14 +234,6 @@ error: called `is_some()` after searching an `Iterator` with `find` LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|(&x, y)| x == *y)` -error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/search_is_some_fixable_some.rs:191:25 - | -LL | fn test_string_1(s: &String) -> bool { - | ^^^^^^^ help: change this to: `&str` - | - = note: `-D clippy::ptr-arg` implied by `-D warnings` - error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:207:26 | @@ -272,5 +264,5 @@ error: called `is_some()` after searching an `Iterator` with `find` LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|fp| test_u32_2(*fp.field))` -error: aborting due to 44 previous errors +error: aborting due to 43 previous errors diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.rs b/src/tools/clippy/tests/ui/slow_vector_initialization.rs index c5ae3ff769b..7e3d357ae50 100644 --- a/src/tools/clippy/tests/ui/slow_vector_initialization.rs +++ b/src/tools/clippy/tests/ui/slow_vector_initialization.rs @@ -53,7 +53,7 @@ fn resize_vector() { vec1.resize(10, 0); } -fn do_stuff(vec: &mut Vec<u8>) {} +fn do_stuff(vec: &mut [u8]) {} fn extend_vector_with_manipulations_between() { let len = 300; diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs index 2edb202892a..21de19a2601 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs @@ -1,5 +1,6 @@ #![deny(clippy::trait_duplication_in_bounds)] +use std::collections::BTreeMap; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z) @@ -73,4 +74,25 @@ impl U for Life { fn f() {} } +// should not warn +trait Iter: Iterator { + fn into_group_btreemap<K, V>(self) -> BTreeMap<K, Vec<V>> + where + Self: Iterator<Item = (K, V)> + Sized, + K: Ord + Eq, + { + unimplemented!(); + } +} + +struct Foo {} + +trait FooIter: Iterator<Item = Foo> { + fn bar() + where + Self: Iterator<Item = Foo>, + { + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr index e0c7a7ec618..6f8c8e47dfb 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr @@ -1,5 +1,5 @@ error: this trait bound is already specified in the where clause - --> $DIR/trait_duplication_in_bounds.rs:5:15 + --> $DIR/trait_duplication_in_bounds.rs:6:15 | LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z) | ^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(clippy::trait_duplication_in_bounds)] = help: consider removing this trait bound error: this trait bound is already specified in the where clause - --> $DIR/trait_duplication_in_bounds.rs:5:23 + --> $DIR/trait_duplication_in_bounds.rs:6:23 | LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z) | ^^^^^^^ @@ -20,7 +20,7 @@ LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z) = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds.rs:34:15 + --> $DIR/trait_duplication_in_bounds.rs:35:15 | LL | Self: Default; | ^^^^^^^ @@ -28,7 +28,7 @@ LL | Self: Default; = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds.rs:48:15 + --> $DIR/trait_duplication_in_bounds.rs:49:15 | LL | Self: Default + Clone; | ^^^^^^^ @@ -36,7 +36,7 @@ LL | Self: Default + Clone; = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds.rs:54:15 + --> $DIR/trait_duplication_in_bounds.rs:55:15 | LL | Self: Default + Clone; | ^^^^^^^ @@ -44,7 +44,7 @@ LL | Self: Default + Clone; = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds.rs:54:25 + --> $DIR/trait_duplication_in_bounds.rs:55:25 | LL | Self: Default + Clone; | ^^^^^ @@ -52,12 +52,20 @@ LL | Self: Default + Clone; = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds.rs:57:15 + --> $DIR/trait_duplication_in_bounds.rs:58:15 | LL | Self: Default; | ^^^^^^^ | = help: consider removing this trait bound -error: aborting due to 7 previous errors +error: this trait bound is already specified in trait declaration + --> $DIR/trait_duplication_in_bounds.rs:93:15 + | +LL | Self: Iterator<Item = Foo>, + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing this trait bound + +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.rs b/src/tools/clippy/tests/ui/unnecessary_cast.rs index e8f2fb46665..b77c19f2ba5 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.rs +++ b/src/tools/clippy/tests/ui/unnecessary_cast.rs @@ -1,6 +1,7 @@ #![warn(clippy::unnecessary_cast)] #![allow(clippy::no_effect)] +#[rustfmt::skip] fn main() { // Test cast_unnecessary 1i32 as i32; @@ -8,6 +9,12 @@ fn main() { false as bool; &1i32 as &i32; + -1_i32 as i32; + - 1_i32 as i32; + -1f32 as f32; + 1_i32 as i32; + 1_f32 as f32; + // macro version macro_rules! foo { ($a:ident, $b:ident) => { diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.stderr b/src/tools/clippy/tests/ui/unnecessary_cast.stderr index 70aa448af68..a5a93c6110c 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_cast.stderr @@ -1,5 +1,5 @@ error: casting integer literal to `i32` is unnecessary - --> $DIR/unnecessary_cast.rs:6:5 + --> $DIR/unnecessary_cast.rs:7:5 | LL | 1i32 as i32; | ^^^^^^^^^^^ help: try: `1_i32` @@ -7,16 +7,46 @@ LL | 1i32 as i32; = note: `-D clippy::unnecessary-cast` implied by `-D warnings` error: casting float literal to `f32` is unnecessary - --> $DIR/unnecessary_cast.rs:7:5 + --> $DIR/unnecessary_cast.rs:8:5 | LL | 1f32 as f32; | ^^^^^^^^^^^ help: try: `1_f32` error: casting to the same type is unnecessary (`bool` -> `bool`) - --> $DIR/unnecessary_cast.rs:8:5 + --> $DIR/unnecessary_cast.rs:9:5 | LL | false as bool; | ^^^^^^^^^^^^^ help: try: `false` -error: aborting due to 3 previous errors +error: casting integer literal to `i32` is unnecessary + --> $DIR/unnecessary_cast.rs:12:5 + | +LL | -1_i32 as i32; + | ^^^^^^^^^^^^^ help: try: `-1_i32` + +error: casting integer literal to `i32` is unnecessary + --> $DIR/unnecessary_cast.rs:13:5 + | +LL | - 1_i32 as i32; + | ^^^^^^^^^^^^^^ help: try: `- 1_i32` + +error: casting float literal to `f32` is unnecessary + --> $DIR/unnecessary_cast.rs:14:5 + | +LL | -1f32 as f32; + | ^^^^^^^^^^^^ help: try: `-1_f32` + +error: casting integer literal to `i32` is unnecessary + --> $DIR/unnecessary_cast.rs:15:5 + | +LL | 1_i32 as i32; + | ^^^^^^^^^^^^ help: try: `1_i32` + +error: casting float literal to `f32` is unnecessary + --> $DIR/unnecessary_cast.rs:16:5 + | +LL | 1_f32 as f32; + | ^^^^^^^^^^^^ help: try: `1_f32` + +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_ref.fixed b/src/tools/clippy/tests/ui/unnecessary_ref.fixed deleted file mode 100644 index d927bae976f..00000000000 --- a/src/tools/clippy/tests/ui/unnecessary_ref.fixed +++ /dev/null @@ -1,23 +0,0 @@ -// run-rustfix - -#![feature(stmt_expr_attributes)] -#![allow(unused_variables, dead_code)] - -struct Outer { - inner: u32, -} - -#[deny(clippy::ref_in_deref)] -fn main() { - let outer = Outer { inner: 0 }; - let inner = outer.inner; -} - -struct Apple; -impl Apple { - fn hello(&self) {} -} -struct Package(pub *const Apple); -fn foobar(package: *const Package) { - unsafe { &*(*package).0 }.hello(); -} diff --git a/src/tools/clippy/tests/ui/unnecessary_ref.rs b/src/tools/clippy/tests/ui/unnecessary_ref.rs deleted file mode 100644 index 86bfb76ec26..00000000000 --- a/src/tools/clippy/tests/ui/unnecessary_ref.rs +++ /dev/null @@ -1,23 +0,0 @@ -// run-rustfix - -#![feature(stmt_expr_attributes)] -#![allow(unused_variables, dead_code)] - -struct Outer { - inner: u32, -} - -#[deny(clippy::ref_in_deref)] -fn main() { - let outer = Outer { inner: 0 }; - let inner = (&outer).inner; -} - -struct Apple; -impl Apple { - fn hello(&self) {} -} -struct Package(pub *const Apple); -fn foobar(package: *const Package) { - unsafe { &*(&*package).0 }.hello(); -} diff --git a/src/tools/clippy/tests/ui/unnecessary_ref.stderr b/src/tools/clippy/tests/ui/unnecessary_ref.stderr deleted file mode 100644 index 436f4bcf738..00000000000 --- a/src/tools/clippy/tests/ui/unnecessary_ref.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: creating a reference that is immediately dereferenced - --> $DIR/unnecessary_ref.rs:13:17 - | -LL | let inner = (&outer).inner; - | ^^^^^^^^ help: try this: `outer` - | -note: the lint level is defined here - --> $DIR/unnecessary_ref.rs:10:8 - | -LL | #[deny(clippy::ref_in_deref)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: creating a reference that is immediately dereferenced - --> $DIR/unnecessary_ref.rs:22:16 - | -LL | unsafe { &*(&*package).0 }.hello(); - | ^^^^^^^^^^^ help: try this: `(*package)` - | - = note: `-D clippy::ref-in-deref` implied by `-D warnings` - -error: aborting due to 2 previous errors - diff --git a/src/tools/clippy/tests/ui/useless_asref.fixed b/src/tools/clippy/tests/ui/useless_asref.fixed index e356f13d087..e431661d180 100644 --- a/src/tools/clippy/tests/ui/useless_asref.fixed +++ b/src/tools/clippy/tests/ui/useless_asref.fixed @@ -67,7 +67,7 @@ fn not_ok() { foo_rslice(mrrrrrslice); foo_rslice(mrrrrrslice); } - #[allow(unused_parens, clippy::double_parens)] + #[allow(unused_parens, clippy::double_parens, clippy::needless_borrow)] foo_rrrrmr((&&&&MoreRef)); generic_not_ok(mrslice); diff --git a/src/tools/clippy/tests/ui/useless_asref.rs b/src/tools/clippy/tests/ui/useless_asref.rs index 2a80291f5d8..6ae931d7aa4 100644 --- a/src/tools/clippy/tests/ui/useless_asref.rs +++ b/src/tools/clippy/tests/ui/useless_asref.rs @@ -67,7 +67,7 @@ fn not_ok() { foo_rslice(mrrrrrslice.as_ref()); foo_rslice(mrrrrrslice); } - #[allow(unused_parens, clippy::double_parens)] + #[allow(unused_parens, clippy::double_parens, clippy::needless_borrow)] foo_rrrrmr((&&&&MoreRef).as_ref()); generic_not_ok(mrslice); diff --git a/src/tools/clippy/tests/ui/write_literal.rs b/src/tools/clippy/tests/ui/write_literal.rs index 0a127858def..44669174411 100644 --- a/src/tools/clippy/tests/ui/write_literal.rs +++ b/src/tools/clippy/tests/ui/write_literal.rs @@ -7,37 +7,37 @@ fn main() { let mut v = Vec::new(); // these should be fine - write!(&mut v, "Hello"); - writeln!(&mut v, "Hello"); + write!(v, "Hello"); + writeln!(v, "Hello"); let world = "world"; - writeln!(&mut v, "Hello {}", world); - writeln!(&mut v, "Hello {world}", world = world); - writeln!(&mut v, "3 in hex is {:X}", 3); - writeln!(&mut v, "2 + 1 = {:.4}", 3); - writeln!(&mut v, "2 + 1 = {:5.4}", 3); - writeln!(&mut v, "Debug test {:?}", "hello, world"); - writeln!(&mut v, "{0:8} {1:>8}", "hello", "world"); - writeln!(&mut v, "{1:8} {0:>8}", "hello", "world"); - writeln!(&mut v, "{foo:8} {bar:>8}", foo = "hello", bar = "world"); - writeln!(&mut v, "{bar:8} {foo:>8}", foo = "hello", bar = "world"); - writeln!(&mut v, "{number:>width$}", number = 1, width = 6); - writeln!(&mut v, "{number:>0width$}", number = 1, width = 6); - writeln!(&mut v, "{} of {:b} people know binary, the other half doesn't", 1, 2); - writeln!(&mut v, "10 / 4 is {}", 2.5); - writeln!(&mut v, "2 + 1 = {}", 3); + writeln!(v, "Hello {}", world); + writeln!(v, "Hello {world}", world = world); + writeln!(v, "3 in hex is {:X}", 3); + writeln!(v, "2 + 1 = {:.4}", 3); + writeln!(v, "2 + 1 = {:5.4}", 3); + writeln!(v, "Debug test {:?}", "hello, world"); + writeln!(v, "{0:8} {1:>8}", "hello", "world"); + writeln!(v, "{1:8} {0:>8}", "hello", "world"); + writeln!(v, "{foo:8} {bar:>8}", foo = "hello", bar = "world"); + writeln!(v, "{bar:8} {foo:>8}", foo = "hello", bar = "world"); + writeln!(v, "{number:>width$}", number = 1, width = 6); + writeln!(v, "{number:>0width$}", number = 1, width = 6); + writeln!(v, "{} of {:b} people know binary, the other half doesn't", 1, 2); + writeln!(v, "10 / 4 is {}", 2.5); + writeln!(v, "2 + 1 = {}", 3); // these should throw warnings - write!(&mut v, "Hello {}", "world"); - writeln!(&mut v, "Hello {} {}", world, "world"); - writeln!(&mut v, "Hello {}", "world"); + write!(v, "Hello {}", "world"); + writeln!(v, "Hello {} {}", world, "world"); + writeln!(v, "Hello {}", "world"); // positional args don't change the fact // that we're using a literal -- this should // throw a warning - writeln!(&mut v, "{0} {1}", "hello", "world"); - writeln!(&mut v, "{1} {0}", "hello", "world"); + writeln!(v, "{0} {1}", "hello", "world"); + writeln!(v, "{1} {0}", "hello", "world"); // named args shouldn't change anything either - writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world"); - writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world"); + writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); + writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); } diff --git a/src/tools/clippy/tests/ui/write_literal.stderr b/src/tools/clippy/tests/ui/write_literal.stderr index e0297c00231..593e9493ec5 100644 --- a/src/tools/clippy/tests/ui/write_literal.stderr +++ b/src/tools/clippy/tests/ui/write_literal.stderr @@ -1,134 +1,134 @@ error: literal with an empty format string - --> $DIR/write_literal.rs:30:32 + --> $DIR/write_literal.rs:30:27 | -LL | write!(&mut v, "Hello {}", "world"); - | ^^^^^^^ +LL | write!(v, "Hello {}", "world"); + | ^^^^^^^ | = note: `-D clippy::write-literal` implied by `-D warnings` help: try this | -LL - write!(&mut v, "Hello {}", "world"); -LL + write!(&mut v, "Hello world"); +LL - write!(v, "Hello {}", "world"); +LL + write!(v, "Hello world"); | error: literal with an empty format string - --> $DIR/write_literal.rs:31:44 + --> $DIR/write_literal.rs:31:39 | -LL | writeln!(&mut v, "Hello {} {}", world, "world"); - | ^^^^^^^ +LL | writeln!(v, "Hello {} {}", world, "world"); + | ^^^^^^^ | help: try this | -LL - writeln!(&mut v, "Hello {} {}", world, "world"); -LL + writeln!(&mut v, "Hello {} world", world); +LL - writeln!(v, "Hello {} {}", world, "world"); +LL + writeln!(v, "Hello {} world", world); | error: literal with an empty format string - --> $DIR/write_literal.rs:32:34 + --> $DIR/write_literal.rs:32:29 | -LL | writeln!(&mut v, "Hello {}", "world"); - | ^^^^^^^ +LL | writeln!(v, "Hello {}", "world"); + | ^^^^^^^ | help: try this | -LL - writeln!(&mut v, "Hello {}", "world"); -LL + writeln!(&mut v, "Hello world"); +LL - writeln!(v, "Hello {}", "world"); +LL + writeln!(v, "Hello world"); | error: literal with an empty format string - --> $DIR/write_literal.rs:37:33 + --> $DIR/write_literal.rs:37:28 | -LL | writeln!(&mut v, "{0} {1}", "hello", "world"); - | ^^^^^^^ +LL | writeln!(v, "{0} {1}", "hello", "world"); + | ^^^^^^^ | help: try this | -LL - writeln!(&mut v, "{0} {1}", "hello", "world"); -LL + writeln!(&mut v, "hello {1}", "world"); +LL - writeln!(v, "{0} {1}", "hello", "world"); +LL + writeln!(v, "hello {1}", "world"); | error: literal with an empty format string - --> $DIR/write_literal.rs:37:42 + --> $DIR/write_literal.rs:37:37 | -LL | writeln!(&mut v, "{0} {1}", "hello", "world"); - | ^^^^^^^ +LL | writeln!(v, "{0} {1}", "hello", "world"); + | ^^^^^^^ | help: try this | -LL - writeln!(&mut v, "{0} {1}", "hello", "world"); -LL + writeln!(&mut v, "{0} world", "hello"); +LL - writeln!(v, "{0} {1}", "hello", "world"); +LL + writeln!(v, "{0} world", "hello"); | error: literal with an empty format string - --> $DIR/write_literal.rs:38:33 + --> $DIR/write_literal.rs:38:28 | -LL | writeln!(&mut v, "{1} {0}", "hello", "world"); - | ^^^^^^^ +LL | writeln!(v, "{1} {0}", "hello", "world"); + | ^^^^^^^ | help: try this | -LL - writeln!(&mut v, "{1} {0}", "hello", "world"); -LL + writeln!(&mut v, "{1} hello", "world"); +LL - writeln!(v, "{1} {0}", "hello", "world"); +LL + writeln!(v, "{1} hello", "world"); | error: literal with an empty format string - --> $DIR/write_literal.rs:38:42 + --> $DIR/write_literal.rs:38:37 | -LL | writeln!(&mut v, "{1} {0}", "hello", "world"); - | ^^^^^^^ +LL | writeln!(v, "{1} {0}", "hello", "world"); + | ^^^^^^^ | help: try this | -LL - writeln!(&mut v, "{1} {0}", "hello", "world"); -LL + writeln!(&mut v, "world {0}", "hello"); +LL - writeln!(v, "{1} {0}", "hello", "world"); +LL + writeln!(v, "world {0}", "hello"); | error: literal with an empty format string - --> $DIR/write_literal.rs:41:37 + --> $DIR/write_literal.rs:41:32 | -LL | writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ +LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); + | ^^^^^^^^^^^^^ | help: try this | -LL - writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world"); -LL + writeln!(&mut v, "hello {bar}", bar = "world"); +LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); +LL + writeln!(v, "hello {bar}", bar = "world"); | error: literal with an empty format string - --> $DIR/write_literal.rs:41:52 + --> $DIR/write_literal.rs:41:47 | -LL | writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ +LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); + | ^^^^^^^^^^^^^ | help: try this | -LL - writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world"); -LL + writeln!(&mut v, "{foo} world", foo = "hello"); +LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); +LL + writeln!(v, "{foo} world", foo = "hello"); | error: literal with an empty format string - --> $DIR/write_literal.rs:42:37 + --> $DIR/write_literal.rs:42:32 | -LL | writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ +LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); + | ^^^^^^^^^^^^^ | help: try this | -LL - writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world"); -LL + writeln!(&mut v, "{bar} hello", bar = "world"); +LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); +LL + writeln!(v, "{bar} hello", bar = "world"); | error: literal with an empty format string - --> $DIR/write_literal.rs:42:52 + --> $DIR/write_literal.rs:42:47 | -LL | writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ +LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); + | ^^^^^^^^^^^^^ | help: try this | -LL - writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world"); -LL + writeln!(&mut v, "world {foo}", foo = "hello"); +LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); +LL + writeln!(v, "world {foo}", foo = "hello"); | error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/write_literal_2.rs b/src/tools/clippy/tests/ui/write_literal_2.rs index f341e8215e1..ba0d7be5eaa 100644 --- a/src/tools/clippy/tests/ui/write_literal_2.rs +++ b/src/tools/clippy/tests/ui/write_literal_2.rs @@ -6,20 +6,20 @@ use std::io::Write; fn main() { let mut v = Vec::new(); - writeln!(&mut v, "{}", "{hello}"); - writeln!(&mut v, r"{}", r"{hello}"); - writeln!(&mut v, "{}", '\''); - writeln!(&mut v, "{}", '"'); - writeln!(&mut v, r"{}", '"'); // don't lint - writeln!(&mut v, r"{}", '\''); + writeln!(v, "{}", "{hello}"); + writeln!(v, r"{}", r"{hello}"); + writeln!(v, "{}", '\''); + writeln!(v, "{}", '"'); + writeln!(v, r"{}", '"'); // don't lint + writeln!(v, r"{}", '\''); writeln!( - &mut v, + v, "some {}", "hello \ world!" ); writeln!( - &mut v, + v, "some {}\ {} \\ {}", "1", "2", "3", diff --git a/src/tools/clippy/tests/ui/write_literal_2.stderr b/src/tools/clippy/tests/ui/write_literal_2.stderr index 73c6b885813..fc40fbfa9e2 100644 --- a/src/tools/clippy/tests/ui/write_literal_2.stderr +++ b/src/tools/clippy/tests/ui/write_literal_2.stderr @@ -1,62 +1,62 @@ error: literal with an empty format string - --> $DIR/write_literal_2.rs:9:28 + --> $DIR/write_literal_2.rs:9:23 | -LL | writeln!(&mut v, "{}", "{hello}"); - | ^^^^^^^^^ +LL | writeln!(v, "{}", "{hello}"); + | ^^^^^^^^^ | = note: `-D clippy::write-literal` implied by `-D warnings` help: try this | -LL - writeln!(&mut v, "{}", "{hello}"); -LL + writeln!(&mut v, "{{hello}}"); +LL - writeln!(v, "{}", "{hello}"); +LL + writeln!(v, "{{hello}}"); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:10:29 + --> $DIR/write_literal_2.rs:10:24 | -LL | writeln!(&mut v, r"{}", r"{hello}"); - | ^^^^^^^^^^ +LL | writeln!(v, r"{}", r"{hello}"); + | ^^^^^^^^^^ | help: try this | -LL - writeln!(&mut v, r"{}", r"{hello}"); -LL + writeln!(&mut v, r"{{hello}}"); +LL - writeln!(v, r"{}", r"{hello}"); +LL + writeln!(v, r"{{hello}}"); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:11:28 + --> $DIR/write_literal_2.rs:11:23 | -LL | writeln!(&mut v, "{}", '/''); - | ^^^^ +LL | writeln!(v, "{}", '/''); + | ^^^^ | help: try this | -LL - writeln!(&mut v, "{}", '/''); -LL + writeln!(&mut v, "'"); +LL - writeln!(v, "{}", '/''); +LL + writeln!(v, "'"); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:12:28 + --> $DIR/write_literal_2.rs:12:23 | -LL | writeln!(&mut v, "{}", '"'); - | ^^^ +LL | writeln!(v, "{}", '"'); + | ^^^ | help: try this | -LL - writeln!(&mut v, "{}", '"'); -LL + writeln!(&mut v, "/""); +LL - writeln!(v, "{}", '"'); +LL + writeln!(v, "/""); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:14:29 + --> $DIR/write_literal_2.rs:14:24 | -LL | writeln!(&mut v, r"{}", '/''); - | ^^^^ +LL | writeln!(v, r"{}", '/''); + | ^^^^ | help: try this | -LL - writeln!(&mut v, r"{}", '/''); -LL + writeln!(&mut v, r"'"); +LL - writeln!(v, r"{}", '/''); +LL + writeln!(v, r"'"); | error: literal with an empty format string diff --git a/src/tools/clippy/tests/ui/write_with_newline.rs b/src/tools/clippy/tests/ui/write_with_newline.rs index 1c1b1b58402..446d6914d34 100644 --- a/src/tools/clippy/tests/ui/write_with_newline.rs +++ b/src/tools/clippy/tests/ui/write_with_newline.rs @@ -10,50 +10,50 @@ fn main() { let mut v = Vec::new(); // These should fail - write!(&mut v, "Hello\n"); - write!(&mut v, "Hello {}\n", "world"); - write!(&mut v, "Hello {} {}\n", "world", "#2"); - write!(&mut v, "{}\n", 1265); - write!(&mut v, "\n"); + write!(v, "Hello\n"); + write!(v, "Hello {}\n", "world"); + write!(v, "Hello {} {}\n", "world", "#2"); + write!(v, "{}\n", 1265); + write!(v, "\n"); // These should be fine - write!(&mut v, ""); - write!(&mut v, "Hello"); - writeln!(&mut v, "Hello"); - writeln!(&mut v, "Hello\n"); - writeln!(&mut v, "Hello {}\n", "world"); - write!(&mut v, "Issue\n{}", 1265); - write!(&mut v, "{}", 1265); - write!(&mut v, "\n{}", 1275); - write!(&mut v, "\n\n"); - write!(&mut v, "like eof\n\n"); - write!(&mut v, "Hello {} {}\n\n", "world", "#2"); - writeln!(&mut v, "\ndon't\nwarn\nfor\nmultiple\nnewlines\n"); // #3126 - writeln!(&mut v, "\nbla\n\n"); // #3126 + write!(v, ""); + write!(v, "Hello"); + writeln!(v, "Hello"); + writeln!(v, "Hello\n"); + writeln!(v, "Hello {}\n", "world"); + write!(v, "Issue\n{}", 1265); + write!(v, "{}", 1265); + write!(v, "\n{}", 1275); + write!(v, "\n\n"); + write!(v, "like eof\n\n"); + write!(v, "Hello {} {}\n\n", "world", "#2"); + writeln!(v, "\ndon't\nwarn\nfor\nmultiple\nnewlines\n"); // #3126 + writeln!(v, "\nbla\n\n"); // #3126 // Escaping - write!(&mut v, "\\n"); // #3514 - write!(&mut v, "\\\n"); // should fail - write!(&mut v, "\\\\n"); + write!(v, "\\n"); // #3514 + write!(v, "\\\n"); // should fail + write!(v, "\\\\n"); // Raw strings - write!(&mut v, r"\n"); // #3778 + write!(v, r"\n"); // #3778 // Literal newlines should also fail write!( - &mut v, + v, " " ); write!( - &mut v, + v, r" " ); // Don't warn on CRLF (#4208) - write!(&mut v, "\r\n"); - write!(&mut v, "foo\r\n"); - write!(&mut v, "\\r\n"); //~ ERROR - write!(&mut v, "foo\rbar\n"); + write!(v, "\r\n"); + write!(v, "foo\r\n"); + write!(v, "\\r\n"); //~ ERROR + write!(v, "foo\rbar\n"); } diff --git a/src/tools/clippy/tests/ui/write_with_newline.stderr b/src/tools/clippy/tests/ui/write_with_newline.stderr index 186459e50b6..3314a2a6e24 100644 --- a/src/tools/clippy/tests/ui/write_with_newline.stderr +++ b/src/tools/clippy/tests/ui/write_with_newline.stderr @@ -1,81 +1,81 @@ error: using `write!()` with a format string that ends in a single newline --> $DIR/write_with_newline.rs:13:5 | -LL | write!(&mut v, "Hello/n"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | write!(v, "Hello/n"); + | ^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::write-with-newline` implied by `-D warnings` help: use `writeln!()` instead | -LL - write!(&mut v, "Hello/n"); -LL + writeln!(&mut v, "Hello"); +LL - write!(v, "Hello/n"); +LL + writeln!(v, "Hello"); | error: using `write!()` with a format string that ends in a single newline --> $DIR/write_with_newline.rs:14:5 | -LL | write!(&mut v, "Hello {}/n", "world"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | write!(v, "Hello {}/n", "world"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: use `writeln!()` instead | -LL - write!(&mut v, "Hello {}/n", "world"); -LL + writeln!(&mut v, "Hello {}", "world"); +LL - write!(v, "Hello {}/n", "world"); +LL + writeln!(v, "Hello {}", "world"); | error: using `write!()` with a format string that ends in a single newline --> $DIR/write_with_newline.rs:15:5 | -LL | write!(&mut v, "Hello {} {}/n", "world", "#2"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | write!(v, "Hello {} {}/n", "world", "#2"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: use `writeln!()` instead | -LL - write!(&mut v, "Hello {} {}/n", "world", "#2"); -LL + writeln!(&mut v, "Hello {} {}", "world", "#2"); +LL - write!(v, "Hello {} {}/n", "world", "#2"); +LL + writeln!(v, "Hello {} {}", "world", "#2"); | error: using `write!()` with a format string that ends in a single newline --> $DIR/write_with_newline.rs:16:5 | -LL | write!(&mut v, "{}/n", 1265); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | write!(v, "{}/n", 1265); + | ^^^^^^^^^^^^^^^^^^^^^^^ | help: use `writeln!()` instead | -LL - write!(&mut v, "{}/n", 1265); -LL + writeln!(&mut v, "{}", 1265); +LL - write!(v, "{}/n", 1265); +LL + writeln!(v, "{}", 1265); | error: using `write!()` with a format string that ends in a single newline --> $DIR/write_with_newline.rs:17:5 | -LL | write!(&mut v, "/n"); - | ^^^^^^^^^^^^^^^^^^^^ +LL | write!(v, "/n"); + | ^^^^^^^^^^^^^^^ | help: use `writeln!()` instead | -LL - write!(&mut v, "/n"); -LL + writeln!(&mut v); +LL - write!(v, "/n"); +LL + writeln!(v); | error: using `write!()` with a format string that ends in a single newline --> $DIR/write_with_newline.rs:36:5 | -LL | write!(&mut v, "//n"); // should fail - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | write!(v, "//n"); // should fail + | ^^^^^^^^^^^^^^^^^ | help: use `writeln!()` instead | -LL - write!(&mut v, "//n"); // should fail -LL + writeln!(&mut v, "/"); // should fail +LL - write!(v, "//n"); // should fail +LL + writeln!(v, "/"); // should fail | error: using `write!()` with a format string that ends in a single newline --> $DIR/write_with_newline.rs:43:5 | LL | / write!( -LL | | &mut v, +LL | | v, LL | | " LL | | " LL | | ); @@ -84,7 +84,7 @@ LL | | ); help: use `writeln!()` instead | LL ~ writeln!( -LL | &mut v, +LL | v, LL ~ "" | @@ -92,7 +92,7 @@ error: using `write!()` with a format string that ends in a single newline --> $DIR/write_with_newline.rs:48:5 | LL | / write!( -LL | | &mut v, +LL | | v, LL | | r" LL | | " LL | | ); @@ -101,32 +101,32 @@ LL | | ); help: use `writeln!()` instead | LL ~ writeln!( -LL | &mut v, +LL | v, LL ~ r"" | error: using `write!()` with a format string that ends in a single newline --> $DIR/write_with_newline.rs:57:5 | -LL | write!(&mut v, "/r/n"); //~ ERROR - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | write!(v, "/r/n"); //~ ERROR + | ^^^^^^^^^^^^^^^^^^ | help: use `writeln!()` instead | -LL - write!(&mut v, "/r/n"); //~ ERROR -LL + writeln!(&mut v, "/r"); //~ ERROR +LL - write!(v, "/r/n"); //~ ERROR +LL + writeln!(v, "/r"); //~ ERROR | error: using `write!()` with a format string that ends in a single newline --> $DIR/write_with_newline.rs:58:5 | -LL | write!(&mut v, "foo/rbar/n"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | write!(v, "foo/rbar/n"); + | ^^^^^^^^^^^^^^^^^^^^^^^ | help: use `writeln!()` instead | -LL - write!(&mut v, "foo/rbar/n"); -LL + writeln!(&mut v, "foo/rbar"); +LL - write!(v, "foo/rbar/n"); +LL + writeln!(v, "foo/rbar"); | error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/writeln_empty_string.fixed b/src/tools/clippy/tests/ui/writeln_empty_string.fixed index c3ac15b0375..e7d94acd130 100644 --- a/src/tools/clippy/tests/ui/writeln_empty_string.fixed +++ b/src/tools/clippy/tests/ui/writeln_empty_string.fixed @@ -8,13 +8,13 @@ fn main() { let mut v = Vec::new(); // These should fail - writeln!(&mut v); + writeln!(v); let mut suggestion = Vec::new(); - writeln!(&mut suggestion); + writeln!(suggestion); // These should be fine - writeln!(&mut v); - writeln!(&mut v, " "); - write!(&mut v, ""); + writeln!(v); + writeln!(v, " "); + write!(v, ""); } diff --git a/src/tools/clippy/tests/ui/writeln_empty_string.rs b/src/tools/clippy/tests/ui/writeln_empty_string.rs index 9a8894b6c0d..662c62f0211 100644 --- a/src/tools/clippy/tests/ui/writeln_empty_string.rs +++ b/src/tools/clippy/tests/ui/writeln_empty_string.rs @@ -8,13 +8,13 @@ fn main() { let mut v = Vec::new(); // These should fail - writeln!(&mut v, ""); + writeln!(v, ""); let mut suggestion = Vec::new(); - writeln!(&mut suggestion, ""); + writeln!(suggestion, ""); // These should be fine - writeln!(&mut v); - writeln!(&mut v, " "); - write!(&mut v, ""); + writeln!(v); + writeln!(v, " "); + write!(v, ""); } diff --git a/src/tools/clippy/tests/ui/writeln_empty_string.stderr b/src/tools/clippy/tests/ui/writeln_empty_string.stderr index 99635229b3e..ac65aadfc0e 100644 --- a/src/tools/clippy/tests/ui/writeln_empty_string.stderr +++ b/src/tools/clippy/tests/ui/writeln_empty_string.stderr @@ -1,16 +1,16 @@ -error: using `writeln!(&mut v, "")` +error: using `writeln!(v, "")` --> $DIR/writeln_empty_string.rs:11:5 | -LL | writeln!(&mut v, ""); - | ^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(&mut v)` +LL | writeln!(v, ""); + | ^^^^^^^^^^^^^^^ help: replace it with: `writeln!(v)` | = note: `-D clippy::writeln-empty-string` implied by `-D warnings` -error: using `writeln!(&mut suggestion, "")` +error: using `writeln!(suggestion, "")` --> $DIR/writeln_empty_string.rs:14:5 | -LL | writeln!(&mut suggestion, ""); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(&mut suggestion)` +LL | writeln!(suggestion, ""); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(suggestion)` error: aborting due to 2 previous errors diff --git a/src/tools/clippy/util/gh-pages/index.html b/src/tools/clippy/util/gh-pages/index.html index 5b7e61a349d..83a200ca3c4 100644 --- a/src/tools/clippy/util/gh-pages/index.html +++ b/src/tools/clippy/util/gh-pages/index.html @@ -522,6 +522,11 @@ Otherwise, have a great day =^.^= } scrollToLintByURL($scope); + + setTimeout(function () { + var el = document.getElementById('filter-input'); + if (el) { el.focus() } + }, 0); }) .error(function (data) { $scope.error = data; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 22785013085..00221b07f74 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3498,10 +3498,12 @@ impl<'test> TestCx<'test> { // with placeholders as we do not want tests needing updated when compiler source code // changes. // eg. $SRC_DIR/libcore/mem.rs:323:14 becomes $SRC_DIR/libcore/mem.rs:LL:COL - normalized = Regex::new("SRC_DIR(.+):\\d+:\\d+(: \\d+:\\d+)?") - .unwrap() - .replace_all(&normalized, "SRC_DIR$1:LL:COL") - .into_owned(); + lazy_static! { + static ref SRC_DIR_RE: Regex = + Regex::new("SRC_DIR(.+):\\d+:\\d+(: \\d+:\\d+)?").unwrap(); + } + + normalized = SRC_DIR_RE.replace_all(&normalized, "SRC_DIR$1:LL:COL").into_owned(); normalized = Self::normalize_platform_differences(&normalized); normalized = normalized.replace("\t", "\\t"); // makes tabs visible @@ -3510,73 +3512,38 @@ impl<'test> TestCx<'test> { // since they duplicate actual errors and make the output hard to read. // This mirrors the regex in src/tools/tidy/src/style.rs, please update // both if either are changed. - normalized = - Regex::new("\\s*//(\\[.*\\])?~.*").unwrap().replace_all(&normalized, "").into_owned(); + lazy_static! { + static ref ANNOTATION_RE: Regex = Regex::new("\\s*//(\\[.*\\])?~.*").unwrap(); + } + + normalized = ANNOTATION_RE.replace_all(&normalized, "").into_owned(); + + // This code normalizes various hashes in v0 symbol mangling that is + // emitted in the ui and mir-opt tests. + lazy_static! { + static ref V0_CRATE_HASH_PREFIX_RE: Regex = + Regex::new(r"_R.*?Cs[0-9a-zA-Z]+_").unwrap(); + static ref V0_CRATE_HASH_RE: Regex = Regex::new(r"Cs[0-9a-zA-Z]+_").unwrap(); + } - // This code normalizes various hashes in both - // v0 and legacy symbol names that are emitted in - // the ui and mir-opt tests. - // - // Some tests still require normalization with headers. - const DEFID_HASH_REGEX: &str = r"\[[0-9a-z]{4}\]"; - const DEFID_HASH_PLACEHOLDER: &str = r"[HASH]"; - const V0_DEMANGLING_HASH_REGEX: &str = r"\[[0-9a-z]+\]"; - const V0_DEMANGLING_HASH_PLACEHOLDER: &str = r"[HASH]"; - const V0_CRATE_HASH_PREFIX_REGEX: &str = r"_R.*?Cs[0-9a-zA-Z]+_"; - const V0_CRATE_HASH_REGEX: &str = r"Cs[0-9a-zA-Z]+_"; const V0_CRATE_HASH_PLACEHOLDER: &str = r"CsCRATE_HASH_"; - const V0_BACK_REF_PREFIX_REGEX: &str = r"\(_R.*?B[0-9a-zA-Z]_"; - const V0_BACK_REF_REGEX: &str = r"B[0-9a-zA-Z]_"; - const V0_BACK_REF_PLACEHOLDER: &str = r"B<REF>_"; - const LEGACY_SYMBOL_HASH_REGEX: &str = r"h[\w]{16}E?\)"; - const LEGACY_SYMBOL_HASH_PLACEHOLDER: &str = r"h<SYMBOL_HASH>)"; - let test_name = self - .output_testname_unique() - .into_os_string() - .into_string() - .unwrap() - .split('.') - .next() - .unwrap() - .replace("-", "_"); - // Normalize `DefId` hashes - let defid_regex = format!("{}{}", test_name, DEFID_HASH_REGEX); - let defid_placeholder = format!("{}{}", test_name, DEFID_HASH_PLACEHOLDER); - normalized = Regex::new(&defid_regex) - .unwrap() - .replace_all(&normalized, defid_placeholder) - .into_owned(); - // Normalize v0 demangling hashes - let demangling_regex = format!("{}{}", test_name, V0_DEMANGLING_HASH_REGEX); - let demangling_placeholder = format!("{}{}", test_name, V0_DEMANGLING_HASH_PLACEHOLDER); - normalized = Regex::new(&demangling_regex) - .unwrap() - .replace_all(&normalized, demangling_placeholder) - .into_owned(); - // Normalize v0 crate hashes (see RFC 2603) - let symbol_mangle_prefix_re = Regex::new(V0_CRATE_HASH_PREFIX_REGEX).unwrap(); - if symbol_mangle_prefix_re.is_match(&normalized) { + if V0_CRATE_HASH_PREFIX_RE.is_match(&normalized) { // Normalize crate hash - normalized = Regex::new(V0_CRATE_HASH_REGEX) - .unwrap() - .replace_all(&normalized, V0_CRATE_HASH_PLACEHOLDER) - .into_owned(); + normalized = + V0_CRATE_HASH_RE.replace_all(&normalized, V0_CRATE_HASH_PLACEHOLDER).into_owned(); + } + + lazy_static! { + static ref V0_BACK_REF_PREFIX_RE: Regex = Regex::new(r"\(_R.*?B[0-9a-zA-Z]_").unwrap(); + static ref V0_BACK_REF_RE: Regex = Regex::new(r"B[0-9a-zA-Z]_").unwrap(); } - let back_ref_prefix_re = Regex::new(V0_BACK_REF_PREFIX_REGEX).unwrap(); - if back_ref_prefix_re.is_match(&normalized) { + + const V0_BACK_REF_PLACEHOLDER: &str = r"B<REF>_"; + if V0_BACK_REF_PREFIX_RE.is_match(&normalized) { // Normalize back references (see RFC 2603) - let back_ref_regex = format!("{}", V0_BACK_REF_REGEX); - let back_ref_placeholder = format!("{}", V0_BACK_REF_PLACEHOLDER); - normalized = Regex::new(&back_ref_regex) - .unwrap() - .replace_all(&normalized, back_ref_placeholder) - .into_owned(); + normalized = + V0_BACK_REF_RE.replace_all(&normalized, V0_BACK_REF_PLACEHOLDER).into_owned(); } - // Normalize legacy mangled symbols - normalized = Regex::new(LEGACY_SYMBOL_HASH_REGEX) - .unwrap() - .replace_all(&normalized, LEGACY_SYMBOL_HASH_PLACEHOLDER) - .into_owned(); // Custom normalization rules for rule in custom_rules { |
