From 38c557ca79908ef11aabf93ef6e15184ba8dd303 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 15 Nov 2023 11:44:48 +0100 Subject: [PATCH 001/734] Correct rustdoc section where we talk about rustdoc emitting errors on invalid code --- src/doc/rustdoc/src/advanced-features.md | 27 ++---------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md index 1733c8fc9a24..124c0da04f67 100644 --- a/src/doc/rustdoc/src/advanced-features.md +++ b/src/doc/rustdoc/src/advanced-features.md @@ -38,33 +38,10 @@ they will both appear in documentation. Rustdoc does not have a magic way to compile documentation 'as-if' you'd run it once for each platform (such a magic wand has been called the ['holy grail of rustdoc'][#1998]). Instead, it sees *all* of your code at once, the same way the Rust compiler would if you passed it -`--cfg doc`. However, Rustdoc has a trick up its sleeve to handle platform-specific code if it -*does* receive it. - -To document your crate, Rustdoc only needs to know the public signature of your functions. -In particular, it doesn't have to know how any of your functions are implemented, so it ignores -all type errors and name resolution errors with function bodies. Note that this does *not* -work for anything outside a function body: since Rustdoc documents your types, it has to -know what those types are! For example, this code will work regardless of the platform: - -```rust,ignore (platform-specific,rustdoc-specific-behavior) -pub fn f() { - use std::os::windows::ffi::OsStrExt; -} -``` - -but this will not, because the unknown type is part of the function signature: - -```rust,ignore (platform-specific,rustdoc-specific-behavior) -pub fn f() -> std::os::windows::ffi::EncodeWide<'static> { - unimplemented!() -} -``` - -For a more realistic example of code this allows, see [the rustdoc test suite][realistic-async]. +`--cfg doc`. The main difference is that rustdoc doesn't run all the compiler passes, meaning +that some invalid code won't emit an error. [#1998]: https://github.com/rust-lang/rust/issues/1998 -[realistic-async]: https://github.com/rust-lang/rust/blob/b146000e910ccd60bdcde89363cb6aa14ecc0d95/src/test/rustdoc-ui/error-in-impl-trait/realistic-async.rs ## Add aliases for an item in documentation search From a85700a1a8f5aa729bd19e5a2a78f8a80d623093 Mon Sep 17 00:00:00 2001 From: matt rice Date: Fri, 23 Feb 2024 16:05:28 -0800 Subject: [PATCH 002/734] Handle .init_array link_section specially on wasm --- compiler/rustc_codegen_llvm/src/consts.rs | 10 ++++++++-- compiler/rustc_hir_analysis/src/check/mod.rs | 20 +++++++++++++------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index ec2fb2c6e546..55477ff5d297 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -481,8 +481,14 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> { } // Wasm statics with custom link sections get special treatment as they - // go into custom sections of the wasm executable. - if self.tcx.sess.target.is_like_wasm { + // go into custom sections of the wasm executable. The exception to this + // is the `.init_array` section which are treated specially by the wasm linker. + if self.tcx.sess.target.is_like_wasm + && attrs + .link_section + .map(|link_section| !link_section.as_str().starts_with(".init_array")) + .unwrap_or(true) + { if let Some(section) = attrs.link_section { let section = llvm::LLVMMDStringInContext2( self.llcx, diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 36a92a4cf7cc..16a1a41eb19f 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -159,21 +159,27 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) { return; } - // For the wasm32 target statics with `#[link_section]` are placed into custom - // sections of the final output file, but this isn't link custom sections of - // other executable formats. Namely we can only embed a list of bytes, - // nothing with provenance (pointers to anything else). If any provenance - // show up, reject it here. + // For the wasm32 target statics with `#[link_section]` other than `.init_array` + // are placed into custom sections of the final output file, but this isn't link + // custom sections of other executable formats. Namely we can only embed a list + // of bytes, nothing with provenance (pointers to anything else). If any + // provenance show up, reject it here. // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is // the consumer's responsibility to ensure all bytes that have been read // have defined values. if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id()) && alloc.inner().provenance().ptrs().len() != 0 { - let msg = "statics with a custom `#[link_section]` must be a \ + if attrs + .link_section + .map(|link_section| !link_section.as_str().starts_with(".init_array")) + .unwrap_or(true) + { + let msg = "statics with a custom `#[link_section]` must be a \ simple list of bytes on the wasm target with no \ extra levels of indirection such as references"; - tcx.dcx().span_err(tcx.def_span(id), msg); + tcx.dcx().span_err(tcx.def_span(id), msg); + } } } From 62e29fe25b039b89ad76a6b9a94f8085eee934d9 Mon Sep 17 00:00:00 2001 From: Martin Geisler Date: Fri, 17 May 2024 11:54:21 +0200 Subject: [PATCH 003/734] Simplify environment variable examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I’ve found myself visiting the documentation for `std::env::vars` every few months, and every time I do, it is because I want to quickly get a snippet to print out all environment variables :-) So I think it could be nice to simplify the examples a little to make them self-contained. It is of course a style question if one should import a module a not, but I personally don’t import modules used just once in a code snippet. --- library/std/src/env.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 6f8ac17f12c7..b3428fb23ba7 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -120,11 +120,8 @@ pub struct VarsOs { /// # Examples /// /// ``` -/// use std::env; -/// -/// // We will iterate through the references to the element returned by -/// // env::vars(); -/// for (key, value) in env::vars() { +/// // Print all environment variables. +/// for (key, value) in std::env::vars() { /// println!("{key}: {value}"); /// } /// ``` @@ -150,11 +147,8 @@ pub fn vars() -> Vars { /// # Examples /// /// ``` -/// use std::env; -/// -/// // We will iterate through the references to the element returned by -/// // env::vars_os(); -/// for (key, value) in env::vars_os() { +/// // Print all environment variables. +/// for (key, value) in std::env::vars_os() { /// println!("{key:?}: {value:?}"); /// } /// ``` From 8d1958f0d27f2a3393f2d6fde9560356c78b5f60 Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Wed, 15 Nov 2023 19:46:42 +0000 Subject: [PATCH 004/734] Ambiguous Self lifetimes: don't elide. struct Concrete(u32); impl Concrete { fn m(self: &Box) -> &u32 { &self.0 } } resulted in a confusing error. impl Concrete { fn n(self: &Box<&Self>) -> &u32 { &self.0 } } resulted in no error or warning, despite apparent ambiguity over the elided lifetime. This commit changes two aspects of the behavior. Previously, when examining the self type, we considered lifetimes only if they were immediately adjacent to Self. We now consider lifetimes anywhere in the self type. Secondly, if more than one lifetime is discovered in the self type, we disregard it as a possible lifetime elision candidate. This is a compatibility break, and in fact has required some changes to tests which assumed the earlier behavior. Fixes https://github.com/rust-lang/rust/issues/117715 --- compiler/rustc_resolve/src/late.rs | 26 ++++--- tests/ui/self/elision/ref-assoc-async.rs | 6 +- tests/ui/self/elision/ref-assoc-async.stderr | 77 ++++++++++++++++++++ tests/ui/self/elision/ref-assoc.rs | 7 +- tests/ui/self/elision/ref-assoc.stderr | 77 ++++++++++++++++++++ tests/ui/self/elision/ref-self-multi.rs | 29 ++++++++ tests/ui/self/elision/ref-self.fixed | 7 ++ tests/ui/self/elision/ref-self.rs | 7 ++ tests/ui/self/elision/ref-self.stderr | 31 ++++++-- 9 files changed, 246 insertions(+), 21 deletions(-) create mode 100644 tests/ui/self/elision/ref-assoc-async.stderr create mode 100644 tests/ui/self/elision/ref-assoc.stderr create mode 100644 tests/ui/self/elision/ref-self-multi.rs diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 0f585aafdd5c..7c971e1f1bb9 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2132,13 +2132,15 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // Handle `self` specially. if index == 0 && has_self { let self_lifetime = self.find_lifetime_for_self(ty); - if let Set1::One(lifetime) = self_lifetime { + elision_lifetime = match self_lifetime { // We found `self` elision. - elision_lifetime = Elision::Self_(lifetime); - } else { + Set1::One(lifetime) => Elision::Self_(lifetime), + // `self` itself had ambiguous lifetimes, e.g. + // &Box<&Self> + Set1::Many => Elision::None, // We do not have `self` elision: disregard the `Elision::Param` that we may // have found. - elision_lifetime = Elision::None; + Set1::Empty => Elision::None, } } debug!("(resolving function / closure) recorded parameter"); @@ -2162,6 +2164,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { r: &'r Resolver<'a, 'tcx>, impl_self: Option, lifetime: Set1, + self_found: bool, } impl SelfVisitor<'_, '_, '_> { @@ -2185,9 +2188,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { impl<'a> Visitor<'a> for SelfVisitor<'_, '_, '_> { fn visit_ty(&mut self, ty: &'a Ty) { trace!("SelfVisitor considering ty={:?}", ty); - if let TyKind::Ref(lt, ref mt) = ty.kind - && self.is_self_ty(&mt.ty) - { + if self.is_self_ty(ty) { + trace!("SelfVisitor found Self"); + self.self_found = true; + } + if let TyKind::Ref(lt, _) = ty.kind { let lt_id = if let Some(lt) = lt { lt.id } else { @@ -2228,10 +2233,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _,) | Res::PrimTy(_) ) }); - let mut visitor = SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty }; + let mut visitor = + SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty, self_found: false }; visitor.visit_ty(ty); - trace!("SelfVisitor found={:?}", visitor.lifetime); - visitor.lifetime + trace!("SelfVisitor found={:?}, self_found={:?}", visitor.lifetime, visitor.self_found); + if visitor.self_found { visitor.lifetime } else { Set1::Empty } } /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved diff --git a/tests/ui/self/elision/ref-assoc-async.rs b/tests/ui/self/elision/ref-assoc-async.rs index 2af4f13a41b3..25deb25253d9 100644 --- a/tests/ui/self/elision/ref-assoc-async.rs +++ b/tests/ui/self/elision/ref-assoc-async.rs @@ -1,5 +1,4 @@ //@ edition:2018 -//@ check-pass #![allow(non_snake_case)] @@ -18,22 +17,27 @@ impl Trait for Struct { impl Struct { async fn ref_AssocType(self: &::AssocType, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } async fn box_ref_AssocType(self: Box<&::AssocType>, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } async fn pin_ref_AssocType(self: Pin<&::AssocType>, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } async fn box_box_ref_AssocType(self: Box::AssocType>>, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } async fn box_pin_ref_AssocType(self: Box::AssocType>>, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } } diff --git a/tests/ui/self/elision/ref-assoc-async.stderr b/tests/ui/self/elision/ref-assoc-async.stderr new file mode 100644 index 000000000000..cf54a86b45f0 --- /dev/null +++ b/tests/ui/self/elision/ref-assoc-async.stderr @@ -0,0 +1,77 @@ +error: lifetime may not live long enough + --> $DIR/ref-assoc-async.rs:19:9 + | +LL | async fn ref_AssocType(self: &::AssocType, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | async fn ref_AssocType<'a>(self: &'a ::AssocType, f: &'a u32) -> &u32 { + | ++++ ++ ++ + +error: lifetime may not live long enough + --> $DIR/ref-assoc-async.rs:24:9 + | +LL | async fn box_ref_AssocType(self: Box<&::AssocType>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | async fn box_ref_AssocType<'a>(self: Box<&'a ::AssocType>, f: &'a u32) -> &u32 { + | ++++ ++ ++ + +error: lifetime may not live long enough + --> $DIR/ref-assoc-async.rs:29:9 + | +LL | async fn pin_ref_AssocType(self: Pin<&::AssocType>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | async fn pin_ref_AssocType<'a>(self: Pin<&'a ::AssocType>, f: &'a u32) -> &u32 { + | ++++ ++ ++ + +error: lifetime may not live long enough + --> $DIR/ref-assoc-async.rs:34:9 + | +LL | async fn box_box_ref_AssocType(self: Box::AssocType>>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | async fn box_box_ref_AssocType<'a>(self: Box::AssocType>>, f: &'a u32) -> &u32 { + | ++++ ++ ++ + +error: lifetime may not live long enough + --> $DIR/ref-assoc-async.rs:39:9 + | +LL | async fn box_pin_ref_AssocType(self: Box::AssocType>>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | async fn box_pin_ref_AssocType<'a>(self: Box::AssocType>>, f: &'a u32) -> &u32 { + | ++++ ++ ++ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/self/elision/ref-assoc.rs b/tests/ui/self/elision/ref-assoc.rs index 8dc78d31d39e..01d2556df62d 100644 --- a/tests/ui/self/elision/ref-assoc.rs +++ b/tests/ui/self/elision/ref-assoc.rs @@ -1,5 +1,3 @@ -//@ check-pass - #![allow(non_snake_case)] use std::pin::Pin; @@ -17,22 +15,27 @@ impl Trait for Struct { impl Struct { fn ref_AssocType(self: &::AssocType, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } fn box_ref_AssocType(self: Box<&::AssocType>, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } fn pin_ref_AssocType(self: Pin<&::AssocType>, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } fn box_box_ref_AssocType(self: Box::AssocType>>, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } fn box_pin_ref_AssocType(self: Box::AssocType>>, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } } diff --git a/tests/ui/self/elision/ref-assoc.stderr b/tests/ui/self/elision/ref-assoc.stderr new file mode 100644 index 000000000000..7c8a1de95aec --- /dev/null +++ b/tests/ui/self/elision/ref-assoc.stderr @@ -0,0 +1,77 @@ +error: lifetime may not live long enough + --> $DIR/ref-assoc.rs:17:9 + | +LL | fn ref_AssocType(self: &::AssocType, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn ref_AssocType<'a>(self: &::AssocType, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ + +error: lifetime may not live long enough + --> $DIR/ref-assoc.rs:22:9 + | +LL | fn box_ref_AssocType(self: Box<&::AssocType>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_ref_AssocType<'a>(self: Box<&::AssocType>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ + +error: lifetime may not live long enough + --> $DIR/ref-assoc.rs:27:9 + | +LL | fn pin_ref_AssocType(self: Pin<&::AssocType>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn pin_ref_AssocType<'a>(self: Pin<&::AssocType>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ + +error: lifetime may not live long enough + --> $DIR/ref-assoc.rs:32:9 + | +LL | fn box_box_ref_AssocType(self: Box::AssocType>>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_box_ref_AssocType<'a>(self: Box::AssocType>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ + +error: lifetime may not live long enough + --> $DIR/ref-assoc.rs:37:9 + | +LL | fn box_pin_ref_AssocType(self: Box::AssocType>>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_pin_ref_AssocType<'a>(self: Box::AssocType>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/self/elision/ref-self-multi.rs b/tests/ui/self/elision/ref-self-multi.rs new file mode 100644 index 000000000000..438e08fb1af3 --- /dev/null +++ b/tests/ui/self/elision/ref-self-multi.rs @@ -0,0 +1,29 @@ +//@ run-pass + +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] +#![allow(unused)] + +use std::marker::PhantomData; +use std::ops::Deref; + +struct Struct { } + +struct Wrap(T, PhantomData

); + +impl Deref for Wrap { + type Target = T; + fn deref(&self) -> &T { &self.0 } +} + +impl Struct { + fn ref_box_ref_Self(self: &Box<&Self>, f: &u32) -> &u32 { + f + } + + fn ref_wrap_ref_Self(self: &Wrap<&Self, u32>, f: &u32) -> &u32 { + f + } +} + +fn main() { } diff --git a/tests/ui/self/elision/ref-self.fixed b/tests/ui/self/elision/ref-self.fixed index 8bf5a0bb2232..784ccb9efe2f 100644 --- a/tests/ui/self/elision/ref-self.fixed +++ b/tests/ui/self/elision/ref-self.fixed @@ -1,4 +1,6 @@ //@ run-rustfix +//@ edition:2018 + #![feature(arbitrary_self_types)] #![allow(non_snake_case, dead_code)] @@ -56,6 +58,11 @@ impl Struct { f //~^ ERROR lifetime may not live long enough } + + fn ref_box_Self<'a>(self: &Box, f: &'a u32) -> &'a u32 { + f + //~^ ERROR lifetime may not live long enough + } } fn main() {} diff --git a/tests/ui/self/elision/ref-self.rs b/tests/ui/self/elision/ref-self.rs index 4b4b8aa5b511..dbe441879cc5 100644 --- a/tests/ui/self/elision/ref-self.rs +++ b/tests/ui/self/elision/ref-self.rs @@ -1,4 +1,6 @@ //@ run-rustfix +//@ edition:2018 + #![feature(arbitrary_self_types)] #![allow(non_snake_case, dead_code)] @@ -56,6 +58,11 @@ impl Struct { f //~^ ERROR lifetime may not live long enough } + + fn ref_box_Self(self: &Box, f: &u32) -> &u32 { + f + //~^ ERROR lifetime may not live long enough + } } fn main() {} diff --git a/tests/ui/self/elision/ref-self.stderr b/tests/ui/self/elision/ref-self.stderr index c4ec8c55a003..64e7bfc1bb06 100644 --- a/tests/ui/self/elision/ref-self.stderr +++ b/tests/ui/self/elision/ref-self.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/ref-self.rs:24:9 + --> $DIR/ref-self.rs:26:9 | LL | fn ref_self(&self, f: &u32) -> &u32 { | - - let's call the lifetime of this reference `'1` @@ -14,7 +14,7 @@ LL | fn ref_self<'a>(&self, f: &'a u32) -> &'a u32 { | ++++ ++ ++ error: lifetime may not live long enough - --> $DIR/ref-self.rs:31:9 + --> $DIR/ref-self.rs:33:9 | LL | fn ref_Self(self: &Self, f: &u32) -> &u32 { | - - let's call the lifetime of this reference `'1` @@ -29,7 +29,7 @@ LL | fn ref_Self<'a>(self: &Self, f: &'a u32) -> &'a u32 { | ++++ ++ ++ error: lifetime may not live long enough - --> $DIR/ref-self.rs:36:9 + --> $DIR/ref-self.rs:38:9 | LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { | - - let's call the lifetime of this reference `'1` @@ -44,7 +44,7 @@ LL | fn box_ref_Self<'a>(self: Box<&Self>, f: &'a u32) -> &'a u32 { | ++++ ++ ++ error: lifetime may not live long enough - --> $DIR/ref-self.rs:41:9 + --> $DIR/ref-self.rs:43:9 | LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { | - - let's call the lifetime of this reference `'1` @@ -59,7 +59,7 @@ LL | fn pin_ref_Self<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 { | ++++ ++ ++ error: lifetime may not live long enough - --> $DIR/ref-self.rs:46:9 + --> $DIR/ref-self.rs:48:9 | LL | fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { | - - let's call the lifetime of this reference `'1` @@ -74,7 +74,7 @@ LL | fn box_box_ref_Self<'a>(self: Box>, f: &'a u32) -> &'a u32 { | ++++ ++ ++ error: lifetime may not live long enough - --> $DIR/ref-self.rs:51:9 + --> $DIR/ref-self.rs:53:9 | LL | fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { | - - let's call the lifetime of this reference `'1` @@ -89,7 +89,7 @@ LL | fn box_pin_ref_Self<'a>(self: Box>, f: &'a u32) -> &'a u32 { | ++++ ++ ++ error: lifetime may not live long enough - --> $DIR/ref-self.rs:56:9 + --> $DIR/ref-self.rs:58:9 | LL | fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 { | - - let's call the lifetime of this reference `'1` @@ -103,5 +103,20 @@ help: consider introducing a named lifetime parameter and update trait if needed LL | fn wrap_ref_Self_Self<'a>(self: Wrap<&Self, Self>, f: &'a u8) -> &'a u8 { | ++++ ++ ++ -error: aborting due to 7 previous errors +error: lifetime may not live long enough + --> $DIR/ref-self.rs:63:9 + | +LL | fn ref_box_Self(self: &Box, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn ref_box_Self<'a>(self: &Box, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ + +error: aborting due to 8 previous errors From e62599f8569509e5ebbea407d81f77fd0a9ca01b Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Tue, 9 Jan 2024 17:32:32 +0000 Subject: [PATCH 005/734] Do not elide if there's ambiguity in self lifetime. This makes a small change as requested in code review, such that if there's ambiguity in the self lifetime, we avoid lifetime elision entirely instead of considering using lifetimes from any of the other parameters. For example, impl Something { fn method(self: &Box<&Self>, something_else: &u32) -> &u32 { ... } } in standard Rust would have assumed the return lifetime was that of &Self; with this PR prior to this commit would have chosen the lifetime of 'something_else', and after this commit would give an error message explaining that the lifetime is ambiguous. --- compiler/rustc_resolve/src/late.rs | 6 +- .../self/elision/multiple-ref-self-async.rs | 6 +- .../elision/multiple-ref-self-async.stderr | 63 +++++++++++++++++++ tests/ui/self/elision/multiple-ref-self.rs | 7 ++- .../ui/self/elision/multiple-ref-self.stderr | 63 +++++++++++++++++++ tests/ui/self/elision/ref-self-multi.rs | 4 +- tests/ui/self/elision/ref-self-multi.stderr | 27 ++++++++ 7 files changed, 169 insertions(+), 7 deletions(-) create mode 100644 tests/ui/self/elision/multiple-ref-self-async.stderr create mode 100644 tests/ui/self/elision/multiple-ref-self.stderr create mode 100644 tests/ui/self/elision/ref-self-multi.stderr diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 7c971e1f1bb9..eb6827c85ec9 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2136,8 +2136,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // We found `self` elision. Set1::One(lifetime) => Elision::Self_(lifetime), // `self` itself had ambiguous lifetimes, e.g. - // &Box<&Self> - Set1::Many => Elision::None, + // &Box<&Self>. In this case we won't consider + // taking an alternative parameter lifetime; just avoid elision + // entirely. + Set1::Many => Elision::Err, // We do not have `self` elision: disregard the `Elision::Param` that we may // have found. Set1::Empty => Elision::None, diff --git a/tests/ui/self/elision/multiple-ref-self-async.rs b/tests/ui/self/elision/multiple-ref-self-async.rs index fb77f91396ca..f63b455901ee 100644 --- a/tests/ui/self/elision/multiple-ref-self-async.rs +++ b/tests/ui/self/elision/multiple-ref-self-async.rs @@ -1,4 +1,3 @@ -//@ check-pass //@ edition:2018 #![feature(arbitrary_self_types)] @@ -21,22 +20,27 @@ impl Struct { // Test using multiple `&Self`: async fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 { + //~^ ERROR missing lifetime specifier f } async fn box_wrap_ref_Self_ref_Self(self: Box>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier f } async fn pin_wrap_ref_Self_ref_Self(self: Pin>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier f } async fn box_box_wrap_ref_Self_ref_Self(self: Box>>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier f } async fn box_pin_wrap_ref_Self_ref_Self(self: Box>>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier f } } diff --git a/tests/ui/self/elision/multiple-ref-self-async.stderr b/tests/ui/self/elision/multiple-ref-self-async.stderr new file mode 100644 index 000000000000..e2abc7c1e785 --- /dev/null +++ b/tests/ui/self/elision/multiple-ref-self-async.stderr @@ -0,0 +1,63 @@ +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self-async.rs:22:74 + | +LL | async fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 { + | ------------------ --- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | async fn wrap_ref_Self_ref_Self<'a>(self: Wrap<&'a Self, &'a Self>, f: &'a u8) -> &'a u8 { + | ++++ ++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self-async.rs:27:84 + | +LL | async fn box_wrap_ref_Self_ref_Self(self: Box>, f: &u32) -> &u32 { + | ----------------------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | async fn box_wrap_ref_Self_ref_Self<'a>(self: Box>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self-async.rs:32:84 + | +LL | async fn pin_wrap_ref_Self_ref_Self(self: Pin>, f: &u32) -> &u32 { + | ----------------------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | async fn pin_wrap_ref_Self_ref_Self<'a>(self: Pin>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self-async.rs:37:93 + | +LL | async fn box_box_wrap_ref_Self_ref_Self(self: Box>>, f: &u32) -> &u32 { + | ---------------------------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | async fn box_box_wrap_ref_Self_ref_Self<'a>(self: Box>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self-async.rs:42:93 + | +LL | async fn box_pin_wrap_ref_Self_ref_Self(self: Box>>, f: &u32) -> &u32 { + | ---------------------------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | async fn box_pin_wrap_ref_Self_ref_Self<'a>(self: Box>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/self/elision/multiple-ref-self.rs b/tests/ui/self/elision/multiple-ref-self.rs index 01d6bb47c045..dd9b138051d0 100644 --- a/tests/ui/self/elision/multiple-ref-self.rs +++ b/tests/ui/self/elision/multiple-ref-self.rs @@ -1,5 +1,3 @@ -//@ check-pass - #![feature(arbitrary_self_types)] #![allow(non_snake_case)] @@ -20,22 +18,27 @@ impl Struct { // Test using multiple `&Self`: fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 { + //~^ ERROR missing lifetime specifier f } fn box_wrap_ref_Self_ref_Self(self: Box>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier f } fn pin_wrap_ref_Self_ref_Self(self: Pin>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier f } fn box_box_wrap_ref_Self_ref_Self(self: Box>>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier f } fn box_pin_wrap_ref_Self_ref_Self(self: Box>>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier f } } diff --git a/tests/ui/self/elision/multiple-ref-self.stderr b/tests/ui/self/elision/multiple-ref-self.stderr new file mode 100644 index 000000000000..24d74d352e48 --- /dev/null +++ b/tests/ui/self/elision/multiple-ref-self.stderr @@ -0,0 +1,63 @@ +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self.rs:20:68 + | +LL | fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 { + | ------------------ --- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | fn wrap_ref_Self_ref_Self<'a>(self: Wrap<&'a Self, &'a Self>, f: &'a u8) -> &'a u8 { + | ++++ ++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self.rs:25:78 + | +LL | fn box_wrap_ref_Self_ref_Self(self: Box>, f: &u32) -> &u32 { + | ----------------------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | fn box_wrap_ref_Self_ref_Self<'a>(self: Box>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self.rs:30:78 + | +LL | fn pin_wrap_ref_Self_ref_Self(self: Pin>, f: &u32) -> &u32 { + | ----------------------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | fn pin_wrap_ref_Self_ref_Self<'a>(self: Pin>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self.rs:35:87 + | +LL | fn box_box_wrap_ref_Self_ref_Self(self: Box>>, f: &u32) -> &u32 { + | ---------------------------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | fn box_box_wrap_ref_Self_ref_Self<'a>(self: Box>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self.rs:40:87 + | +LL | fn box_pin_wrap_ref_Self_ref_Self(self: Box>>, f: &u32) -> &u32 { + | ---------------------------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | fn box_pin_wrap_ref_Self_ref_Self<'a>(self: Box>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/self/elision/ref-self-multi.rs b/tests/ui/self/elision/ref-self-multi.rs index 438e08fb1af3..ed431a9c852d 100644 --- a/tests/ui/self/elision/ref-self-multi.rs +++ b/tests/ui/self/elision/ref-self-multi.rs @@ -1,5 +1,3 @@ -//@ run-pass - #![feature(arbitrary_self_types)] #![allow(non_snake_case)] #![allow(unused)] @@ -18,10 +16,12 @@ impl Deref for Wrap { impl Struct { fn ref_box_ref_Self(self: &Box<&Self>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier f } fn ref_wrap_ref_Self(self: &Wrap<&Self, u32>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier f } } diff --git a/tests/ui/self/elision/ref-self-multi.stderr b/tests/ui/self/elision/ref-self-multi.stderr new file mode 100644 index 000000000000..7e0451aa0d5c --- /dev/null +++ b/tests/ui/self/elision/ref-self-multi.stderr @@ -0,0 +1,27 @@ +error[E0106]: missing lifetime specifier + --> $DIR/ref-self-multi.rs:18:56 + | +LL | fn ref_box_ref_Self(self: &Box<&Self>, f: &u32) -> &u32 { + | ----------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | fn ref_box_ref_Self<'a>(self: &'a Box<&'a Self>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/ref-self-multi.rs:23:63 + | +LL | fn ref_wrap_ref_Self(self: &Wrap<&Self, u32>, f: &u32) -> &u32 { + | ----------------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | fn ref_wrap_ref_Self<'a>(self: &'a Wrap<&'a Self, u32>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0106`. From 6287c94fa131208111a26886d1aca81183e9eba0 Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Wed, 22 May 2024 15:58:00 +0000 Subject: [PATCH 006/734] Adjust crash bug to still reproduce. This test reproduces a rustc ICE. Unfortunately, the changes to lifetime elision mask the original ICE bug by making this function signature illegal. However, by simplifying the signature we can regain the original ICE. --- tests/crashes/122903-1.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/crashes/122903-1.rs b/tests/crashes/122903-1.rs index 9323c435851e..0953962ed9ef 100644 --- a/tests/crashes/122903-1.rs +++ b/tests/crashes/122903-1.rs @@ -1,7 +1,7 @@ //@ known-bug: #122903 impl Struct { - async fn box_box_ref_Struct( - self: Box>)>>, + fn box_box_ref_Struct( + self: impl FnMut(Box), ) -> &u32 { f } From 8c1777750bce6329a3ce1268c0f6f49b7842f7d2 Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Fri, 31 May 2024 11:03:37 +0000 Subject: [PATCH 007/734] Remove duplicative test. I think that this test is supposed to be a treereduced version of 122903-1.rs, but is actually identical. --- tests/crashes/122903-2.rs | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 tests/crashes/122903-2.rs diff --git a/tests/crashes/122903-2.rs b/tests/crashes/122903-2.rs deleted file mode 100644 index 0d5d93014c18..000000000000 --- a/tests/crashes/122903-2.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: #122903 - -impl Struct { - async fn box_box_ref_Struct( - self: Box>)>> - ) -> &u32 { - f - } -} From 24ce341185d929e0c3f14cce73ce7aac9ede0bf8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 2 Jun 2024 16:43:29 +0200 Subject: [PATCH 008/734] from_ref, from_mut: clarify domain of quantification --- library/core/src/ptr/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 8e3447d0b1b2..f1a1b1a41493 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -777,8 +777,8 @@ where /// Convert a reference to a raw pointer. /// -/// This is equivalent to `r as *const T`, but is a bit safer since it will never silently change -/// type or mutability, in particular if the code is refactored. +/// For `r: &T`, `from_ref(r)` is equivalent to `r as *const T`, but is a bit safer since it will +/// never silently change type or mutability, in particular if the code is refactored. #[inline(always)] #[must_use] #[stable(feature = "ptr_from_ref", since = "1.76.0")] @@ -791,8 +791,8 @@ pub const fn from_ref(r: &T) -> *const T { /// Convert a mutable reference to a raw pointer. /// -/// This is equivalent to `r as *mut T`, but is a bit safer since it will never silently change -/// type or mutability, in particular if the code is refactored. +/// For `r: &mut T`, `from_mut(r)` is equivalent to `r as *mut T`, but is a bit safer since it will +/// never silently change type or mutability, in particular if the code is refactored. #[inline(always)] #[must_use] #[stable(feature = "ptr_from_ref", since = "1.76.0")] From fa58d1bef832151a97d1f7b763a530b287bfb787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kr=C3=B6ger?= Date: Mon, 3 Jun 2024 22:56:25 +0200 Subject: [PATCH 009/734] Windows: Use futex implementation for `Once` Keep the queue implementation for win7. Inspired by PR #121956 --- library/std/src/sys/sync/once/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/sync/once/mod.rs b/library/std/src/sys/sync/once/mod.rs index 61b29713fa1a..0e38937b1219 100644 --- a/library/std/src/sys/sync/once/mod.rs +++ b/library/std/src/sys/sync/once/mod.rs @@ -9,6 +9,7 @@ cfg_if::cfg_if! { if #[cfg(any( + all(target_os = "windows", not(target_vendor="win7")), target_os = "linux", target_os = "android", all(target_arch = "wasm32", target_feature = "atomics"), From 64e7337be596cb12aa8c7f593a1fe5d17ab089ca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 4 Jun 2024 07:37:24 +0200 Subject: [PATCH 010/734] more explicitly state the basic rules of working with the obtained raw pointers --- library/core/src/ptr/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index f1a1b1a41493..c6af6617bab7 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -779,6 +779,15 @@ where /// /// For `r: &T`, `from_ref(r)` is equivalent to `r as *const T`, but is a bit safer since it will /// never silently change type or mutability, in particular if the code is refactored. +/// +/// The caller must ensure that the pointee outlives the pointer this function returns, or else it +/// will end up pointing to garbage. +/// +/// The caller must also ensure that the memory the pointer (non-transitively) points to is never +/// written to (except inside an `UnsafeCell`) using this pointer or any pointer derived from it. If +/// you need to mutate the pointee, use [`from_mut`]`. Specifically, to turn a mutable reference `m: +/// &mut T` into `*const T`, prefer `from_mut(m).cast_const()` to obtain a pointer that can later be +/// used for mutation. #[inline(always)] #[must_use] #[stable(feature = "ptr_from_ref", since = "1.76.0")] @@ -791,6 +800,9 @@ pub const fn from_ref(r: &T) -> *const T { /// Convert a mutable reference to a raw pointer. /// +/// The caller must ensure that the pointee outlives the pointer this function returns, or else it +/// will end up pointing to garbage. +/// /// For `r: &mut T`, `from_mut(r)` is equivalent to `r as *mut T`, but is a bit safer since it will /// never silently change type or mutability, in particular if the code is refactored. #[inline(always)] From c713caff6d952f12acfdf55d1a2fd9c6a0904f31 Mon Sep 17 00:00:00 2001 From: coekjan Date: Tue, 4 Jun 2024 16:09:23 +0800 Subject: [PATCH 011/734] update tracking issue for `const_binary_heap_new_in` --- library/alloc/src/collections/binary_heap/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index 0b04fb4a2744..8d644ec8ee8c 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -487,7 +487,7 @@ impl BinaryHeap { /// heap.push(4); /// ``` #[unstable(feature = "allocator_api", issue = "32838")] - #[rustc_const_unstable(feature = "const_binary_heap_new_in", issue = "112353")] + #[rustc_const_unstable(feature = "const_binary_heap_new_in", issue = "125961")] #[must_use] pub const fn new_in(alloc: A) -> BinaryHeap { BinaryHeap { data: Vec::new_in(alloc) } From c20a90f2b87bf935d7e62124cf0660839813f1a9 Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Tue, 4 Jun 2024 15:06:25 +0000 Subject: [PATCH 012/734] Add additional tests. --- .../elision/ignore-non-reference-lifetimes.rs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/ui/self/elision/ignore-non-reference-lifetimes.rs diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.rs b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs new file mode 100644 index 000000000000..f7f61b8c8106 --- /dev/null +++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs @@ -0,0 +1,22 @@ +//@ check-pass + +struct Foo<'a>(&'a str); + +impl<'b> Foo<'b> { + fn a<'a>(self: Self, a: &'a str) -> &str { + a + } + fn b<'a>(self: Foo<'b>, a: &'a str) -> &str { + a + } +} + +struct Foo2<'a>(&'a u32); +impl<'a> Foo2<'a> { + fn foo(self: &Self) -> &u32 { self.0 } // ok + fn bar(self: &Foo2<'a>) -> &u32 { self.0 } // ok (do not look into `Foo`) + fn baz2(self: Self, arg: &u32) -> &u32 { arg } // use lt from `arg` + fn baz3(self: Foo2<'a>, arg: &u32) -> &u32 { arg } // use lt from `arg` +} + +fn main() {} From 386838d69fc404da44ce11537a2cc640683e4742 Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Wed, 5 Jun 2024 14:19:20 +0000 Subject: [PATCH 013/734] Additional test due to Pin<&Self> discovery --- tests/ui/self/elision/no-shadow-pin-self.rs | 17 ++++++++++ .../ui/self/elision/no-shadow-pin-self.stderr | 32 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 tests/ui/self/elision/no-shadow-pin-self.rs create mode 100644 tests/ui/self/elision/no-shadow-pin-self.stderr diff --git a/tests/ui/self/elision/no-shadow-pin-self.rs b/tests/ui/self/elision/no-shadow-pin-self.rs new file mode 100644 index 000000000000..e390b869ca7b --- /dev/null +++ b/tests/ui/self/elision/no-shadow-pin-self.rs @@ -0,0 +1,17 @@ +use std::pin::Pin; +trait Trait { + fn method<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 { + f + } +} + +impl

Trait for Pin

{ + // This should not hide `&Self`, which would cause this to compile. + fn method(self: Pin<&Self>, f: &u32) -> &u32 { + //~^ ERROR `impl` item signature doesn't match `trait` + f + //~^ ERROR lifetime may not live long enough + } +} + +fn main() {} diff --git a/tests/ui/self/elision/no-shadow-pin-self.stderr b/tests/ui/self/elision/no-shadow-pin-self.stderr new file mode 100644 index 000000000000..23485e9de79b --- /dev/null +++ b/tests/ui/self/elision/no-shadow-pin-self.stderr @@ -0,0 +1,32 @@ +error: `impl` item signature doesn't match `trait` item signature + --> $DIR/no-shadow-pin-self.rs:10:5 + | +LL | fn method<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 { + | ------------------------------------------------------ expected `fn(Pin<&'1 Pin

>, &'a u32) -> &'a u32` +... +LL | fn method(self: Pin<&Self>, f: &u32) -> &u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(Pin<&'1 Pin

>, &'2 u32) -> &'1 u32` + | + = note: expected signature `fn(Pin<&'1 Pin

>, &'a u32) -> &'a u32` + found signature `fn(Pin<&'1 Pin

>, &'2 u32) -> &'1 u32` + = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` + = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output + +error: lifetime may not live long enough + --> $DIR/no-shadow-pin-self.rs:12:9 + | +LL | fn method(self: Pin<&Self>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn method<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ + +error: aborting due to 2 previous errors + From 05b7f282e8a883005237833f3bbc972072111e74 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 6 Jun 2024 08:04:34 +0200 Subject: [PATCH 014/734] less garbage, more examples --- library/alloc/src/vec/mod.rs | 4 +- library/core/src/ptr/mod.rs | 82 ++++++++++++++++++++++++++++++++--- library/core/src/slice/mod.rs | 4 +- 3 files changed, 79 insertions(+), 11 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index aa9b632cbed9..7ecc8855dbc6 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1276,7 +1276,7 @@ impl Vec { /// valid for zero sized reads if the vector didn't allocate. /// /// The caller must ensure that the vector outlives the pointer this - /// function returns, or else it will end up pointing to garbage. + /// function returns, or else it will end up dangling. /// Modifying the vector may cause its buffer to be reallocated, /// which would also make any pointers to it invalid. /// @@ -1336,7 +1336,7 @@ impl Vec { /// raw pointer valid for zero sized reads if the vector didn't allocate. /// /// The caller must ensure that the vector outlives the pointer this - /// function returns, or else it will end up pointing to garbage. + /// function returns, or else it will end up dangling. /// Modifying the vector may cause its buffer to be reallocated, /// which would also make any pointers to it invalid. /// diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index c6af6617bab7..0a20b3c04c8e 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -777,17 +777,51 @@ where /// Convert a reference to a raw pointer. /// -/// For `r: &T`, `from_ref(r)` is equivalent to `r as *const T`, but is a bit safer since it will -/// never silently change type or mutability, in particular if the code is refactored. +/// For `r: &T`, `from_ref(r)` is equivalent to `r as *const T` (except for the caveat noted below), +/// but is a bit safer since it will never silently change type or mutability, in particular if the +/// code is refactored. /// /// The caller must ensure that the pointee outlives the pointer this function returns, or else it -/// will end up pointing to garbage. +/// will end up dangling. /// /// The caller must also ensure that the memory the pointer (non-transitively) points to is never /// written to (except inside an `UnsafeCell`) using this pointer or any pointer derived from it. If /// you need to mutate the pointee, use [`from_mut`]`. Specifically, to turn a mutable reference `m: /// &mut T` into `*const T`, prefer `from_mut(m).cast_const()` to obtain a pointer that can later be /// used for mutation. +/// +/// ## Interaction with lifetime extension +/// +/// Note that this has subtle interactions with the rules for lifetime extension of temporaries in +/// tail expressions. This code is valid, albeit in a non-obvious way: +/// ```rust +/// # type T = i32; +/// # fn foo() -> T { 42 } +/// // The temporary holding the return value of `foo` has its lifetime extended, +/// // because the surrounding expression involves no function call. +/// let p = &foo() as *const T; +/// unsafe { p.read() }; +/// ``` +/// Naively replacing the cast with `from_ref` is not valid: +/// ```rust,no_run +/// # use std::ptr; +/// # type T = i32; +/// # fn foo() -> T { 42 } +/// // The temporary holding the return value of `foo` does *not* have its lifetime extended, +/// // because the surrounding expression involves no function call. +/// let p = ptr::from_ref(&foo()); +/// unsafe { p.read() }; // UB! Reading from a dangling pointer ⚠️ +/// ``` +/// The recommended way to write this code is to avoid relying on lifetime extension +/// when raw pointers are involved: +/// ```rust +/// # use std::ptr; +/// # type T = i32; +/// # fn foo() -> T { 42 } +/// let x = foo(); +/// let p = ptr::from_ref(&x); +/// unsafe { p.read() }; +/// ``` #[inline(always)] #[must_use] #[stable(feature = "ptr_from_ref", since = "1.76.0")] @@ -800,11 +834,45 @@ pub const fn from_ref(r: &T) -> *const T { /// Convert a mutable reference to a raw pointer. /// -/// The caller must ensure that the pointee outlives the pointer this function returns, or else it -/// will end up pointing to garbage. +/// For `r: &mut T`, `from_mut(r)` is equivalent to `r as *mut T` (except for the caveat noted +/// below), but is a bit safer since it will never silently change type or mutability, in particular +/// if the code is refactored. /// -/// For `r: &mut T`, `from_mut(r)` is equivalent to `r as *mut T`, but is a bit safer since it will -/// never silently change type or mutability, in particular if the code is refactored. +/// The caller must ensure that the pointee outlives the pointer this function returns, or else it +/// will end up dangling. +/// +/// ## Interaction with lifetime extension +/// +/// Note that this has subtle interactions with the rules for lifetime extension of temporaries in +/// tail expressions. This code is valid, albeit in a non-obvious way: +/// ```rust +/// # type T = i32; +/// # fn foo() -> T { 42 } +/// // The temporary holding the return value of `foo` has its lifetime extended, +/// // because the surrounding expression involves no function call. +/// let p = &mut foo() as *mut T; +/// unsafe { p.write(T::default()) }; +/// ``` +/// Naively replacing the cast with `from_mut` is not valid: +/// ```rust,no_run +/// # use std::ptr; +/// # type T = i32; +/// # fn foo() -> T { 42 } +/// // The temporary holding the return value of `foo` does *not* have its lifetime extended, +/// // because the surrounding expression involves no function call. +/// let p = ptr::from_mut(&mut foo()); +/// unsafe { p.write(T::default()) }; // UB! Writing to a dangling pointer ⚠️ +/// ``` +/// The recommended way to write this code is to avoid relying on lifetime extension +/// when raw pointers are involved: +/// ```rust +/// # use std::ptr; +/// # type T = i32; +/// # fn foo() -> T { 42 } +/// let mut x = foo(); +/// let p = ptr::from_mut(&mut x); +/// unsafe { p.write(T::default()) }; +/// ``` #[inline(always)] #[must_use] #[stable(feature = "ptr_from_ref", since = "1.76.0")] diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 503107c74803..8ada77c34b35 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -731,7 +731,7 @@ impl [T] { /// Returns a raw pointer to the slice's buffer. /// /// The caller must ensure that the slice outlives the pointer this - /// function returns, or else it will end up pointing to garbage. + /// function returns, or else it will end up dangling. /// /// The caller must also ensure that the memory the pointer (non-transitively) points to /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer @@ -766,7 +766,7 @@ impl [T] { /// Returns an unsafe mutable pointer to the slice's buffer. /// /// The caller must ensure that the slice outlives the pointer this - /// function returns, or else it will end up pointing to garbage. + /// function returns, or else it will end up dangling. /// /// Modifying the container referenced by this slice may cause its buffer /// to be reallocated, which would also make any pointers to it invalid. From a22130e1e0ed619b53bfe15c50c9c7f7400c3a5a Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Mon, 10 Jun 2024 08:44:44 +0000 Subject: [PATCH 015/734] Elision: consider lifetimes from &T iff T has Self Change the algorithm which determines whether a self lifetime can be used for return type lifetime elision, such that we consider lifetimes attached to any reference in the self type, so long as Self can be found anywhere inside the type of that reference. --- compiler/rustc_resolve/src/late.rs | 64 +++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index eb6827c85ec9..c3243f68e1b2 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2162,16 +2162,55 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { /// List all the lifetimes that appear in the provided type. fn find_lifetime_for_self(&self, ty: &'ast Ty) -> Set1 { - struct SelfVisitor<'r, 'a, 'tcx> { + /// Visits a type to find all the &references, and determines the + /// set of lifetimes for all of those references where the referent + /// contains Self. + struct FindReferenceVisitor<'r, 'a, 'tcx> { r: &'r Resolver<'a, 'tcx>, impl_self: Option, lifetime: Set1, + } + + impl<'a> Visitor<'a> for FindReferenceVisitor<'_, '_, '_> { + fn visit_ty(&mut self, ty: &'a Ty) { + trace!("FindReferenceVisitor considering ty={:?}", ty); + if let TyKind::Ref(lt, _) = ty.kind { + // See if anything inside the &thing contains Self + let mut visitor = + SelfVisitor { r: self.r, impl_self: self.impl_self, self_found: false }; + visitor.visit_ty(ty); + trace!("FindReferenceVisitor: SelfVisitor self_found={:?}", visitor.self_found); + if visitor.self_found { + let lt_id = if let Some(lt) = lt { + lt.id + } else { + let res = self.r.lifetimes_res_map[&ty.id]; + let LifetimeRes::ElidedAnchor { start, .. } = res else { bug!() }; + start + }; + let lt_res = self.r.lifetimes_res_map[<_id]; + trace!("FindReferenceVisitor inserting res={:?}", lt_res); + self.lifetime.insert(lt_res); + } + } + visit::walk_ty(self, ty) + } + + // A type may have an expression as a const generic argument. + // We do not want to recurse into those. + fn visit_expr(&mut self, _: &'a Expr) {} + } + + /// Visitor which checks the referent of a &Thing to see if the + /// Thing contains Self + struct SelfVisitor<'r, 'a, 'tcx> { + r: &'r Resolver<'a, 'tcx>, + impl_self: Option, self_found: bool, } impl SelfVisitor<'_, '_, '_> { - // Look for `self: &'a Self` - also desugared from `&'a self`, - // and if that matches, use it for elision and return early. + // Look for `self: &'a Self` - also desugared from `&'a self` fn is_self_ty(&self, ty: &Ty) -> bool { match ty.kind { TyKind::ImplicitSelf => true, @@ -2194,18 +2233,6 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { trace!("SelfVisitor found Self"); self.self_found = true; } - if let TyKind::Ref(lt, _) = ty.kind { - let lt_id = if let Some(lt) = lt { - lt.id - } else { - let res = self.r.lifetimes_res_map[&ty.id]; - let LifetimeRes::ElidedAnchor { start, .. } = res else { bug!() }; - start - }; - let lt_res = self.r.lifetimes_res_map[<_id]; - trace!("SelfVisitor inserting res={:?}", lt_res); - self.lifetime.insert(lt_res); - } visit::walk_ty(self, ty) } @@ -2235,11 +2262,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _,) | Res::PrimTy(_) ) }); - let mut visitor = - SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty, self_found: false }; + let mut visitor = FindReferenceVisitor { r: self.r, impl_self, lifetime: Set1::Empty }; visitor.visit_ty(ty); - trace!("SelfVisitor found={:?}, self_found={:?}", visitor.lifetime, visitor.self_found); - if visitor.self_found { visitor.lifetime } else { Set1::Empty } + trace!("FindReferenceVisitor found={:?}", visitor.lifetime); + visitor.lifetime } /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved From c4391b326edbf4bcf374c9891fb0bfc2bc33531a Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 11 Jun 2024 13:24:35 +0200 Subject: [PATCH 016/734] Skip fast path for dec2flt when optimize_for_size --- library/core/src/num/dec2flt/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index a4bc8b1c9b0c..c10bf797b57f 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -250,8 +250,10 @@ pub fn dec2flt(s: &str) -> Result { None => return Err(pfe_invalid()), }; num.negative = negative; - if let Some(value) = num.try_fast_path::() { - return Ok(value); + if cfg!(not(feature = "optimize_for_size")) { + if let Some(value) = num.try_fast_path::() { + return Ok(value); + } } // If significant digits were truncated, then we can have rounding error From 1de046fa24a8a0304be274963b43819cfe56013a Mon Sep 17 00:00:00 2001 From: matt rice Date: Fri, 14 Jun 2024 07:53:37 -0700 Subject: [PATCH 017/734] Update for review --- compiler/rustc_hir_analysis/src/check/mod.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 16a1a41eb19f..9ce60bffea62 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -160,20 +160,35 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) { } // For the wasm32 target statics with `#[link_section]` other than `.init_array` - // are placed into custom sections of the final output file, but this isn't link + // are placed into custom sections of the final output file, but this isn't like // custom sections of other executable formats. Namely we can only embed a list // of bytes, nothing with provenance (pointers to anything else). If any // provenance show up, reject it here. // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is // the consumer's responsibility to ensure all bytes that have been read // have defined values. + // + // The `.init_array` section is left to go through the normal custom section code path. + // When dealing with `.init_array` wasm-ld currently has several limitations. This manifests + // in workarounds in user-code. + // + // * The linker fails to merge multiple items in a crate into the .init_array section. + // To work around this, a single array can be used placing multiple items in the array. + // #[link_section = ".init_array"] + // static FOO: [unsafe extern "C" fn(); 2] = [ctor, ctor]; + // * Even symbols marked used get gc'd from dependant crates unless at least one symbol + // in the crate is marked with an `#[export_name]` + // + // Once `.init_array` support in wasm-ld is complete, the user code workarounds should + // continue to work, but would no longer be necessary. + if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id()) && alloc.inner().provenance().ptrs().len() != 0 { if attrs .link_section .map(|link_section| !link_section.as_str().starts_with(".init_array")) - .unwrap_or(true) + .unwrap() { let msg = "statics with a custom `#[link_section]` must be a \ simple list of bytes on the wasm target with no \ From 46b84956f8391b90a4c140a85270571954309bbf Mon Sep 17 00:00:00 2001 From: ilikdoge Date: Sun, 23 Jun 2024 13:43:46 -0700 Subject: [PATCH 018/734] Implement `unsigned_signed_diff` --- library/core/src/num/uint_macros.rs | 61 +++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 1491c27372bf..81062f916134 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -726,6 +726,67 @@ macro_rules! uint_impl { } } + #[doc = concat!( + "Checked integer subtraction. Computes `self - rhs` and checks if the result fits into an [`", + stringify!($SignedT), "`], returning `None` if overflow occurred." + )] + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(unsigned_signed_diff)] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_signed_diff(2), Some(8));")] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_signed_diff(10), Some(-8));")] + #[doc = concat!( + "assert_eq!(", + stringify!($SelfT), + "::MAX.checked_signed_diff(", + stringify!($SignedT), + "::MAX as ", + stringify!($SelfT), + "), None);" + )] + #[doc = concat!( + "assert_eq!((", + stringify!($SignedT), + "::MAX as ", + stringify!($SelfT), + ").checked_signed_diff(", + stringify!($SelfT), + "::MAX), Some(", + stringify!($SignedT), + "::MIN));" + )] + #[doc = concat!( + "assert_eq!((", + stringify!($SignedT), + "::MAX as ", + stringify!($SelfT), + " + 1).checked_signed_diff(0), None);" + )] + #[doc = concat!( + "assert_eq!(", + stringify!($SelfT), + "::MAX.checked_signed_diff(", + stringify!($SelfT), + "::MAX), Some(0));" + )] + /// ``` + #[unstable(feature = "unsigned_signed_diff", issue = "126041")] + #[inline] + pub const fn checked_signed_diff(self, rhs: Self) -> Option<$SignedT> { + let res = self.wrapping_sub(rhs) as $SignedT; + let overflow = (self >= rhs) == (res < 0); + + if !overflow { + Some(res) + } else { + None + } + } + /// Checked integer multiplication. Computes `self * rhs`, returning /// `None` if overflow occurred. /// From 414ebeaeea13d37bcd59473d11660169286b7cd5 Mon Sep 17 00:00:00 2001 From: Stephen Skeirik Date: Mon, 17 Jun 2024 17:01:38 -0400 Subject: [PATCH 019/734] add serde derive Serialize to stable_mir --- Cargo.lock | 1 + compiler/stable_mir/Cargo.toml | 1 + compiler/stable_mir/src/abi.rs | 35 ++--- compiler/stable_mir/src/crate_def.rs | 3 +- compiler/stable_mir/src/lib.rs | 10 +- compiler/stable_mir/src/mir/alloc.rs | 5 +- compiler/stable_mir/src/mir/body.rs | 81 +++++------ compiler/stable_mir/src/mir/mono.rs | 10 +- compiler/stable_mir/src/target.rs | 7 +- compiler/stable_mir/src/ty.rs | 153 ++++++++++++--------- tests/ui-fulldeps/stable-mir/smir_serde.rs | 75 ++++++++++ 11 files changed, 242 insertions(+), 139 deletions(-) create mode 100644 tests/ui-fulldeps/stable-mir/smir_serde.rs diff --git a/Cargo.lock b/Cargo.lock index 241a37588b40..24caf5cd3e67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5254,6 +5254,7 @@ name = "stable_mir" version = "0.1.0-preview" dependencies = [ "scoped-tls", + "serde", ] [[package]] diff --git a/compiler/stable_mir/Cargo.toml b/compiler/stable_mir/Cargo.toml index 4ed611527365..2edb3f140d7a 100644 --- a/compiler/stable_mir/Cargo.toml +++ b/compiler/stable_mir/Cargo.toml @@ -5,3 +5,4 @@ edition = "2021" [dependencies] scoped-tls = "1.0" +serde = { version = "1.0.125", features = [ "derive" ] } diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs index e1c14fe0b380..c003ec1fbc92 100644 --- a/compiler/stable_mir/src/abi.rs +++ b/compiler/stable_mir/src/abi.rs @@ -5,12 +5,13 @@ use crate::target::{MachineInfo, MachineSize as Size}; use crate::ty::{Align, IndexedVal, Ty, VariantIdx}; use crate::Error; use crate::Opaque; +use serde::Serialize; use std::fmt::{self, Debug}; use std::num::NonZero; use std::ops::RangeInclusive; /// A function ABI definition. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub struct FnAbi { /// The types of each argument. pub args: Vec, @@ -31,7 +32,7 @@ pub struct FnAbi { } /// Information about the ABI of a function's argument, or return value. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub struct ArgAbi { pub ty: Ty, pub layout: Layout, @@ -39,7 +40,7 @@ pub struct ArgAbi { } /// How a function argument should be passed in to the target function. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum PassMode { /// Ignore the argument. /// @@ -60,14 +61,14 @@ pub enum PassMode { } /// The layout of a type, alongside the type itself. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub struct TyAndLayout { pub ty: Ty, pub layout: Layout, } /// The layout of a type in memory. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub struct LayoutShape { /// The fields location withing the layout pub fields: FieldsShape, @@ -108,7 +109,7 @@ impl LayoutShape { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub struct Layout(usize); impl Layout { @@ -127,7 +128,7 @@ impl IndexedVal for Layout { } /// Describes how the fields of a type are shaped in memory. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum FieldsShape { /// Scalar primitives and `!`, which never have fields. Primitive, @@ -177,7 +178,7 @@ impl FieldsShape { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum VariantsShape { /// Single enum variants, structs/tuples, unions, and all non-ADTs. Single { index: VariantIdx }, @@ -196,7 +197,7 @@ pub enum VariantsShape { }, } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum TagEncoding { /// The tag directly stores the discriminant, but possibly with a smaller layout /// (so converting the tag to the discriminant can require sign extension). @@ -221,7 +222,7 @@ pub enum TagEncoding { /// Describes how values of the type are passed by target ABIs, /// in terms of categories of C types there are ABI rules for. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum ValueAbi { Uninhabited, Scalar(Scalar), @@ -250,7 +251,7 @@ impl ValueAbi { } /// Information about one scalar component of a Rust type. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize)] pub enum Scalar { Initialized { /// The primitive type used to represent this value. @@ -280,7 +281,7 @@ impl Scalar { } /// Fundamental unit of memory access and layout. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize)] pub enum Primitive { /// The `bool` is the signedness of the `Integer` type. /// @@ -310,7 +311,7 @@ impl Primitive { } /// Enum representing the existing integer lengths. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] pub enum IntegerLength { I8, I16, @@ -320,7 +321,7 @@ pub enum IntegerLength { } /// Enum representing the existing float lengths. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] pub enum FloatLength { F16, F32, @@ -354,7 +355,7 @@ impl FloatLength { /// An identifier that specifies the address space that some operation /// should operate on. Special address spaces have an effect on code generation, /// depending on the target and the address spaces it implements. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] pub struct AddressSpace(pub u32); impl AddressSpace { @@ -369,7 +370,7 @@ impl AddressSpace { /// sequence: /// /// 254 (-2), 255 (-1), 0, 1, 2 -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)] pub struct WrappingRange { pub start: u128, pub end: u128, @@ -420,7 +421,7 @@ impl Debug for WrappingRange { } /// General language calling conventions. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum CallConvention { C, Rust, diff --git a/compiler/stable_mir/src/crate_def.rs b/compiler/stable_mir/src/crate_def.rs index 67752a5e629f..a7cebc4c132b 100644 --- a/compiler/stable_mir/src/crate_def.rs +++ b/compiler/stable_mir/src/crate_def.rs @@ -3,9 +3,10 @@ use crate::ty::{GenericArgs, Span, Ty}; use crate::{with, Crate, Symbol}; +use serde::Serialize; /// A unique identification number for each item accessible for the current compilation unit. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)] pub struct DefId(pub(crate) usize); /// A trait for retrieving information about a particular definition. diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index 8385856ae532..fe745326d819 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -27,6 +27,7 @@ pub use crate::error::*; use crate::mir::Body; use crate::mir::Mutability; use crate::ty::{ForeignModuleDef, ImplDef, IndexedVal, Span, TraitDef, Ty}; +use serde::Serialize; pub mod abi; #[macro_use] @@ -74,7 +75,7 @@ pub type TraitDecls = Vec; pub type ImplTraitDecls = Vec; /// Holds information about a crate. -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug, Serialize)] pub struct Crate { pub id: CrateNum, pub name: Symbol, @@ -98,7 +99,7 @@ impl Crate { } } -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)] pub enum ItemKind { Fn, Static, @@ -106,7 +107,7 @@ pub enum ItemKind { Ctor(CtorKind), } -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)] pub enum CtorKind { Const, Fn, @@ -116,6 +117,7 @@ pub type Filename = String; crate_def_with_ty! { /// Holds information about an item in a crate. + #[derive(Serialize)] pub CrateItem; } @@ -188,7 +190,7 @@ pub fn all_trait_impls() -> ImplTraitDecls { } /// A type that provides internal information but that can still be used for debug purpose. -#[derive(Clone, PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq, Eq, Hash, Serialize)] pub struct Opaque(String); impl std::fmt::Display for Opaque { diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs index ef1568151f2e..9e0cac67f0aa 100644 --- a/compiler/stable_mir/src/mir/alloc.rs +++ b/compiler/stable_mir/src/mir/alloc.rs @@ -4,11 +4,12 @@ use crate::mir::mono::{Instance, StaticDef}; use crate::target::{Endian, MachineInfo}; use crate::ty::{Allocation, Binder, ExistentialTraitRef, IndexedVal, Ty}; use crate::{with, Error}; +use serde::Serialize; use std::io::Read; /// An allocation in the SMIR global memory can be either a function pointer, /// a static, or a "real" allocation with some data in it. -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize)] pub enum GlobalAlloc { /// The alloc ID is used as a function pointer. Function(Instance), @@ -41,7 +42,7 @@ impl GlobalAlloc { } /// A unique identification number for each provenance -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] pub struct AllocId(usize); impl IndexedVal for AllocId { diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index e0f9e7ae67a0..f7457ecd38f4 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -5,10 +5,11 @@ use crate::ty::{ TyConst, TyKind, VariantIdx, }; use crate::{Error, Opaque, Span, Symbol}; +use serde::Serialize; use std::io; /// The SMIR representation of a single function. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize)] pub struct Body { pub blocks: Vec, @@ -104,20 +105,20 @@ impl Body { type LocalDecls = Vec; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct LocalDecl { pub ty: Ty, pub span: Span, pub mutability: Mutability, } -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug, Serialize)] pub struct BasicBlock { pub statements: Vec, pub terminator: Terminator, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct Terminator { pub kind: TerminatorKind, pub span: Span, @@ -131,7 +132,7 @@ impl Terminator { pub type Successors = Vec; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum TerminatorKind { Goto { target: BasicBlockIdx, @@ -221,7 +222,7 @@ impl TerminatorKind { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct InlineAsmOperand { pub in_value: Option, pub out_place: Option, @@ -230,7 +231,7 @@ pub struct InlineAsmOperand { pub raw_rpr: String, } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum UnwindAction { Continue, Unreachable, @@ -238,7 +239,7 @@ pub enum UnwindAction { Cleanup(BasicBlockIdx), } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum AssertMessage { BoundsCheck { len: Operand, index: Operand }, Overflow(BinOp, Operand, Operand), @@ -307,7 +308,7 @@ impl AssertMessage { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum BinOp { Add, AddUnchecked, @@ -342,7 +343,7 @@ impl BinOp { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum UnOp { Not, Neg, @@ -357,20 +358,20 @@ impl UnOp { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum CoroutineKind { Desugared(CoroutineDesugaring, CoroutineSource), Coroutine(Movability), } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum CoroutineSource { Block, Closure, Fn, } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum CoroutineDesugaring { Async, @@ -386,7 +387,7 @@ pub(crate) type LocalDefId = Opaque; pub(crate) type Coverage = Opaque; /// The FakeReadCause describes the type of pattern why a FakeRead statement exists. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum FakeReadCause { ForMatchGuard, ForMatchedPlace(LocalDefId), @@ -396,7 +397,7 @@ pub enum FakeReadCause { } /// Describes what kind of retag is to be performed -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum RetagKind { FnEntry, TwoPhase, @@ -404,7 +405,7 @@ pub enum RetagKind { Default, } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum Variance { Covariant, Invariant, @@ -412,26 +413,26 @@ pub enum Variance { Bivariant, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct CopyNonOverlapping { pub src: Operand, pub dst: Operand, pub count: Operand, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum NonDivergingIntrinsic { Assume(Operand), CopyNonOverlapping(CopyNonOverlapping), } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct Statement { pub kind: StatementKind, pub span: Span, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum StatementKind { Assign(Place, Rvalue), FakeRead(FakeReadCause, Place), @@ -448,7 +449,7 @@ pub enum StatementKind { Nop, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum Rvalue { /// Creates a pointer with the indicated mutability to the place. /// @@ -622,7 +623,7 @@ impl Rvalue { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum AggregateKind { Array(Ty), Tuple, @@ -633,14 +634,14 @@ pub enum AggregateKind { RawPtr(Ty, Mutability), } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum Operand { Copy(Place), Move(Place), Constant(ConstOperand), } -#[derive(Clone, Eq, PartialEq)] +#[derive(Clone, Eq, PartialEq, Serialize)] pub struct Place { pub local: Local, /// projection out of a place (access a field, deref a pointer, etc) @@ -653,7 +654,7 @@ impl From for Place { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct ConstOperand { pub span: Span, pub user_ty: Option, @@ -661,7 +662,7 @@ pub struct ConstOperand { } /// Debug information pertaining to a user variable. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct VarDebugInfo { /// The variable name. pub name: Symbol, @@ -703,19 +704,19 @@ impl VarDebugInfo { pub type SourceScope = u32; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct SourceInfo { pub span: Span, pub scope: SourceScope, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct VarDebugInfoFragment { pub ty: Ty, pub projection: Vec, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum VarDebugInfoContents { Place(Place), Const(ConstOperand), @@ -726,7 +727,7 @@ pub enum VarDebugInfoContents { // ProjectionElem) and user-provided type annotations (for which the projection elements // are of type ProjectionElem<(), ()>). In SMIR we don't need this generality, so we just use // ProjectionElem for Places. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum ProjectionElem { /// Dereference projections (e.g. `*_1`) project to the address referenced by the base place. Deref, @@ -800,7 +801,7 @@ pub enum ProjectionElem { Subtype(Ty), } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct UserTypeProjection { pub base: UserTypeAnnotationIndex, @@ -830,7 +831,7 @@ pub type FieldIdx = usize; type UserTypeAnnotationIndex = usize; /// The possible branch sites of a [TerminatorKind::SwitchInt]. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct SwitchTargets { /// The conditional branches where the first element represents the value that guards this /// branch, and the second element is the branch target. @@ -867,7 +868,7 @@ impl SwitchTargets { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum BorrowKind { /// Data must be immutable and is aliasable. Shared, @@ -894,14 +895,14 @@ impl BorrowKind { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum MutBorrowKind { Default, TwoPhaseBorrow, ClosureCapture, } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum FakeBorrowKind { /// A shared (deep) borrow. Data must be immutable and is aliasable. Deep, @@ -912,19 +913,19 @@ pub enum FakeBorrowKind { Shallow, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum Mutability { Not, Mut, } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum Safety { Safe, Unsafe, } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum PointerCoercion { /// Go from a fn-item type to a fn-pointer type. ReifyFnPointer, @@ -951,7 +952,7 @@ pub enum PointerCoercion { Unsize, } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub enum CastKind { // FIXME(smir-rename): rename this to PointerExposeProvenance PointerExposeAddress, @@ -967,7 +968,7 @@ pub enum CastKind { Transmute, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum NullOp { /// Returns the size of a value of that type. SizeOf, diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs index 572f1499c5a5..c23293388f93 100644 --- a/compiler/stable_mir/src/mir/mono.rs +++ b/compiler/stable_mir/src/mir/mono.rs @@ -3,17 +3,18 @@ use crate::crate_def::CrateDef; use crate::mir::Body; use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty}; use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque, Symbol}; +use serde::Serialize; use std::fmt::{Debug, Formatter}; use std::io; -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum MonoItem { Fn(Instance), Static(StaticDef), GlobalAsm(Opaque), } -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize)] pub struct Instance { /// The type of instance. pub kind: InstanceKind, @@ -22,7 +23,7 @@ pub struct Instance { pub def: InstanceDef, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum InstanceKind { /// A user defined item. Item, @@ -240,7 +241,7 @@ impl From for CrateItem { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)] pub struct InstanceDef(usize); impl CrateDef for InstanceDef { @@ -251,6 +252,7 @@ impl CrateDef for InstanceDef { crate_def! { /// Holds information about a static variable definition. + #[derive(Serialize)] pub StaticDef; } diff --git a/compiler/stable_mir/src/target.rs b/compiler/stable_mir/src/target.rs index e00a418c5403..9fb5e046abc3 100644 --- a/compiler/stable_mir/src/target.rs +++ b/compiler/stable_mir/src/target.rs @@ -1,9 +1,10 @@ //! Provide information about the machine that this is being compiled into. use crate::compiler_interface::with; +use serde::Serialize; /// The properties of the target machine being compiled into. -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq, Serialize)] pub struct MachineInfo { pub endian: Endian, pub pointer_width: MachineSize, @@ -23,14 +24,14 @@ impl MachineInfo { } } -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq, Serialize)] pub enum Endian { Little, Big, } /// Represent the size of a component. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] pub struct MachineSize { num_bits: usize, } diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 8c120a96e75b..9c8921da52ff 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -8,10 +8,11 @@ use crate::mir::alloc::{read_target_int, read_target_uint, AllocId}; use crate::mir::mono::StaticDef; use crate::target::MachineInfo; use crate::{Filename, Opaque}; +use serde::Serialize; use std::fmt::{self, Debug, Display, Formatter}; use std::ops::Range; -#[derive(Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize)] pub struct Ty(usize); impl Debug for Ty { @@ -100,13 +101,13 @@ impl Ty { } /// Represents a pattern in the type system -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum Pattern { Range { start: Option, end: Option, include_end: bool }, } /// Represents a constant in the type system -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct TyConst { pub(crate) kind: TyConstKind, pub id: TyConstId, @@ -133,7 +134,7 @@ impl TyConst { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum TyConstKind { Param(ParamConst), Bound(DebruijnIndex, BoundVar), @@ -144,11 +145,11 @@ pub enum TyConstKind { ZSTValue(Ty), } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] pub struct TyConstId(usize); /// Represents a constant in MIR -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct MirConst { /// The constant kind. pub(crate) kind: ConstantKind, @@ -205,17 +206,17 @@ impl MirConst { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] pub struct MirConstId(usize); type Ident = Opaque; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct Region { pub kind: RegionKind, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum RegionKind { ReEarlyParam(EarlyParamRegion), ReBound(DebruijnIndex, BoundRegion), @@ -226,7 +227,7 @@ pub enum RegionKind { pub(crate) type DebruijnIndex = u32; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct EarlyParamRegion { pub index: u32, pub name: Symbol, @@ -234,7 +235,7 @@ pub struct EarlyParamRegion { pub(crate) type BoundVar = u32; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct BoundRegion { pub var: BoundVar, pub kind: BoundRegionKind, @@ -242,13 +243,13 @@ pub struct BoundRegion { pub(crate) type UniverseIndex = u32; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct Placeholder { pub universe: UniverseIndex, pub bound: T, } -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, Serialize)] pub struct Span(usize); impl Debug for Span { @@ -272,7 +273,7 @@ impl Span { } } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Serialize)] /// Information you get from `Span` in a struct form. /// Line and col start from 1. pub struct LineInfo { @@ -282,7 +283,7 @@ pub struct LineInfo { pub end_col: usize, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum TyKind { RigidTy(RigidTy), Alias(AliasKind, AliasTy), @@ -521,7 +522,7 @@ pub struct TypeAndMut { pub mutability: Mutability, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum RigidTy { Bool, Char, @@ -560,7 +561,7 @@ impl From for TyKind { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] pub enum IntTy { Isize, I8, @@ -583,7 +584,7 @@ impl IntTy { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] pub enum UintTy { Usize, U8, @@ -606,19 +607,20 @@ impl UintTy { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] pub enum FloatTy { F32, F64, } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] pub enum Movability { Static, Movable, } crate_def! { + #[derive(Serialize)] pub ForeignModuleDef; } @@ -641,6 +643,7 @@ impl ForeignModule { crate_def_with_ty! { /// Hold information about a ForeignItem in a crate. + #[derive(Serialize)] pub ForeignDef; } @@ -650,7 +653,7 @@ impl ForeignDef { } } -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] pub enum ForeignItemKind { Fn(FnDef), Static(StaticDef), @@ -659,6 +662,7 @@ pub enum ForeignItemKind { crate_def_with_ty! { /// Hold information about a function definition in a crate. + #[derive(Serialize)] pub FnDef; } @@ -692,6 +696,7 @@ impl FnDef { } crate_def_with_ty! { + #[derive(Serialize)] pub IntrinsicDef; } @@ -716,26 +721,31 @@ impl From for FnDef { } crate_def! { + #[derive(Serialize)] pub ClosureDef; } crate_def! { + #[derive(Serialize)] pub CoroutineDef; } crate_def! { + #[derive(Serialize)] pub ParamDef; } crate_def! { + #[derive(Serialize)] pub BrNamedDef; } -crate_def_with_ty! { +crate_def! { + #[derive(Serialize)] pub AdtDef; } -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] pub enum AdtKind { Enum, Union, @@ -789,7 +799,7 @@ impl AdtDef { } /// Definition of a variant, which can be either a struct / union field or an enum variant. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)] pub struct VariantDef { /// The variant index. /// @@ -818,7 +828,7 @@ impl VariantDef { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct FieldDef { /// The field definition. /// @@ -869,11 +879,13 @@ impl AdtKind { } crate_def! { + #[derive(Serialize)] pub AliasDef; } crate_def! { /// A trait's definition. + #[derive(Serialize)] pub TraitDef; } @@ -884,15 +896,18 @@ impl TraitDef { } crate_def! { + #[derive(Serialize)] pub GenericDef; } crate_def_with_ty! { + #[derive(Serialize)] pub ConstDef; } crate_def! { /// A trait impl definition. + #[derive(Serialize)] pub ImplDef; } @@ -904,15 +919,17 @@ impl ImplDef { } crate_def! { + #[derive(Serialize)] pub RegionDef; } crate_def! { + #[derive(Serialize)] pub CoroutineWitnessDef; } /// A list of generic arguments. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct GenericArgs(pub Vec); impl std::ops::Index for GenericArgs { @@ -931,7 +948,7 @@ impl std::ops::Index for GenericArgs { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum GenericArgKind { Lifetime(Region), Type(Ty), @@ -968,13 +985,13 @@ impl GenericArgKind { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum TermKind { Type(Ty), Const(TyConst), } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum AliasKind { Projection, Inherent, @@ -982,13 +999,13 @@ pub enum AliasKind { Weak, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct AliasTy { pub def_id: AliasDef, pub args: GenericArgs, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct AliasTerm { pub def_id: AliasDef, pub args: GenericArgs, @@ -1006,7 +1023,7 @@ impl PolyFnSig { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct FnSig { pub inputs_and_output: Vec, pub c_variadic: bool, @@ -1024,7 +1041,7 @@ impl FnSig { } } -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug, Serialize)] pub enum Abi { Rust, C { unwind: bool }, @@ -1054,7 +1071,7 @@ pub enum Abi { } /// A binder represents a possibly generic type and its bound vars. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct Binder { pub value: T, pub bound_vars: Vec, @@ -1094,38 +1111,38 @@ impl Binder { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct EarlyBinder { pub value: T, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum BoundVariableKind { Ty(BoundTyKind), Region(BoundRegionKind), Const, } -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug, Serialize)] pub enum BoundTyKind { Anon, Param(ParamDef, String), } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum BoundRegionKind { BrAnon, BrNamed(BrNamedDef, String), BrEnv, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum DynKind { Dyn, DynStar, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum ExistentialPredicate { Trait(ExistentialTraitRef), Projection(ExistentialProjection), @@ -1135,7 +1152,7 @@ pub enum ExistentialPredicate { /// An existential reference to a trait where `Self` is not included. /// /// The `generic_args` will include any other known argument. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct ExistentialTraitRef { pub def_id: TraitDef, pub generic_args: GenericArgs, @@ -1153,20 +1170,20 @@ impl ExistentialTraitRef { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct ExistentialProjection { pub def_id: TraitDef, pub generic_args: GenericArgs, pub term: TermKind, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct ParamTy { pub index: u32, pub name: String, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct BoundTy { pub var: usize, pub kind: BoundTyKind, @@ -1177,7 +1194,7 @@ pub type Bytes = Vec>; /// Size in bytes. pub type Size = usize; -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] pub struct Prov(pub AllocId); pub type Align = u64; @@ -1185,14 +1202,14 @@ pub type Promoted = u32; pub type InitMaskMaterialized = Vec; /// Stores the provenance information of pointers stored in memory. -#[derive(Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub struct ProvenanceMap { /// Provenance in this map applies from the given offset for an entire pointer-size worth of /// bytes. Two entries in this map are always at least a pointer size apart. pub ptrs: Vec<(Size, Prov)>, } -#[derive(Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub struct Allocation { pub bytes: Bytes, pub provenance: ProvenanceMap, @@ -1268,7 +1285,7 @@ impl Allocation { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum ConstantKind { Ty(TyConst), Allocated(Allocation), @@ -1279,27 +1296,27 @@ pub enum ConstantKind { ZeroSized, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct ParamConst { pub index: u32, pub name: String, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct UnevaluatedConst { pub def: ConstDef, pub args: GenericArgs, pub promoted: Option, } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] pub enum TraitSpecializationKind { None, Marker, AlwaysApplicable, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct TraitDecl { pub def_id: TraitDef, pub safety: Safety, @@ -1332,7 +1349,7 @@ impl TraitDecl { pub type ImplTrait = EarlyBinder; /// A complete reference to a trait, i.e., one where `Self` is known. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct TraitRef { pub def_id: TraitDef, /// The generic arguments for this definition. @@ -1366,7 +1383,7 @@ impl TraitRef { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct Generics { pub parent: Option, pub parent_count: usize, @@ -1377,14 +1394,14 @@ pub struct Generics { pub host_effect_index: Option, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum GenericParamDefKind { Lifetime, Type { has_default: bool, synthetic: bool }, Const { has_default: bool }, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct GenericParamDef { pub name: super::Symbol, pub def_id: GenericDef, @@ -1398,7 +1415,7 @@ pub struct GenericPredicates { pub predicates: Vec<(PredicateKind, Span)>, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum PredicateKind { Clause(ClauseKind), ObjectSafe(TraitDef), @@ -1409,7 +1426,7 @@ pub enum PredicateKind { AliasRelate(TermKind, TermKind, AliasRelationDirection), } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum ClauseKind { Trait(TraitPredicate), RegionOutlives(RegionOutlivesPredicate), @@ -1420,57 +1437,57 @@ pub enum ClauseKind { ConstEvaluatable(TyConst), } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum ClosureKind { Fn, FnMut, FnOnce, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct SubtypePredicate { pub a: Ty, pub b: Ty, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct CoercePredicate { pub a: Ty, pub b: Ty, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum AliasRelationDirection { Equate, Subtype, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct TraitPredicate { pub trait_ref: TraitRef, pub polarity: PredicatePolarity, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct OutlivesPredicate(pub A, pub B); pub type RegionOutlivesPredicate = OutlivesPredicate; pub type TypeOutlivesPredicate = OutlivesPredicate; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct ProjectionPredicate { pub projection_term: AliasTerm, pub term: TermKind, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum ImplPolarity { Positive, Negative, Reservation, } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum PredicatePolarity { Positive, Negative, @@ -1513,7 +1530,7 @@ index_impl!(Span); /// `a` is in the variant with the `VariantIdx` of `0`, /// `c` is in the variant with the `VariantIdx` of `1`, and /// `g` is in the variant with the `VariantIdx` of `0`. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)] pub struct VariantIdx(usize); index_impl!(VariantIdx); diff --git a/tests/ui-fulldeps/stable-mir/smir_serde.rs b/tests/ui-fulldeps/stable-mir/smir_serde.rs new file mode 100644 index 000000000000..957d840f7a24 --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/smir_serde.rs @@ -0,0 +1,75 @@ +//@ run-pass +//! Test that users are able to use serialize stable MIR constructs. + +//@ ignore-stage1 +//@ ignore-cross-compile +//@ ignore-remote +//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 +//@ edition: 2021 + +#![feature(rustc_private)] +#![feature(assert_matches)] +#![feature(control_flow_enum)] + +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate rustc_middle; +extern crate stable_mir; +extern crate serde; +extern crate serde_json; + +use rustc_middle::ty::TyCtxt; +use rustc_smir::rustc_internal; +use stable_mir::mir::Body; +use std::io::{Write, BufWriter}; +use std::ops::ControlFlow; +use serde_json::to_string; + + +const CRATE_NAME: &str = "input"; + +fn serialize_to_json(_tcx: TyCtxt<'_>) -> ControlFlow<()> { + let path = "output.json"; + let mut writer = BufWriter::new(std::fs::File::create(path) + .expect("Failed to create path")); + let local_crate = stable_mir::local_crate(); + let items: Vec = stable_mir::all_local_items() + .iter() + .map(|item| { item.body() }) + .collect(); + let crate_data = ( local_crate.name, items ); + writer.write_all(to_string(&crate_data) + .expect("serde_json failed") + .as_bytes()).expect("JSON serialization failed"); + ControlFlow::Continue(()) +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "internal_input.rs"; + generate_input(&path).unwrap(); + let args = vec![ + "rustc".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run_with_tcx!(args, serialize_to_json).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + pub fn main() {{ + }} + "# + )?; + Ok(()) +} From 8449d10a29b09c0852660ee168a77083d8179cf2 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Thu, 27 Jun 2024 14:11:54 +0800 Subject: [PATCH 020/734] Extend rules of dead code analysis for impls for adts to impls for types refer to adts --- compiler/rustc_passes/src/dead.rs | 32 ++++++++----- .../dead-code/unused-impl-for-non-adts.rs | 45 +++++++++++++++++++ .../dead-code/unused-impl-for-non-adts.stderr | 20 +++++++++ 3 files changed, 87 insertions(+), 10 deletions(-) create mode 100644 tests/ui/lint/dead-code/unused-impl-for-non-adts.rs create mode 100644 tests/ui/lint/dead-code/unused-impl-for-non-adts.stderr diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index bbd586386dd2..0a3b6ae06df3 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -54,7 +54,24 @@ impl Publicness { } } -fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: DefId) -> bool { +fn adt_of<'tcx>(ty: &hir::Ty<'tcx>) -> Option<(LocalDefId, DefKind)> { + match ty.kind { + TyKind::Path(hir::QPath::Resolved(_, path)) => { + if let Res::Def(def_kind, def_id) = path.res + && let Some(local_def_id) = def_id.as_local() + { + Some((local_def_id, def_kind)) + } else { + None + } + } + TyKind::Slice(ty) | TyKind::Array(ty, _) => adt_of(ty), + TyKind::Ptr(ty) | TyKind::Ref(_, ty) => adt_of(ty.ty), + _ => None, + } +} + +fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: LocalDefId) -> bool { // treat PhantomData and positional ZST as public, // we don't want to lint types which only have them, // cause it's a common way to use such types to check things like well-formedness @@ -79,10 +96,7 @@ fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: DefId) -> bool { /// for enum and union, just check they are public, /// and doesn't solve types like &T for now, just skip them fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> Publicness { - if let TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind - && let Res::Def(def_kind, def_id) = path.res - && def_id.is_local() - { + if let Some((def_id, def_kind)) = adt_of(ty) { return match def_kind { DefKind::Enum | DefKind::Union => { let ty_is_public = tcx.visibility(def_id).is_public(); @@ -584,10 +598,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } fn impl_item_with_used_self(&mut self, impl_id: hir::ItemId, impl_item_id: LocalDefId) -> bool { - if let TyKind::Path(hir::QPath::Resolved(_, path)) = - self.tcx.hir().item(impl_id).expect_impl().self_ty.kind - && let Res::Def(def_kind, def_id) = path.res - && let Some(local_def_id) = def_id.as_local() + if let Some((local_def_id, def_kind)) = + adt_of(self.tcx.hir().item(impl_id).expect_impl().self_ty) && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union) { if let Some(trait_item_id) = self.tcx.associated_item(impl_item_id).trait_item_def_id @@ -931,7 +943,7 @@ fn create_and_seed_worklist( match tcx.def_kind(id) { DefKind::Impl { .. } => false, DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer), - DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(), + DefKind::Struct => struct_all_fields_are_public(tcx, id) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(), _ => true }) .map(|id| (id, ComesFromAllowExpect::No)) diff --git a/tests/ui/lint/dead-code/unused-impl-for-non-adts.rs b/tests/ui/lint/dead-code/unused-impl-for-non-adts.rs new file mode 100644 index 000000000000..46065dcee81e --- /dev/null +++ b/tests/ui/lint/dead-code/unused-impl-for-non-adts.rs @@ -0,0 +1,45 @@ +#![deny(dead_code)] + +struct Foo; //~ ERROR struct `Foo` is never constructed + +trait Trait { //~ ERROR trait `Trait` is never used + fn foo(&self) {} +} + +impl Trait for Foo {} + +impl Trait for [Foo] {} +impl Trait for [Foo; N] {} + +impl Trait for *const Foo {} +impl Trait for *mut Foo {} + +impl Trait for &Foo {} +impl Trait for &&Foo {} +impl Trait for &mut Foo {} + +impl Trait for [&Foo] {} +impl Trait for &[Foo] {} +impl Trait for &*const Foo {} + +pub trait Trait2 { + fn foo(&self) {} +} + +impl Trait2 for Foo {} + +impl Trait2 for [Foo] {} +impl Trait2 for [Foo; N] {} + +impl Trait2 for *const Foo {} +impl Trait2 for *mut Foo {} + +impl Trait2 for &Foo {} +impl Trait2 for &&Foo {} +impl Trait2 for &mut Foo {} + +impl Trait2 for [&Foo] {} +impl Trait2 for &[Foo] {} +impl Trait2 for &*const Foo {} + +fn main() {} diff --git a/tests/ui/lint/dead-code/unused-impl-for-non-adts.stderr b/tests/ui/lint/dead-code/unused-impl-for-non-adts.stderr new file mode 100644 index 000000000000..e61fc403e810 --- /dev/null +++ b/tests/ui/lint/dead-code/unused-impl-for-non-adts.stderr @@ -0,0 +1,20 @@ +error: struct `Foo` is never constructed + --> $DIR/unused-impl-for-non-adts.rs:3:8 + | +LL | struct Foo; + | ^^^ + | +note: the lint level is defined here + --> $DIR/unused-impl-for-non-adts.rs:1:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: trait `Trait` is never used + --> $DIR/unused-impl-for-non-adts.rs:5:7 + | +LL | trait Trait { + | ^^^^^ + +error: aborting due to 2 previous errors + From 9f7e049744bcbc77150c66f5ab39fd46c074a22c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 30 Jun 2024 17:09:46 +0000 Subject: [PATCH 021/734] Distribute rustc_codegen_cranelift for arm64 macOS --- compiler/rustc_codegen_cranelift/Readme.md | 2 +- src/bootstrap/src/utils/helpers.rs | 4 +++- src/ci/github-actions/jobs.yml | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md index eb21e027dd0e..3b3c86a1bd17 100644 --- a/compiler/rustc_codegen_cranelift/Readme.md +++ b/compiler/rustc_codegen_cranelift/Readme.md @@ -70,7 +70,7 @@ For more docs on how to build and test see [build_system/usage.txt](build_system |FreeBSD|✅[^no-rustup]|❓|❓|❓| |AIX|❌[^xcoff]|N/A|N/A|❌[^xcoff]| |Other unixes|❓|❓|❓|❓| -|macOS|✅|✅[^no-rustup]|N/A|N/A| +|macOS|✅|✅|N/A|N/A| |Windows|✅[^no-rustup]|❌|N/A|N/A| ✅: Fully supported and tested diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index adf18c0ace1b..0d45b8302dcc 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -202,7 +202,9 @@ pub fn target_supports_cranelift_backend(target: TargetSelection) -> bool { || target.contains("aarch64") || target.contains("s390x") || target.contains("riscv64gc") - } else if target.contains("darwin") || target.is_windows() { + } else if target.contains("darwin") { + target.contains("x86_64") || target.contains("aarch64") + } else if target.is_windows() { target.contains("x86_64") } else { false diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index a6e12c6ff954..638f14ad53fe 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -326,6 +326,7 @@ auto: NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 + CODEGEN_BACKENDS: llvm,cranelift <<: *job-macos-m1 # This target only needs to support 11.0 and up as nothing else supports the hardware From 1f41fbe0ef6685a97d9d04056c2de3020aa81775 Mon Sep 17 00:00:00 2001 From: Boxy Date: Mon, 1 Jul 2024 20:39:48 +0100 Subject: [PATCH 022/734] introduce tests --- tests/ui/dropck/const_drop_is_valid.rs | 11 + tests/ui/dropck/const_drop_is_valid.stderr | 45 ++++ .../constrained_by_assoc_type_equality.rs | 12 + .../constrained_by_assoc_type_equality.stderr | 15 ++ .../unconstrained_const_param_on_drop.rs | 8 + .../unconstrained_const_param_on_drop.stderr | 219 ++++++++++++++++++ 6 files changed, 310 insertions(+) create mode 100644 tests/ui/dropck/const_drop_is_valid.rs create mode 100644 tests/ui/dropck/const_drop_is_valid.stderr create mode 100644 tests/ui/dropck/constrained_by_assoc_type_equality.rs create mode 100644 tests/ui/dropck/constrained_by_assoc_type_equality.stderr create mode 100644 tests/ui/dropck/unconstrained_const_param_on_drop.rs create mode 100644 tests/ui/dropck/unconstrained_const_param_on_drop.stderr diff --git a/tests/ui/dropck/const_drop_is_valid.rs b/tests/ui/dropck/const_drop_is_valid.rs new file mode 100644 index 000000000000..0441b6ed067a --- /dev/null +++ b/tests/ui/dropck/const_drop_is_valid.rs @@ -0,0 +1,11 @@ +#![feature(effects)] +//~^ WARN: the feature `effects` is incomplete + +struct A(); + +impl const Drop for A {} +//~^ ERROR: const trait impls are experimental +//~| const `impl` for trait `Drop` which is not marked with `#[const_trait]` +//~| not all trait items implemented, missing: `drop` + +fn main() {} diff --git a/tests/ui/dropck/const_drop_is_valid.stderr b/tests/ui/dropck/const_drop_is_valid.stderr new file mode 100644 index 000000000000..f15b7ba946db --- /dev/null +++ b/tests/ui/dropck/const_drop_is_valid.stderr @@ -0,0 +1,45 @@ +error[E0658]: const trait impls are experimental + --> $DIR/const_drop_is_valid.rs:6:6 + | +LL | impl const Drop for A {} + | ^^^^^ + | + = note: see issue #67792 for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const_drop_is_valid.rs:1:12 + | +LL | #![feature(effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: using `#![feature(effects)]` without enabling next trait solver globally + | + = note: the next trait solver must be enabled globally for the effects feature to work correctly + = help: use `-Znext-solver` to enable + +error: const `impl` for trait `Drop` which is not marked with `#[const_trait]` + --> $DIR/const_drop_is_valid.rs:6:12 + | +LL | impl const Drop for A {} + | ^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error[E0046]: not all trait items implemented, missing: `drop` + --> $DIR/const_drop_is_valid.rs:6:1 + | +LL | impl const Drop for A {} + | ^^^^^^^^^^^^^^^^^^^^^ missing `drop` in implementation + | + = help: implement the missing item: `fn drop(&mut self) { todo!() }` + +error: aborting due to 4 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0046, E0658. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/dropck/constrained_by_assoc_type_equality.rs b/tests/ui/dropck/constrained_by_assoc_type_equality.rs new file mode 100644 index 000000000000..521806cc1d7a --- /dev/null +++ b/tests/ui/dropck/constrained_by_assoc_type_equality.rs @@ -0,0 +1,12 @@ +struct Foo(T); + +trait Trait { + type Assoc; +} + +impl, U: ?Sized> Drop for Foo { + //~^ ERROR: `Drop` impl requires `::Assoc == U` + fn drop(&mut self) {} +} + +fn main() {} diff --git a/tests/ui/dropck/constrained_by_assoc_type_equality.stderr b/tests/ui/dropck/constrained_by_assoc_type_equality.stderr new file mode 100644 index 000000000000..29f4881c3fbe --- /dev/null +++ b/tests/ui/dropck/constrained_by_assoc_type_equality.stderr @@ -0,0 +1,15 @@ +error[E0367]: `Drop` impl requires `::Assoc == U` but the struct it is implemented for does not + --> $DIR/constrained_by_assoc_type_equality.rs:7:15 + | +LL | impl, U: ?Sized> Drop for Foo { + | ^^^^^^^^^ + | +note: the implementor must specify the same requirement + --> $DIR/constrained_by_assoc_type_equality.rs:1:1 + | +LL | struct Foo(T); + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0367`. diff --git a/tests/ui/dropck/unconstrained_const_param_on_drop.rs b/tests/ui/dropck/unconstrained_const_param_on_drop.rs new file mode 100644 index 000000000000..369ec7280bd3 --- /dev/null +++ b/tests/ui/dropck/unconstrained_const_param_on_drop.rs @@ -0,0 +1,8 @@ +//@ known-bug: unknown +//@ failure-status: 101 + +struct Foo {} + +impl Drop for Foo {} + +fn main() {} diff --git a/tests/ui/dropck/unconstrained_const_param_on_drop.stderr b/tests/ui/dropck/unconstrained_const_param_on_drop.stderr new file mode 100644 index 000000000000..b48ae8cc8af2 --- /dev/null +++ b/tests/ui/dropck/unconstrained_const_param_on_drop.stderr @@ -0,0 +1,219 @@ +thread 'rustc' panicked at compiler/rustc_middle/src/ty/sty.rs:360:36: +called `Option::unwrap()` on a `None` value +stack backtrace: + 0: begin_panic_handler + at ./library/std/src/panicking.rs:661:5 + 1: panic_fmt + at ./library/core/src/panicking.rs:74:14 + 2: panic + at ./library/core/src/panicking.rs:148:5 + 3: core::option::unwrap_failed + at ./library/core/src/option.rs:2013:5 + 4: unwrap + at ./library/core/src/option.rs:963:21 + 5: find_ty_from_env + at ./compiler/rustc_middle/src/ty/sty.rs:360:36 + 6: process_obligation + at ./compiler/rustc_trait_selection/src/traits/fulfill.rs:472:29 + 7: process_obligations + at ./compiler/rustc_data_structures/src/obligation_forest/mod.rs:462:23 + 8: select + at ./compiler/rustc_trait_selection/src/traits/fulfill.rs:107:13 + 9: select_where_possible + at ./compiler/rustc_trait_selection/src/traits/fulfill.rs:160:9 + 10: select_all_or_error, rustc_trait_selection::traits::FulfillmentError> + at ./compiler/rustc_infer/src/traits/engine.rs:82:22 + 11: select_all_or_error + at ./compiler/rustc_trait_selection/src/traits/engine.rs:189:9 + 12: ensure_drop_predicates_are_implied_by_item_defn + at ./compiler/rustc_hir_analysis/src/check/dropck.rs:154:18 + 13: check_drop_impl + at ./compiler/rustc_hir_analysis/src/check/dropck.rs:60:13 + 14: call core::result::Result<(), rustc_span::ErrorGuaranteed>, (rustc_middle::ty::context::TyCtxt, rustc_span::def_id::DefId)> + at ./library/core/src/ops/function.rs:79:5 + 15: {closure#0} core::result::Result<(), rustc_span::ErrorGuaranteed>> + at ./compiler/rustc_middle/src/ty/util.rs:360:16 + 16: for_each_relevant_impl core::result::Result<(), rustc_span::ErrorGuaranteed>>> + at ./compiler/rustc_middle/src/ty/trait_def.rs:166:21 + 17: calculate_dtor core::result::Result<(), rustc_span::ErrorGuaranteed>> + at ./compiler/rustc_middle/src/ty/util.rs:359:9 + 18: rustc_hir_analysis::check::adt_destructor + at ./compiler/rustc_hir_analysis/src/check/mod.rs:125:5 + 19: {closure#0} + at ./compiler/rustc_query_impl/src/plumbing.rs:285:13 + [... omitted 22 frames ...] + 20: query_get_at>> + at ./compiler/rustc_middle/src/query/plumbing.rs:145:17 + 21: adt_destructor + at ./compiler/rustc_middle/src/query/plumbing.rs:423:31 + 22: adt_destructor + at ./compiler/rustc_middle/src/query/plumbing.rs:414:35 + 23: destructor + at ./compiler/rustc_middle/src/ty/adt.rs:610:13 + 24: check_struct + at ./compiler/rustc_hir_analysis/src/check/check.rs:71:5 + 25: check_item_type + at ./compiler/rustc_hir_analysis/src/check/check.rs:730:13 + 26: check_item + at ./compiler/rustc_hir_analysis/src/check/wfcheck.rs:335:5 + 27: check_well_formed + at ./compiler/rustc_hir_analysis/src/check/wfcheck.rs:192:39 + 28: {closure#0} + at ./compiler/rustc_query_impl/src/plumbing.rs:281:9 + [... omitted 22 frames ...] + 29: query_ensure_error_guaranteed>, ()> + at ./compiler/rustc_middle/src/query/plumbing.rs:181:9 + 30: check_well_formed + at ./compiler/rustc_middle/src/query/plumbing.rs:199:9 + 31: {closure#1} + at ./compiler/rustc_hir_analysis/src/check/wfcheck.rs:1995:47 + 32: {closure#0} + at ./compiler/rustc_middle/src/hir/mod.rs:89:57 + 33: {closure#0}<&[rustc_hir::hir::ImplItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_impl_items::{closure_env#0}> + at ./compiler/rustc_data_structures/src/sync/parallel.rs:203:50 + 34: call_once, rustc_data_structures::sync::parallel::enabled::try_par_for_each_in::{closure#0}::{closure#0}::{closure_env#0}<&[rustc_hir::hir::ImplItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_impl_items::{closure_env#0}>> + at ./library/core/src/panic/unwind_safe.rs:272:9 + 35: do_call>>, core::result::Result<(), rustc_span::ErrorGuaranteed>> + at ./library/std/src/panicking.rs:553:40 + 36: try, core::panic::unwind_safe::AssertUnwindSafe>>> + at ./library/std/src/panicking.rs:517:19 + 37: catch_unwind>>, core::result::Result<(), rustc_span::ErrorGuaranteed>> + at ./library/std/src/panic.rs:350:14 + 38: run, rustc_data_structures::sync::parallel::enabled::try_par_for_each_in::{closure#0}::{closure#2}::{closure_env#0}<&[rustc_hir::hir::ItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_items::{closure_env#0}>> + at ./compiler/rustc_data_structures/src/sync/parallel.rs:28:9 + 39: {closure#2}<&[rustc_hir::hir::ItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_items::{closure_env#0}> + at ./compiler/rustc_data_structures/src/sync/parallel.rs:206:46 + 40: {closure#0}<&rustc_hir::hir::ItemId, core::result::Result<(), rustc_span::ErrorGuaranteed>, core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_data_structures::sync::parallel::enabled::try_par_for_each_in::{closure#0}::{closure_env#2}<&[rustc_hir::hir::ItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_items::{closure_env#0}>, fn(core::result::Result<(), rustc_span::ErrorGuaranteed>, core::result::Result<(), rustc_span::ErrorGuaranteed>) -> core::result::Result<(), rustc_span::ErrorGuaranteed>> + at ./library/core/src/iter/adapters/filter_map.rs:39:28 + 41: fold, core::iter::adapters::filter_map::filter_map_fold::{closure_env#0}<&rustc_hir::hir::ItemId, core::result::Result<(), rustc_span::ErrorGuaranteed>, core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_data_structures::sync::parallel::enabled::try_par_for_each_in::{closure#0}::{closure_env#2}<&[rustc_hir::hir::ItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_items::{closure_env#0}>, fn(core::result::Result<(), rustc_span::ErrorGuaranteed>, core::result::Result<(), rustc_span::ErrorGuaranteed>) -> core::result::Result<(), rustc_span::ErrorGuaranteed>>> + at ./library/core/src/slice/iter/macros.rs:232:27 + 42: fold, core::slice::iter::Iter, rustc_data_structures::sync::parallel::enabled::try_par_for_each_in::{closure#0}::{closure_env#2}<&[rustc_hir::hir::ItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_items::{closure_env#0}>, core::result::Result<(), rustc_span::ErrorGuaranteed>, fn(core::result::Result<(), rustc_span::ErrorGuaranteed>, core::result::Result<(), rustc_span::ErrorGuaranteed>) -> core::result::Result<(), rustc_span::ErrorGuaranteed>> + at ./library/core/src/iter/adapters/filter_map.rs:148:9 + 43: {closure#0}<&[rustc_hir::hir::ItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_items::{closure_env#0}> + at ./compiler/rustc_data_structures/src/sync/parallel.rs:206:73 + 44: parallel_guard, rustc_data_structures::sync::parallel::enabled::try_par_for_each_in::{closure_env#0}<&[rustc_hir::hir::ItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_items::{closure_env#0}>> + at ./compiler/rustc_data_structures/src/sync/parallel.rs:44:15 + 45: try_par_for_each_in<&[rustc_hir::hir::ItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_items::{closure_env#0}> + at ./compiler/rustc_data_structures/src/sync/parallel.rs:199:9 + 46: par_items + at ./compiler/rustc_middle/src/hir/mod.rs:75:9 + 47: check_mod_type_wf + at ./compiler/rustc_hir_analysis/src/check/wfcheck.rs:1994:19 + 48: {closure#0} + at ./compiler/rustc_query_impl/src/plumbing.rs:281:9 + [... omitted 22 frames ...] + 49: query_ensure_error_guaranteed>, ()> + at ./compiler/rustc_middle/src/query/plumbing.rs:181:9 + 50: check_mod_type_wf + at ./compiler/rustc_middle/src/query/plumbing.rs:199:9 + 51: {closure#0} + at ./compiler/rustc_hir_analysis/src/lib.rs:162:21 + 52: {closure#0} + at ./compiler/rustc_middle/src/hir/map/mod.rs:463:13 + 53: {closure#0}<&rustc_hir::hir_id::OwnerId, &[rustc_hir::hir_id::OwnerId], rustc_middle::hir::map::{impl#3}::par_for_each_module::{closure_env#0}> + at ./compiler/rustc_data_structures/src/sync/parallel.rs:182:34 + 54: call_once<(), rustc_data_structures::sync::parallel::enabled::par_for_each_in::{closure#0}::{closure#0}::{closure_env#0}<&rustc_hir::hir_id::OwnerId, &[rustc_hir::hir_id::OwnerId], rustc_middle::hir::map::{impl#3}::par_for_each_module::{closure_env#0}>> + at ./library/core/src/panic/unwind_safe.rs:272:9 + 55: do_call>>, ()> + at ./library/std/src/panicking.rs:553:40 + 56: try<(), core::panic::unwind_safe::AssertUnwindSafe>>> + at ./library/std/src/panicking.rs:517:19 + 57: catch_unwind>>, ()> + at ./library/std/src/panic.rs:350:14 + 58: run<(), rustc_data_structures::sync::parallel::enabled::par_for_each_in::{closure#0}::{closure#1}::{closure_env#0}<&rustc_hir::hir_id::OwnerId, &[rustc_hir::hir_id::OwnerId], rustc_middle::hir::map::{impl#3}::par_for_each_module::{closure_env#0}>> + at ./compiler/rustc_data_structures/src/sync/parallel.rs:28:9 + 59: {closure#1}<&rustc_hir::hir_id::OwnerId, &[rustc_hir::hir_id::OwnerId], rustc_middle::hir::map::{impl#3}::par_for_each_module::{closure_env#0}> + at ./compiler/rustc_data_structures/src/sync/parallel.rs:186:21 + 60: for_each>> + at ./library/core/src/slice/iter/macros.rs:254:21 + 61: {closure#0}<&rustc_hir::hir_id::OwnerId, &[rustc_hir::hir_id::OwnerId], rustc_middle::hir::map::{impl#3}::par_for_each_module::{closure_env#0}> + at ./compiler/rustc_data_structures/src/sync/parallel.rs:185:17 + 62: parallel_guard<(), rustc_data_structures::sync::parallel::enabled::par_for_each_in::{closure_env#0}<&rustc_hir::hir_id::OwnerId, &[rustc_hir::hir_id::OwnerId], rustc_middle::hir::map::{impl#3}::par_for_each_module::{closure_env#0}>> + at ./compiler/rustc_data_structures/src/sync/parallel.rs:44:15 + 63: par_for_each_in<&rustc_hir::hir_id::OwnerId, &[rustc_hir::hir_id::OwnerId], rustc_middle::hir::map::{impl#3}::par_for_each_module::{closure_env#0}> + at ./compiler/rustc_data_structures/src/sync/parallel.rs:178:9 + 64: par_for_each_module + at ./compiler/rustc_middle/src/hir/map/mod.rs:462:9 + 65: {closure#0} + at ./compiler/rustc_hir_analysis/src/lib.rs:161:9 + 66: run<(), rustc_hir_analysis::check_crate::{closure_env#0}> + at ./compiler/rustc_data_structures/src/profiling.rs:754:9 + 67: time<(), rustc_hir_analysis::check_crate::{closure_env#0}> + at ./compiler/rustc_session/src/utils.rs:16:9 + 68: check_crate + at ./compiler/rustc_hir_analysis/src/lib.rs:160:5 + 69: run_required_analyses + at ./compiler/rustc_interface/src/passes.rs:784:5 + 70: analysis + at ./compiler/rustc_interface/src/passes.rs:823:5 + 71: {closure#0} + at ./compiler/rustc_query_impl/src/plumbing.rs:281:9 + [... omitted 22 frames ...] + 72: query_get_at>> + at ./compiler/rustc_middle/src/query/plumbing.rs:145:17 + 73: analysis + at ./compiler/rustc_middle/src/query/plumbing.rs:423:31 + 74: analysis + at ./compiler/rustc_middle/src/query/plumbing.rs:414:35 + 75: {closure#5} + at ./compiler/rustc_driver_impl/src/lib.rs:445:52 + 76: {closure#1}> + at ./compiler/rustc_middle/src/ty/context.rs:1296:37 + 77: {closure#0}>, core::result::Result<(), rustc_span::ErrorGuaranteed>> + at ./compiler/rustc_middle/src/ty/context/tls.rs:82:9 + 78: try_with, rustc_middle::ty::context::tls::enter_context::{closure_env#0}>, core::result::Result<(), rustc_span::ErrorGuaranteed>>, core::result::Result<(), rustc_span::ErrorGuaranteed>> + at ./library/std/src/thread/local.rs:283:12 + 79: with, rustc_middle::ty::context::tls::enter_context::{closure_env#0}>, core::result::Result<(), rustc_span::ErrorGuaranteed>>, core::result::Result<(), rustc_span::ErrorGuaranteed>> + at ./library/std/src/thread/local.rs:260:9 + 80: enter_context>, core::result::Result<(), rustc_span::ErrorGuaranteed>> + at ./compiler/rustc_middle/src/ty/context/tls.rs:79:9 + 81: enter> + at ./compiler/rustc_middle/src/ty/context.rs:1296:9 + 82: {closure#1} + at ./compiler/rustc_driver_impl/src/lib.rs:445:13 + 83: enter, rustc_span::ErrorGuaranteed>> + at ./compiler/rustc_interface/src/queries.rs:202:19 + 84: {closure#0} + at ./compiler/rustc_driver_impl/src/lib.rs:389:22 + 85: {closure#1}, rustc_driver_impl::run_compiler::{closure_env#0}> + at ./compiler/rustc_interface/src/interface.rs:502:27 + 86: {closure#0}, rustc_driver_impl::run_compiler::{closure_env#0}>, core::result::Result<(), rustc_span::ErrorGuaranteed>> + at ./compiler/rustc_interface/src/util.rs:154:13 + 87: {closure#0}, rustc_driver_impl::run_compiler::{closure_env#0}>, core::result::Result<(), rustc_span::ErrorGuaranteed>>, core::result::Result<(), rustc_span::ErrorGuaranteed>> + at ./compiler/rustc_interface/src/util.rs:106:21 + 88: set, rustc_driver_impl::run_compiler::{closure_env#0}>, core::result::Result<(), rustc_span::ErrorGuaranteed>>, core::result::Result<(), rustc_span::ErrorGuaranteed>>, core::result::Result<(), rustc_span::ErrorGuaranteed>> + at /home/boxy/.cargo/registry/src/index.crates.io-6f17d22bba15001f/scoped-tls-1.0.1/src/lib.rs:137:9 + 89: create_session_globals_then, rustc_interface::util::run_in_thread_with_globals::{closure#0}::{closure#0}::{closure_env#0}, rustc_driver_impl::run_compiler::{closure_env#0}>, core::result::Result<(), rustc_span::ErrorGuaranteed>>, core::result::Result<(), rustc_span::ErrorGuaranteed>>> + at ./compiler/rustc_span/src/lib.rs:134:5 + 90: {closure#0}, rustc_driver_impl::run_compiler::{closure_env#0}>, core::result::Result<(), rustc_span::ErrorGuaranteed>>, core::result::Result<(), rustc_span::ErrorGuaranteed>> + at ./compiler/rustc_interface/src/util.rs:105:17 +note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. + +error: the compiler unexpectedly panicked. this is a bug. + +note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md + +note: please make sure that you have updated to the latest nightly + +note: rustc 1.81.0-dev running on x86_64-unknown-linux-gnu + +note: compiler flags: -Z threads=1 -Z simulate-remapped-rust-src-base=/rustc/FAKE_PREFIX -Z translate-remapped-path-to-local-path=no -Z ignore-directory-in-diagnostics-source-blocks=/home/boxy/.cargo -Z ignore-directory-in-diagnostics-source-blocks=/media/Nyoomies/Repos/rust/vendor -C codegen-units=1 -Z ui-testing -Z deduplicate-diagnostics=no -Z write-long-types-to-disk=no -C strip=debuginfo -C prefer-dynamic -C rpath -C debuginfo=0 + +query stack during panic: +#0 [adt_destructor] computing `Drop` impl for `Foo` +#1 [check_well_formed] checking that `Foo` is well-formed +#2 [check_mod_type_wf] checking that types are well-formed in top-level module +#3 [analysis] running analysis passes on this crate +end of query stack +error[E0207]: the const parameter `UNUSED` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained_const_param_on_drop.rs:6:6 + | +LL | impl Drop for Foo {} + | ^^^^^^^^^^^^^^^^^^^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0207`. From 5fc30b857c326dfdb6de7be952ad42192f890b93 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 1 Jul 2024 17:08:49 -0700 Subject: [PATCH 023/734] rustdoc: click target for sidebar items flush left --- src/librustdoc/html/static/css/rustdoc.css | 16 ++++++++++++---- tests/rustdoc-gui/huge-logo.goml | 3 ++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 4c0ba75d2612..940f444dde1f 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -15,6 +15,7 @@ --desktop-sidebar-width: 200px; --src-sidebar-width: 300px; --desktop-sidebar-z-index: 100; + --sidebar-elems-left-padding: 24px; } /* See FiraSans-LICENSE.txt for the Fira Sans license. */ @@ -559,8 +560,11 @@ ul.block, .block li { .sidebar > h2 a { display: block; padding: 0.25rem; /* 4px */ - margin-left: -0.25rem; margin-right: 0.25rem; + /* extend click target to far edge of screen (mile wide bar) */ + border-left: solid var(--sidebar-elems-left-padding) transparent; + margin-left: calc(-0.25rem - var(--sidebar-elems-left-padding)); + background-clip: padding-box; } .sidebar h2 { @@ -578,7 +582,7 @@ ul.block, .block li { .sidebar-elems, .sidebar > .version, .sidebar > h2 { - padding-left: 24px; + padding-left: var(--sidebar-elems-left-padding); } .sidebar a { @@ -632,13 +636,17 @@ ul.block, .block li { .sidebar-crate .logo-container { /* The logo is expected to have 8px "slop" along its edges, so we can optically center it. */ - margin: 0 -16px 0 -16px; + margin: 0 calc(-16px - var(--sidebar-elems-left-padding)); + padding: 0 var(--sidebar-elems-left-padding); text-align: center; } .sidebar-crate h2 a { display: block; - margin: 0 calc(-24px + 0.25rem) 0 -0.2rem; + /* extend click target to far edge of screen (mile wide bar) */ + border-left: solid var(--sidebar-elems-left-padding) transparent; + background-clip: padding-box; + margin: 0 calc(-24px + 0.25rem) 0 calc(-0.2rem - var(--sidebar-elems-left-padding)); /* Align the sidebar crate link with the search bar, which have different font sizes. diff --git a/tests/rustdoc-gui/huge-logo.goml b/tests/rustdoc-gui/huge-logo.goml index e4e5cb1ec741..6fc45ede181e 100644 --- a/tests/rustdoc-gui/huge-logo.goml +++ b/tests/rustdoc-gui/huge-logo.goml @@ -3,8 +3,9 @@ go-to: "file://" + |DOC_PATH| + "/huge_logo/index.html" set-window-size: (1280, 1024) +// offsetWidth = width of sidebar + left and right margins +assert-property: (".sidebar-crate .logo-container", {"offsetWidth": "96", "offsetHeight": 48}) // offsetWidth = width of sidebar -assert-property: (".sidebar-crate .logo-container", {"offsetWidth": "48", "offsetHeight": 48}) assert-property: (".sidebar-crate .logo-container img", {"offsetWidth": "48", "offsetHeight": 48}) set-window-size: (400, 600) From 6a0000827671ab12837a5a3a692d5dd9c31def69 Mon Sep 17 00:00:00 2001 From: Boxy Date: Mon, 1 Jul 2024 21:43:00 +0100 Subject: [PATCH 024/734] Rewrite dropck --- .../rustc_hir_analysis/src/check/dropck.rs | 34 ++- .../constrained_by_assoc_type_equality.rs | 3 +- ...ined_by_assoc_type_equality_and_self_ty.rs | 12 + ...by_assoc_type_equality_and_self_ty.stderr} | 10 +- .../dropck/reject-specialized-drops-8142.rs | 166 +++++++++---- .../reject-specialized-drops-8142.stderr | 167 ++++++------- .../ui/dropck/transitive-outlives.bad.stderr | 9 +- tests/ui/dropck/transitive-outlives.rs | 2 +- .../unconstrained_const_param_on_drop.rs | 5 +- .../unconstrained_const_param_on_drop.stderr | 224 ++---------------- 10 files changed, 265 insertions(+), 367 deletions(-) create mode 100644 tests/ui/dropck/constrained_by_assoc_type_equality_and_self_ty.rs rename tests/ui/dropck/{constrained_by_assoc_type_equality.stderr => constrained_by_assoc_type_equality_and_self_ty.stderr} (53%) diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 193714480255..06ec01484a41 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -6,10 +6,10 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; -use rustc_infer::traits::ObligationCauseCode; +use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::util::CheckRegions; -use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{GenericArgsRef, Ty}; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::{self, ObligationCtxt}; @@ -115,8 +115,9 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( Err(err.emit()) } -/// Confirms that every predicate imposed by dtor_predicates is -/// implied by assuming the predicates attached to self_type_did. +/// Confirms that all predicates defined on the `Drop` impl (`drop_impl_def_id`) are able to be +/// proven from within `adt_def_id`'s environment. I.e. all the predicates on the impl are +/// implied by the ADT being well formed. fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( tcx: TyCtxt<'tcx>, drop_impl_def_id: LocalDefId, @@ -126,6 +127,8 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( let infcx = tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); + let impl_span = tcx.def_span(drop_impl_def_id.to_def_id()); + // Take the param-env of the adt and instantiate the args that show up in // the implementation's self type. This gives us the assumptions that the // self ty of the implementation is allowed to know just from it being a @@ -135,14 +138,27 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( // We don't need to normalize this param-env or anything, since we're only // instantiating it with free params, so no additional param-env normalization // can occur on top of what has been done in the param_env query itself. - let param_env = + // + // Note: Ideally instead of instantiating the `ParamEnv` with the arguments from the impl ty we + // could instead use identity args for the adt. Unfortunately this would cause any errors to + // reference the params from the ADT instead of from the impl which is bad UX. To resolve + // this we "rename" the ADT's params to be the impl's params which should not affect behaviour. + let impl_adt_ty = Ty::new_adt(tcx, tcx.adt_def(adt_def_id), adt_to_impl_args); + let adt_env = ty::EarlyBinder::bind(tcx.param_env(adt_def_id)).instantiate(tcx, adt_to_impl_args); - for (pred, span) in tcx.predicates_of(drop_impl_def_id).instantiate_identity(tcx) { + let fresh_impl_args = infcx.fresh_args_for_item(impl_span, drop_impl_def_id.to_def_id()); + let fresh_adt_ty = + tcx.impl_trait_ref(drop_impl_def_id).unwrap().instantiate(tcx, fresh_impl_args).self_ty(); + + ocx.eq(&ObligationCause::dummy_with_span(impl_span), adt_env, fresh_adt_ty, impl_adt_ty) + .unwrap(); + + for (clause, span) in tcx.predicates_of(drop_impl_def_id).instantiate(tcx, fresh_impl_args) { let normalize_cause = traits::ObligationCause::misc(span, adt_def_id); - let pred = ocx.normalize(&normalize_cause, param_env, pred); + let pred = ocx.normalize(&normalize_cause, adt_env, clause); let cause = traits::ObligationCause::new(span, adt_def_id, ObligationCauseCode::DropImpl); - ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, pred)); + ocx.register_obligation(traits::Obligation::new(tcx, cause, adt_env, pred)); } // All of the custom error reporting logic is to preserve parity with the old @@ -176,7 +192,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( return Err(guar.unwrap()); } - let errors = ocx.infcx.resolve_regions(&OutlivesEnvironment::new(param_env)); + let errors = ocx.infcx.resolve_regions(&OutlivesEnvironment::new(adt_env)); if !errors.is_empty() { let mut guar = None; for error in errors { diff --git a/tests/ui/dropck/constrained_by_assoc_type_equality.rs b/tests/ui/dropck/constrained_by_assoc_type_equality.rs index 521806cc1d7a..4101fe83c3be 100644 --- a/tests/ui/dropck/constrained_by_assoc_type_equality.rs +++ b/tests/ui/dropck/constrained_by_assoc_type_equality.rs @@ -1,3 +1,5 @@ +//@ check-pass + struct Foo(T); trait Trait { @@ -5,7 +7,6 @@ trait Trait { } impl, U: ?Sized> Drop for Foo { - //~^ ERROR: `Drop` impl requires `::Assoc == U` fn drop(&mut self) {} } diff --git a/tests/ui/dropck/constrained_by_assoc_type_equality_and_self_ty.rs b/tests/ui/dropck/constrained_by_assoc_type_equality_and_self_ty.rs new file mode 100644 index 000000000000..3a85b86cb1fd --- /dev/null +++ b/tests/ui/dropck/constrained_by_assoc_type_equality_and_self_ty.rs @@ -0,0 +1,12 @@ +trait Trait { + type Assoc; +} + +struct Foo(T, U); + +impl, U: ?Sized> Drop for Foo { + //~^ ERROR: `Drop` impl requires `::Assoc == U` + fn drop(&mut self) {} +} + +fn main() {} diff --git a/tests/ui/dropck/constrained_by_assoc_type_equality.stderr b/tests/ui/dropck/constrained_by_assoc_type_equality_and_self_ty.stderr similarity index 53% rename from tests/ui/dropck/constrained_by_assoc_type_equality.stderr rename to tests/ui/dropck/constrained_by_assoc_type_equality_and_self_ty.stderr index 29f4881c3fbe..dab8c55d0e7f 100644 --- a/tests/ui/dropck/constrained_by_assoc_type_equality.stderr +++ b/tests/ui/dropck/constrained_by_assoc_type_equality_and_self_ty.stderr @@ -1,14 +1,14 @@ error[E0367]: `Drop` impl requires `::Assoc == U` but the struct it is implemented for does not - --> $DIR/constrained_by_assoc_type_equality.rs:7:15 + --> $DIR/constrained_by_assoc_type_equality_and_self_ty.rs:7:15 | -LL | impl, U: ?Sized> Drop for Foo { +LL | impl, U: ?Sized> Drop for Foo { | ^^^^^^^^^ | note: the implementor must specify the same requirement - --> $DIR/constrained_by_assoc_type_equality.rs:1:1 + --> $DIR/constrained_by_assoc_type_equality_and_self_ty.rs:5:1 | -LL | struct Foo(T); - | ^^^^^^^^^^^^^^^^^^^^ +LL | struct Foo(T, U); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/dropck/reject-specialized-drops-8142.rs b/tests/ui/dropck/reject-specialized-drops-8142.rs index 7a3bbe7cb093..1b73fe9a0655 100644 --- a/tests/ui/dropck/reject-specialized-drops-8142.rs +++ b/tests/ui/dropck/reject-specialized-drops-8142.rs @@ -1,75 +1,145 @@ // Issue 8142: Test that Drop impls cannot be specialized beyond the // predicates attached to the type definition itself. -trait Bound { fn foo(&self) { } } -struct K<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 } -struct L<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 } -struct M<'m> { x: &'m i8 } -struct N<'n> { x: &'n i8 } -struct O { x: *const To } -struct P { x: *const Tp } -struct Q { x: *const Tq } -struct R { x: *const Tr } -struct S { x: *const Ts } -struct T<'t,Ts:'t> { x: &'t Ts } +trait Bound { + fn foo(&self) {} +} +struct K<'l1, 'l2> { + x: &'l1 i8, + y: &'l2 u8, +} +struct L<'l1, 'l2> { + x: &'l1 i8, + y: &'l2 u8, +} +struct M<'m> { + x: &'m i8, +} +struct N<'n> { + x: &'n i8, +} +struct O { + x: *const To, +} +struct P { + x: *const Tp, +} +struct Q { + x: *const Tq, +} +struct R { + x: *const Tr, +} +struct S { + x: *const Ts, +} +struct T<'t, Ts: 't> { + x: &'t Ts, +} struct U; -struct V { x: *const Tva, y: *const Tvb } -struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 } +struct V { + x: *const Tva, + y: *const Tvb, +} +struct W<'l1, 'l2> { + x: &'l1 i8, + y: &'l2 u8, +} struct X; struct Y; -enum Enum { Variant(T) } +enum Enum { + Variant(T), +} struct TupleStruct(T); -union Union { f: T } +union Union { + f: T, +} -impl<'al,'adds_bnd:'al> Drop for K<'al,'adds_bnd> { // REJECT +impl<'al, 'adds_bnd: 'al> Drop for K<'al, 'adds_bnd> { //~^ ERROR `Drop` impl requires `'adds_bnd: 'al` - fn drop(&mut self) { } } + fn drop(&mut self) {} +} -impl<'al,'adds_bnd> Drop for L<'al,'adds_bnd> where 'adds_bnd:'al { // REJECT - //~^ ERROR `Drop` impl requires `'adds_bnd: 'al` - fn drop(&mut self) { } } +impl<'al, 'adds_bnd> Drop for L<'al, 'adds_bnd> +//~^ ERROR `Drop` impl requires `'adds_bnd: 'al` +where + 'adds_bnd: 'al, +{ + fn drop(&mut self) {} +} -impl<'ml> Drop for M<'ml> { fn drop(&mut self) { } } // ACCEPT +impl<'ml> Drop for M<'ml> { + fn drop(&mut self) {} +} -impl Drop for N<'static> { fn drop(&mut self) { } } // REJECT -//~^ ERROR `Drop` impls cannot be specialized +impl Drop for N<'static> { + //~^ ERROR `Drop` impls cannot be specialized + fn drop(&mut self) {} +} -impl Drop for O { fn drop(&mut self) { } } // ACCEPT +impl Drop for O { + fn drop(&mut self) {} +} -impl Drop for P { fn drop(&mut self) { } } // REJECT -//~^ ERROR `Drop` impls cannot be specialized +impl Drop for P { + //~^ ERROR `Drop` impls cannot be specialized + fn drop(&mut self) {} +} -impl Drop for Q { fn drop(&mut self) { } } // REJECT -//~^ ERROR `Drop` impl requires `AddsBnd: Bound` +impl Drop for Q { + //~^ ERROR `Drop` impl requires `AddsBnd: Bound` + fn drop(&mut self) {} +} -impl<'rbnd,AddsRBnd:'rbnd> Drop for R { fn drop(&mut self) { } } // REJECT -//~^ ERROR `Drop` impl requires `AddsRBnd: 'rbnd` +impl<'rbnd, AddsRBnd: 'rbnd> Drop for R { + fn drop(&mut self) {} +} -impl Drop for S { fn drop(&mut self) { } } // ACCEPT +impl Drop for S { + fn drop(&mut self) {} +} -impl<'t,Bt:'t> Drop for T<'t,Bt> { fn drop(&mut self) { } } // ACCEPT +impl<'t, Bt: 't> Drop for T<'t, Bt> { + fn drop(&mut self) {} +} -impl Drop for U { fn drop(&mut self) { } } // ACCEPT +impl Drop for U { + fn drop(&mut self) {} +} -impl Drop for V { fn drop(&mut self) { } } // REJECT -//~^ ERROR `Drop` impls cannot be specialized +impl Drop for V { + //~^ ERROR `Drop` impls cannot be specialized + fn drop(&mut self) {} +} -impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT -//~^ ERROR `Drop` impls cannot be specialized +impl<'lw> Drop for W<'lw, 'lw> { + //~^ ERROR `Drop` impls cannot be specialized + fn drop(&mut self) {} +} -impl Drop for X<3> { fn drop(&mut self) { } } // REJECT -//~^ ERROR `Drop` impls cannot be specialized +impl Drop for X<3> { + //~^ ERROR `Drop` impls cannot be specialized + fn drop(&mut self) {} +} -impl Drop for Y { fn drop(&mut self) { } } // REJECT -//~^ ERROR `Drop` impls cannot be specialized +impl Drop for Y { + //~^ ERROR `Drop` impls cannot be specialized + fn drop(&mut self) {} +} -impl Drop for Enum { fn drop(&mut self) { } } // REJECT -//~^ ERROR `Drop` impl requires `AddsBnd: Bound` +impl Drop for Enum { + //~^ ERROR `Drop` impl requires `AddsBnd: Bound` + fn drop(&mut self) {} +} -impl Drop for TupleStruct { fn drop(&mut self) { } } // REJECT -//~^ ERROR `Drop` impl requires `AddsBnd: Bound` +impl Drop for TupleStruct { + //~^ ERROR `Drop` impl requires `AddsBnd: Bound` + fn drop(&mut self) {} +} -impl Drop for Union { fn drop(&mut self) { } } // REJECT -//~^ ERROR `Drop` impl requires `AddsBnd: Bound` +impl Drop for Union { + //~^ ERROR `Drop` impl requires `AddsBnd: Bound` + fn drop(&mut self) {} +} -pub fn main() { } +pub fn main() {} diff --git a/tests/ui/dropck/reject-specialized-drops-8142.stderr b/tests/ui/dropck/reject-specialized-drops-8142.stderr index cb48221c67a8..9c8b6d544639 100644 --- a/tests/ui/dropck/reject-specialized-drops-8142.stderr +++ b/tests/ui/dropck/reject-specialized-drops-8142.stderr @@ -1,166 +1,157 @@ error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not - --> $DIR/reject-specialized-drops-8142.rs:24:20 + --> $DIR/reject-specialized-drops-8142.rs:58:1 | -LL | impl<'al,'adds_bnd:'al> Drop for K<'al,'adds_bnd> { // REJECT - | ^^^ +LL | impl<'al, 'adds_bnd: 'al> Drop for K<'al, 'adds_bnd> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the implementor must specify the same requirement - --> $DIR/reject-specialized-drops-8142.rs:4:1 + --> $DIR/reject-specialized-drops-8142.rs:6:1 | -LL | struct K<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 } - | ^^^^^^^^^^^^^^^^^ +LL | struct K<'l1, 'l2> { + | ^^^^^^^^^^^^^^^^^^ error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not - --> $DIR/reject-specialized-drops-8142.rs:28:67 + --> $DIR/reject-specialized-drops-8142.rs:63:1 | -LL | impl<'al,'adds_bnd> Drop for L<'al,'adds_bnd> where 'adds_bnd:'al { // REJECT - | ^^^ - | -note: the implementor must specify the same requirement - --> $DIR/reject-specialized-drops-8142.rs:5:1 - | -LL | struct L<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 } - | ^^^^^^^^^^^^^^^^^ - -error[E0366]: `Drop` impls cannot be specialized - --> $DIR/reject-specialized-drops-8142.rs:34:1 - | -LL | impl Drop for N<'static> { fn drop(&mut self) { } } // REJECT - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `'static` is not a generic parameter -note: use the same sequence of generic lifetime, type and const parameters as the struct definition - --> $DIR/reject-specialized-drops-8142.rs:7:1 - | -LL | struct N<'n> { x: &'n i8 } - | ^^^^^^^^^^^^ - -error[E0366]: `Drop` impls cannot be specialized - --> $DIR/reject-specialized-drops-8142.rs:39:1 - | -LL | impl Drop for P { fn drop(&mut self) { } } // REJECT - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `i8` is not a generic parameter -note: use the same sequence of generic lifetime, type and const parameters as the struct definition - --> $DIR/reject-specialized-drops-8142.rs:9:1 - | -LL | struct P { x: *const Tp } - | ^^^^^^^^^^^^ - -error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not - --> $DIR/reject-specialized-drops-8142.rs:42:14 - | -LL | impl Drop for Q { fn drop(&mut self) { } } // REJECT - | ^^^^^ +LL | / impl<'al, 'adds_bnd> Drop for L<'al, 'adds_bnd> +LL | | +LL | | where +LL | | 'adds_bnd: 'al, + | |___________________^ | note: the implementor must specify the same requirement --> $DIR/reject-specialized-drops-8142.rs:10:1 | -LL | struct Q { x: *const Tq } - | ^^^^^^^^^^^^ +LL | struct L<'l1, 'l2> { + | ^^^^^^^^^^^^^^^^^^ -error[E0367]: `Drop` impl requires `AddsRBnd: 'rbnd` but the struct it is implemented for does not - --> $DIR/reject-specialized-drops-8142.rs:45:21 +error[E0366]: `Drop` impls cannot be specialized + --> $DIR/reject-specialized-drops-8142.rs:75:1 | -LL | impl<'rbnd,AddsRBnd:'rbnd> Drop for R { fn drop(&mut self) { } } // REJECT - | ^^^^^ +LL | impl Drop for N<'static> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the implementor must specify the same requirement - --> $DIR/reject-specialized-drops-8142.rs:11:1 + = note: `'static` is not a generic parameter +note: use the same sequence of generic lifetime, type and const parameters as the struct definition + --> $DIR/reject-specialized-drops-8142.rs:17:1 | -LL | struct R { x: *const Tr } +LL | struct N<'n> { | ^^^^^^^^^^^^ error[E0366]: `Drop` impls cannot be specialized - --> $DIR/reject-specialized-drops-8142.rs:54:1 + --> $DIR/reject-specialized-drops-8142.rs:84:1 | -LL | impl Drop for V { fn drop(&mut self) { } } // REJECT - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Drop for P { + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `i8` is not a generic parameter +note: use the same sequence of generic lifetime, type and const parameters as the struct definition + --> $DIR/reject-specialized-drops-8142.rs:23:1 + | +LL | struct P { + | ^^^^^^^^^^^^ + +error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not + --> $DIR/reject-specialized-drops-8142.rs:89:15 + | +LL | impl Drop for Q { + | ^^^^^ + | +note: the implementor must specify the same requirement + --> $DIR/reject-specialized-drops-8142.rs:26:1 + | +LL | struct Q { + | ^^^^^^^^^^^^ + +error[E0366]: `Drop` impls cannot be specialized + --> $DIR/reject-specialized-drops-8142.rs:110:1 + | +LL | impl Drop for V { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `One` is mentioned multiple times note: use the same sequence of generic lifetime, type and const parameters as the struct definition - --> $DIR/reject-specialized-drops-8142.rs:15:1 + --> $DIR/reject-specialized-drops-8142.rs:39:1 | -LL | struct V { x: *const Tva, y: *const Tvb } +LL | struct V { | ^^^^^^^^^^^^^^^^^^ error[E0366]: `Drop` impls cannot be specialized - --> $DIR/reject-specialized-drops-8142.rs:57:1 + --> $DIR/reject-specialized-drops-8142.rs:115:1 | -LL | impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl<'lw> Drop for W<'lw, 'lw> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `'lw` is mentioned multiple times note: use the same sequence of generic lifetime, type and const parameters as the struct definition - --> $DIR/reject-specialized-drops-8142.rs:16:1 + --> $DIR/reject-specialized-drops-8142.rs:43:1 | -LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 } +LL | struct W<'l1, 'l2> { | ^^^^^^^^^^^^^^^^^^ error[E0366]: `Drop` impls cannot be specialized - --> $DIR/reject-specialized-drops-8142.rs:60:1 + --> $DIR/reject-specialized-drops-8142.rs:120:1 | -LL | impl Drop for X<3> { fn drop(&mut self) { } } // REJECT - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Drop for X<3> { + | ^^^^^^^^^^^^^^^^^^ | = note: `3` is not a generic parameter note: use the same sequence of generic lifetime, type and const parameters as the struct definition - --> $DIR/reject-specialized-drops-8142.rs:17:1 + --> $DIR/reject-specialized-drops-8142.rs:47:1 | LL | struct X; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0366]: `Drop` impls cannot be specialized - --> $DIR/reject-specialized-drops-8142.rs:63:1 + --> $DIR/reject-specialized-drops-8142.rs:125:1 | -LL | impl Drop for Y { fn drop(&mut self) { } } // REJECT +LL | impl Drop for Y { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `Ca` is mentioned multiple times note: use the same sequence of generic lifetime, type and const parameters as the struct definition - --> $DIR/reject-specialized-drops-8142.rs:18:1 + --> $DIR/reject-specialized-drops-8142.rs:48:1 | LL | struct Y; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the enum it is implemented for does not - --> $DIR/reject-specialized-drops-8142.rs:66:14 + --> $DIR/reject-specialized-drops-8142.rs:130:15 | -LL | impl Drop for Enum { fn drop(&mut self) { } } // REJECT - | ^^^^^ +LL | impl Drop for Enum { + | ^^^^^ | note: the implementor must specify the same requirement - --> $DIR/reject-specialized-drops-8142.rs:20:1 + --> $DIR/reject-specialized-drops-8142.rs:50:1 | -LL | enum Enum { Variant(T) } +LL | enum Enum { | ^^^^^^^^^^^^ error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not - --> $DIR/reject-specialized-drops-8142.rs:69:14 + --> $DIR/reject-specialized-drops-8142.rs:135:15 | -LL | impl Drop for TupleStruct { fn drop(&mut self) { } } // REJECT - | ^^^^^ +LL | impl Drop for TupleStruct { + | ^^^^^ | note: the implementor must specify the same requirement - --> $DIR/reject-specialized-drops-8142.rs:21:1 + --> $DIR/reject-specialized-drops-8142.rs:53:1 | LL | struct TupleStruct(T); | ^^^^^^^^^^^^^^^^^^^^^ error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not - --> $DIR/reject-specialized-drops-8142.rs:72:21 + --> $DIR/reject-specialized-drops-8142.rs:140:22 | -LL | impl Drop for Union { fn drop(&mut self) { } } // REJECT - | ^^^^^ +LL | impl Drop for Union { + | ^^^^^ | note: the implementor must specify the same requirement - --> $DIR/reject-specialized-drops-8142.rs:22:1 + --> $DIR/reject-specialized-drops-8142.rs:54:1 | -LL | union Union { f: T } +LL | union Union { | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 13 previous errors +error: aborting due to 12 previous errors Some errors have detailed explanations: E0366, E0367. For more information about an error, try `rustc --explain E0366`. diff --git a/tests/ui/dropck/transitive-outlives.bad.stderr b/tests/ui/dropck/transitive-outlives.bad.stderr index 9ecc4841dce5..5b7968fce80c 100644 --- a/tests/ui/dropck/transitive-outlives.bad.stderr +++ b/tests/ui/dropck/transitive-outlives.bad.stderr @@ -1,8 +1,11 @@ error[E0367]: `Drop` impl requires `'a: 'c` but the struct it is implemented for does not - --> $DIR/transitive-outlives.rs:20:9 + --> $DIR/transitive-outlives.rs:18:1 | -LL | 'a: 'c, - | ^^ +LL | / impl<'a, 'b, 'c> Drop for DropMe<'a, 'b, 'c> +LL | | +LL | | where +LL | | 'a: 'c, + | |___________^ | note: the implementor must specify the same requirement --> $DIR/transitive-outlives.rs:7:1 diff --git a/tests/ui/dropck/transitive-outlives.rs b/tests/ui/dropck/transitive-outlives.rs index e96ac6faae47..37c0a1ff5e27 100644 --- a/tests/ui/dropck/transitive-outlives.rs +++ b/tests/ui/dropck/transitive-outlives.rs @@ -16,9 +16,9 @@ where #[cfg(bad)] impl<'a, 'b, 'c> Drop for DropMe<'a, 'b, 'c> +//[bad]~^ ERROR `Drop` impl requires `'a: 'c` where 'a: 'c, - //[bad]~^ ERROR `Drop` impl requires `'a: 'c` { fn drop(&mut self) {} } diff --git a/tests/ui/dropck/unconstrained_const_param_on_drop.rs b/tests/ui/dropck/unconstrained_const_param_on_drop.rs index 369ec7280bd3..de77fa55fb28 100644 --- a/tests/ui/dropck/unconstrained_const_param_on_drop.rs +++ b/tests/ui/dropck/unconstrained_const_param_on_drop.rs @@ -1,8 +1,7 @@ -//@ known-bug: unknown -//@ failure-status: 101 - struct Foo {} impl Drop for Foo {} +//~^ ERROR: `Drop` impl requires `the constant `_` has type `usize`` +//~| ERROR: the const parameter `UNUSED` is not constrained by the impl trait, self type, or predicates fn main() {} diff --git a/tests/ui/dropck/unconstrained_const_param_on_drop.stderr b/tests/ui/dropck/unconstrained_const_param_on_drop.stderr index b48ae8cc8af2..851888534eeb 100644 --- a/tests/ui/dropck/unconstrained_const_param_on_drop.stderr +++ b/tests/ui/dropck/unconstrained_const_param_on_drop.stderr @@ -1,212 +1,17 @@ -thread 'rustc' panicked at compiler/rustc_middle/src/ty/sty.rs:360:36: -called `Option::unwrap()` on a `None` value -stack backtrace: - 0: begin_panic_handler - at ./library/std/src/panicking.rs:661:5 - 1: panic_fmt - at ./library/core/src/panicking.rs:74:14 - 2: panic - at ./library/core/src/panicking.rs:148:5 - 3: core::option::unwrap_failed - at ./library/core/src/option.rs:2013:5 - 4: unwrap - at ./library/core/src/option.rs:963:21 - 5: find_ty_from_env - at ./compiler/rustc_middle/src/ty/sty.rs:360:36 - 6: process_obligation - at ./compiler/rustc_trait_selection/src/traits/fulfill.rs:472:29 - 7: process_obligations - at ./compiler/rustc_data_structures/src/obligation_forest/mod.rs:462:23 - 8: select - at ./compiler/rustc_trait_selection/src/traits/fulfill.rs:107:13 - 9: select_where_possible - at ./compiler/rustc_trait_selection/src/traits/fulfill.rs:160:9 - 10: select_all_or_error, rustc_trait_selection::traits::FulfillmentError> - at ./compiler/rustc_infer/src/traits/engine.rs:82:22 - 11: select_all_or_error - at ./compiler/rustc_trait_selection/src/traits/engine.rs:189:9 - 12: ensure_drop_predicates_are_implied_by_item_defn - at ./compiler/rustc_hir_analysis/src/check/dropck.rs:154:18 - 13: check_drop_impl - at ./compiler/rustc_hir_analysis/src/check/dropck.rs:60:13 - 14: call core::result::Result<(), rustc_span::ErrorGuaranteed>, (rustc_middle::ty::context::TyCtxt, rustc_span::def_id::DefId)> - at ./library/core/src/ops/function.rs:79:5 - 15: {closure#0} core::result::Result<(), rustc_span::ErrorGuaranteed>> - at ./compiler/rustc_middle/src/ty/util.rs:360:16 - 16: for_each_relevant_impl core::result::Result<(), rustc_span::ErrorGuaranteed>>> - at ./compiler/rustc_middle/src/ty/trait_def.rs:166:21 - 17: calculate_dtor core::result::Result<(), rustc_span::ErrorGuaranteed>> - at ./compiler/rustc_middle/src/ty/util.rs:359:9 - 18: rustc_hir_analysis::check::adt_destructor - at ./compiler/rustc_hir_analysis/src/check/mod.rs:125:5 - 19: {closure#0} - at ./compiler/rustc_query_impl/src/plumbing.rs:285:13 - [... omitted 22 frames ...] - 20: query_get_at>> - at ./compiler/rustc_middle/src/query/plumbing.rs:145:17 - 21: adt_destructor - at ./compiler/rustc_middle/src/query/plumbing.rs:423:31 - 22: adt_destructor - at ./compiler/rustc_middle/src/query/plumbing.rs:414:35 - 23: destructor - at ./compiler/rustc_middle/src/ty/adt.rs:610:13 - 24: check_struct - at ./compiler/rustc_hir_analysis/src/check/check.rs:71:5 - 25: check_item_type - at ./compiler/rustc_hir_analysis/src/check/check.rs:730:13 - 26: check_item - at ./compiler/rustc_hir_analysis/src/check/wfcheck.rs:335:5 - 27: check_well_formed - at ./compiler/rustc_hir_analysis/src/check/wfcheck.rs:192:39 - 28: {closure#0} - at ./compiler/rustc_query_impl/src/plumbing.rs:281:9 - [... omitted 22 frames ...] - 29: query_ensure_error_guaranteed>, ()> - at ./compiler/rustc_middle/src/query/plumbing.rs:181:9 - 30: check_well_formed - at ./compiler/rustc_middle/src/query/plumbing.rs:199:9 - 31: {closure#1} - at ./compiler/rustc_hir_analysis/src/check/wfcheck.rs:1995:47 - 32: {closure#0} - at ./compiler/rustc_middle/src/hir/mod.rs:89:57 - 33: {closure#0}<&[rustc_hir::hir::ImplItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_impl_items::{closure_env#0}> - at ./compiler/rustc_data_structures/src/sync/parallel.rs:203:50 - 34: call_once, rustc_data_structures::sync::parallel::enabled::try_par_for_each_in::{closure#0}::{closure#0}::{closure_env#0}<&[rustc_hir::hir::ImplItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_impl_items::{closure_env#0}>> - at ./library/core/src/panic/unwind_safe.rs:272:9 - 35: do_call>>, core::result::Result<(), rustc_span::ErrorGuaranteed>> - at ./library/std/src/panicking.rs:553:40 - 36: try, core::panic::unwind_safe::AssertUnwindSafe>>> - at ./library/std/src/panicking.rs:517:19 - 37: catch_unwind>>, core::result::Result<(), rustc_span::ErrorGuaranteed>> - at ./library/std/src/panic.rs:350:14 - 38: run, rustc_data_structures::sync::parallel::enabled::try_par_for_each_in::{closure#0}::{closure#2}::{closure_env#0}<&[rustc_hir::hir::ItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_items::{closure_env#0}>> - at ./compiler/rustc_data_structures/src/sync/parallel.rs:28:9 - 39: {closure#2}<&[rustc_hir::hir::ItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_items::{closure_env#0}> - at ./compiler/rustc_data_structures/src/sync/parallel.rs:206:46 - 40: {closure#0}<&rustc_hir::hir::ItemId, core::result::Result<(), rustc_span::ErrorGuaranteed>, core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_data_structures::sync::parallel::enabled::try_par_for_each_in::{closure#0}::{closure_env#2}<&[rustc_hir::hir::ItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_items::{closure_env#0}>, fn(core::result::Result<(), rustc_span::ErrorGuaranteed>, core::result::Result<(), rustc_span::ErrorGuaranteed>) -> core::result::Result<(), rustc_span::ErrorGuaranteed>> - at ./library/core/src/iter/adapters/filter_map.rs:39:28 - 41: fold, core::iter::adapters::filter_map::filter_map_fold::{closure_env#0}<&rustc_hir::hir::ItemId, core::result::Result<(), rustc_span::ErrorGuaranteed>, core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_data_structures::sync::parallel::enabled::try_par_for_each_in::{closure#0}::{closure_env#2}<&[rustc_hir::hir::ItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_items::{closure_env#0}>, fn(core::result::Result<(), rustc_span::ErrorGuaranteed>, core::result::Result<(), rustc_span::ErrorGuaranteed>) -> core::result::Result<(), rustc_span::ErrorGuaranteed>>> - at ./library/core/src/slice/iter/macros.rs:232:27 - 42: fold, core::slice::iter::Iter, rustc_data_structures::sync::parallel::enabled::try_par_for_each_in::{closure#0}::{closure_env#2}<&[rustc_hir::hir::ItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_items::{closure_env#0}>, core::result::Result<(), rustc_span::ErrorGuaranteed>, fn(core::result::Result<(), rustc_span::ErrorGuaranteed>, core::result::Result<(), rustc_span::ErrorGuaranteed>) -> core::result::Result<(), rustc_span::ErrorGuaranteed>> - at ./library/core/src/iter/adapters/filter_map.rs:148:9 - 43: {closure#0}<&[rustc_hir::hir::ItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_items::{closure_env#0}> - at ./compiler/rustc_data_structures/src/sync/parallel.rs:206:73 - 44: parallel_guard, rustc_data_structures::sync::parallel::enabled::try_par_for_each_in::{closure_env#0}<&[rustc_hir::hir::ItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_items::{closure_env#0}>> - at ./compiler/rustc_data_structures/src/sync/parallel.rs:44:15 - 45: try_par_for_each_in<&[rustc_hir::hir::ItemId], rustc_span::ErrorGuaranteed, rustc_middle::hir::{impl#0}::par_items::{closure_env#0}> - at ./compiler/rustc_data_structures/src/sync/parallel.rs:199:9 - 46: par_items - at ./compiler/rustc_middle/src/hir/mod.rs:75:9 - 47: check_mod_type_wf - at ./compiler/rustc_hir_analysis/src/check/wfcheck.rs:1994:19 - 48: {closure#0} - at ./compiler/rustc_query_impl/src/plumbing.rs:281:9 - [... omitted 22 frames ...] - 49: query_ensure_error_guaranteed>, ()> - at ./compiler/rustc_middle/src/query/plumbing.rs:181:9 - 50: check_mod_type_wf - at ./compiler/rustc_middle/src/query/plumbing.rs:199:9 - 51: {closure#0} - at ./compiler/rustc_hir_analysis/src/lib.rs:162:21 - 52: {closure#0} - at ./compiler/rustc_middle/src/hir/map/mod.rs:463:13 - 53: {closure#0}<&rustc_hir::hir_id::OwnerId, &[rustc_hir::hir_id::OwnerId], rustc_middle::hir::map::{impl#3}::par_for_each_module::{closure_env#0}> - at ./compiler/rustc_data_structures/src/sync/parallel.rs:182:34 - 54: call_once<(), rustc_data_structures::sync::parallel::enabled::par_for_each_in::{closure#0}::{closure#0}::{closure_env#0}<&rustc_hir::hir_id::OwnerId, &[rustc_hir::hir_id::OwnerId], rustc_middle::hir::map::{impl#3}::par_for_each_module::{closure_env#0}>> - at ./library/core/src/panic/unwind_safe.rs:272:9 - 55: do_call>>, ()> - at ./library/std/src/panicking.rs:553:40 - 56: try<(), core::panic::unwind_safe::AssertUnwindSafe>>> - at ./library/std/src/panicking.rs:517:19 - 57: catch_unwind>>, ()> - at ./library/std/src/panic.rs:350:14 - 58: run<(), rustc_data_structures::sync::parallel::enabled::par_for_each_in::{closure#0}::{closure#1}::{closure_env#0}<&rustc_hir::hir_id::OwnerId, &[rustc_hir::hir_id::OwnerId], rustc_middle::hir::map::{impl#3}::par_for_each_module::{closure_env#0}>> - at ./compiler/rustc_data_structures/src/sync/parallel.rs:28:9 - 59: {closure#1}<&rustc_hir::hir_id::OwnerId, &[rustc_hir::hir_id::OwnerId], rustc_middle::hir::map::{impl#3}::par_for_each_module::{closure_env#0}> - at ./compiler/rustc_data_structures/src/sync/parallel.rs:186:21 - 60: for_each>> - at ./library/core/src/slice/iter/macros.rs:254:21 - 61: {closure#0}<&rustc_hir::hir_id::OwnerId, &[rustc_hir::hir_id::OwnerId], rustc_middle::hir::map::{impl#3}::par_for_each_module::{closure_env#0}> - at ./compiler/rustc_data_structures/src/sync/parallel.rs:185:17 - 62: parallel_guard<(), rustc_data_structures::sync::parallel::enabled::par_for_each_in::{closure_env#0}<&rustc_hir::hir_id::OwnerId, &[rustc_hir::hir_id::OwnerId], rustc_middle::hir::map::{impl#3}::par_for_each_module::{closure_env#0}>> - at ./compiler/rustc_data_structures/src/sync/parallel.rs:44:15 - 63: par_for_each_in<&rustc_hir::hir_id::OwnerId, &[rustc_hir::hir_id::OwnerId], rustc_middle::hir::map::{impl#3}::par_for_each_module::{closure_env#0}> - at ./compiler/rustc_data_structures/src/sync/parallel.rs:178:9 - 64: par_for_each_module - at ./compiler/rustc_middle/src/hir/map/mod.rs:462:9 - 65: {closure#0} - at ./compiler/rustc_hir_analysis/src/lib.rs:161:9 - 66: run<(), rustc_hir_analysis::check_crate::{closure_env#0}> - at ./compiler/rustc_data_structures/src/profiling.rs:754:9 - 67: time<(), rustc_hir_analysis::check_crate::{closure_env#0}> - at ./compiler/rustc_session/src/utils.rs:16:9 - 68: check_crate - at ./compiler/rustc_hir_analysis/src/lib.rs:160:5 - 69: run_required_analyses - at ./compiler/rustc_interface/src/passes.rs:784:5 - 70: analysis - at ./compiler/rustc_interface/src/passes.rs:823:5 - 71: {closure#0} - at ./compiler/rustc_query_impl/src/plumbing.rs:281:9 - [... omitted 22 frames ...] - 72: query_get_at>> - at ./compiler/rustc_middle/src/query/plumbing.rs:145:17 - 73: analysis - at ./compiler/rustc_middle/src/query/plumbing.rs:423:31 - 74: analysis - at ./compiler/rustc_middle/src/query/plumbing.rs:414:35 - 75: {closure#5} - at ./compiler/rustc_driver_impl/src/lib.rs:445:52 - 76: {closure#1}> - at ./compiler/rustc_middle/src/ty/context.rs:1296:37 - 77: {closure#0}>, core::result::Result<(), rustc_span::ErrorGuaranteed>> - at ./compiler/rustc_middle/src/ty/context/tls.rs:82:9 - 78: try_with, rustc_middle::ty::context::tls::enter_context::{closure_env#0}>, core::result::Result<(), rustc_span::ErrorGuaranteed>>, core::result::Result<(), rustc_span::ErrorGuaranteed>> - at ./library/std/src/thread/local.rs:283:12 - 79: with, rustc_middle::ty::context::tls::enter_context::{closure_env#0}>, core::result::Result<(), rustc_span::ErrorGuaranteed>>, core::result::Result<(), rustc_span::ErrorGuaranteed>> - at ./library/std/src/thread/local.rs:260:9 - 80: enter_context>, core::result::Result<(), rustc_span::ErrorGuaranteed>> - at ./compiler/rustc_middle/src/ty/context/tls.rs:79:9 - 81: enter> - at ./compiler/rustc_middle/src/ty/context.rs:1296:9 - 82: {closure#1} - at ./compiler/rustc_driver_impl/src/lib.rs:445:13 - 83: enter, rustc_span::ErrorGuaranteed>> - at ./compiler/rustc_interface/src/queries.rs:202:19 - 84: {closure#0} - at ./compiler/rustc_driver_impl/src/lib.rs:389:22 - 85: {closure#1}, rustc_driver_impl::run_compiler::{closure_env#0}> - at ./compiler/rustc_interface/src/interface.rs:502:27 - 86: {closure#0}, rustc_driver_impl::run_compiler::{closure_env#0}>, core::result::Result<(), rustc_span::ErrorGuaranteed>> - at ./compiler/rustc_interface/src/util.rs:154:13 - 87: {closure#0}, rustc_driver_impl::run_compiler::{closure_env#0}>, core::result::Result<(), rustc_span::ErrorGuaranteed>>, core::result::Result<(), rustc_span::ErrorGuaranteed>> - at ./compiler/rustc_interface/src/util.rs:106:21 - 88: set, rustc_driver_impl::run_compiler::{closure_env#0}>, core::result::Result<(), rustc_span::ErrorGuaranteed>>, core::result::Result<(), rustc_span::ErrorGuaranteed>>, core::result::Result<(), rustc_span::ErrorGuaranteed>> - at /home/boxy/.cargo/registry/src/index.crates.io-6f17d22bba15001f/scoped-tls-1.0.1/src/lib.rs:137:9 - 89: create_session_globals_then, rustc_interface::util::run_in_thread_with_globals::{closure#0}::{closure#0}::{closure_env#0}, rustc_driver_impl::run_compiler::{closure_env#0}>, core::result::Result<(), rustc_span::ErrorGuaranteed>>, core::result::Result<(), rustc_span::ErrorGuaranteed>>> - at ./compiler/rustc_span/src/lib.rs:134:5 - 90: {closure#0}, rustc_driver_impl::run_compiler::{closure_env#0}>, core::result::Result<(), rustc_span::ErrorGuaranteed>>, core::result::Result<(), rustc_span::ErrorGuaranteed>> - at ./compiler/rustc_interface/src/util.rs:105:17 -note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. +error[E0367]: `Drop` impl requires `the constant `_` has type `usize`` but the struct it is implemented for does not + --> $DIR/unconstrained_const_param_on_drop.rs:3:6 + | +LL | impl Drop for Foo {} + | ^^^^^^^^^^^^^^^^^^^ + | +note: the implementor must specify the same requirement + --> $DIR/unconstrained_const_param_on_drop.rs:1:1 + | +LL | struct Foo {} + | ^^^^^^^^^^ -error: the compiler unexpectedly panicked. this is a bug. - -note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md - -note: please make sure that you have updated to the latest nightly - -note: rustc 1.81.0-dev running on x86_64-unknown-linux-gnu - -note: compiler flags: -Z threads=1 -Z simulate-remapped-rust-src-base=/rustc/FAKE_PREFIX -Z translate-remapped-path-to-local-path=no -Z ignore-directory-in-diagnostics-source-blocks=/home/boxy/.cargo -Z ignore-directory-in-diagnostics-source-blocks=/media/Nyoomies/Repos/rust/vendor -C codegen-units=1 -Z ui-testing -Z deduplicate-diagnostics=no -Z write-long-types-to-disk=no -C strip=debuginfo -C prefer-dynamic -C rpath -C debuginfo=0 - -query stack during panic: -#0 [adt_destructor] computing `Drop` impl for `Foo` -#1 [check_well_formed] checking that `Foo` is well-formed -#2 [check_mod_type_wf] checking that types are well-formed in top-level module -#3 [analysis] running analysis passes on this crate -end of query stack error[E0207]: the const parameter `UNUSED` is not constrained by the impl trait, self type, or predicates - --> $DIR/unconstrained_const_param_on_drop.rs:6:6 + --> $DIR/unconstrained_const_param_on_drop.rs:3:6 | LL | impl Drop for Foo {} | ^^^^^^^^^^^^^^^^^^^ unconstrained const parameter @@ -214,6 +19,7 @@ LL | impl Drop for Foo {} = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0207`. +Some errors have detailed explanations: E0207, E0367. +For more information about an error, try `rustc --explain E0207`. From 91af6b51223625ea5cd34d77861648ca19566deb Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Tue, 2 Jul 2024 15:00:09 -0700 Subject: [PATCH 025/734] Add edge-case examples to `{count,leading,trailing}_{ones,zeros}` methods Some architectures (i386) do not define a "count leading zeros" instruction, they define a "find first set bit" instruction (`bsf`) whose result is undefined when given zero (ie none of the bits are set). Of this family of bitwise operations, I always forget which of these things is potentially undefined for zero, and I'm also not 100% sure that Rust provides a hard guarantee for the results of these methods when given zero. So I figured there are others who have these same uncertainties, and it would be good to resolve them and answer the question via extending these doc examples/tests. See https://en.wikipedia.org/wiki/Find_first_set#Hardware_support for more info on i386 and `bsf` on zero. --- library/core/src/num/uint_macros.rs | 41 ++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index ad72c29758bd..40bc58204e80 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -65,8 +65,13 @@ macro_rules! uint_impl { /// /// ``` #[doc = concat!("let n = 0b01001100", stringify!($SelfT), ";")] - /// /// assert_eq!(n.count_ones(), 3); + /// + #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")] + #[doc = concat!("assert_eq!(max.count_ones(), ", stringify!($BITS), ");")] + /// + #[doc = concat!("let zero = 0", stringify!($SelfT), ";")] + /// assert_eq!(zero.count_ones(), 0); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] @@ -86,7 +91,11 @@ macro_rules! uint_impl { /// Basic usage: /// /// ``` - #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 0);")] + #[doc = concat!("let zero = 0", stringify!($SelfT), ";")] + #[doc = concat!("assert_eq!(zero.count_zeros(), ", stringify!($BITS), ");")] + /// + #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")] + /// assert_eq!(max.count_zeros(), 0); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] @@ -108,8 +117,13 @@ macro_rules! uint_impl { /// /// ``` #[doc = concat!("let n = ", stringify!($SelfT), "::MAX >> 2;")] - /// /// assert_eq!(n.leading_zeros(), 2); + /// + #[doc = concat!("let zero = 0", stringify!($SelfT), ";")] + #[doc = concat!("assert_eq!(zero.leading_zeros(), ", stringify!($BITS), ");")] + /// + #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")] + /// assert_eq!(max.leading_zeros(), 0); /// ``` #[doc = concat!("[`ilog2`]: ", stringify!($SelfT), "::ilog2")] #[stable(feature = "rust1", since = "1.0.0")] @@ -130,8 +144,13 @@ macro_rules! uint_impl { /// /// ``` #[doc = concat!("let n = 0b0101000", stringify!($SelfT), ";")] - /// /// assert_eq!(n.trailing_zeros(), 3); + /// + #[doc = concat!("let zero = 0", stringify!($SelfT), ";")] + #[doc = concat!("assert_eq!(zero.trailing_zeros(), ", stringify!($BITS), ");")] + /// + #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")] + #[doc = concat!("assert_eq!(max.trailing_zeros(), 0);")] /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] @@ -150,8 +169,13 @@ macro_rules! uint_impl { /// /// ``` #[doc = concat!("let n = !(", stringify!($SelfT), "::MAX >> 2);")] - /// /// assert_eq!(n.leading_ones(), 2); + /// + #[doc = concat!("let zero = 0", stringify!($SelfT), ";")] + /// assert_eq!(zero.leading_ones(), 0); + /// + #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")] + #[doc = concat!("assert_eq!(max.leading_ones(), ", stringify!($BITS), ");")] /// ``` #[stable(feature = "leading_trailing_ones", since = "1.46.0")] #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] @@ -171,8 +195,13 @@ macro_rules! uint_impl { /// /// ``` #[doc = concat!("let n = 0b1010111", stringify!($SelfT), ";")] - /// /// assert_eq!(n.trailing_ones(), 3); + /// + #[doc = concat!("let zero = 0", stringify!($SelfT), ";")] + /// assert_eq!(zero.trailing_ones(), 0); + /// + #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")] + #[doc = concat!("assert_eq!(max.trailing_ones(), ", stringify!($BITS), ");")] /// ``` #[stable(feature = "leading_trailing_ones", since = "1.46.0")] #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] From c90b6b8d2937cc116c635aa5c58f90afcc535248 Mon Sep 17 00:00:00 2001 From: Skgland Date: Thu, 9 May 2024 15:41:15 +0200 Subject: [PATCH 026/734] stabilize `const_int_from_str` --- library/core/src/lib.rs | 1 - library/core/src/num/error.rs | 2 +- library/core/src/num/mod.rs | 6 ++++-- library/core/tests/lib.rs | 1 - tests/ui/consts/const-eval/parse_ints.rs | 2 -- tests/ui/consts/const-eval/parse_ints.stderr | 4 ++-- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index c5a1fca667bc..ef90333596fd 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -128,7 +128,6 @@ #![feature(const_hash)] #![feature(const_heap)] #![feature(const_index_range_slice_index)] -#![feature(const_int_from_str)] #![feature(const_intrinsic_copy)] #![feature(const_intrinsic_forget)] #![feature(const_ipv4)] diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index a2d7e6f7b075..b8e22a8aef95 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -113,7 +113,7 @@ pub enum IntErrorKind { impl ParseIntError { /// Outputs the detailed cause of parsing an integer failing. #[must_use] - #[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")] + #[rustc_const_stable(feature = "const_int_from_str", since = "CURRENT_RUSTC_VERSION")] #[stable(feature = "int_error_matching", since = "1.55.0")] pub const fn kind(&self) -> &IntErrorKind { &self.kind diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 034af6a0d573..6010f7cee06e 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1387,6 +1387,7 @@ from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } #[doc(hidden)] #[inline(always)] #[unstable(issue = "none", feature = "std_internals")] +#[rustc_const_unstable(issue = "none", feature = "const_int_cannot_overflow")] pub const fn can_not_overflow(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool { radix <= 16 && digits.len() <= mem::size_of::() * 2 - is_signed_ty as usize } @@ -1410,6 +1411,7 @@ const fn from_str_radix_panic(radix: u32) { intrinsics::const_eval_select((radix,), from_str_radix_panic_ct, from_str_radix_panic_rt); } +#[allow_internal_unstable(const_int_cannot_overflow)] macro_rules! from_str_radix { ($($int_ty:ty)+) => {$( impl $int_ty { @@ -1436,7 +1438,7 @@ macro_rules! from_str_radix { #[doc = concat!("assert_eq!(", stringify!($int_ty), "::from_str_radix(\"A\", 16), Ok(10));")] /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")] + #[rustc_const_stable(feature = "const_int_from_str", since = "CURRENT_RUSTC_VERSION")] pub const fn from_str_radix(src: &str, radix: u32) -> Result<$int_ty, ParseIntError> { use self::IntErrorKind::*; use self::ParseIntError as PIE; @@ -1566,7 +1568,7 @@ macro_rules! from_str_radix_size_impl { #[doc = concat!("assert_eq!(", stringify!($size), "::from_str_radix(\"A\", 16), Ok(10));")] /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")] + #[rustc_const_stable(feature = "const_int_from_str", since = "CURRENT_RUSTC_VERSION")] pub const fn from_str_radix(src: &str, radix: u32) -> Result<$size, ParseIntError> { match <$t>::from_str_radix(src, radix) { Ok(x) => Ok(x as $size), diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 83a615fcd8be..feef5e81480c 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -16,7 +16,6 @@ #![feature(const_hash)] #![feature(const_heap)] #![feature(const_intrinsic_copy)] -#![feature(const_int_from_str)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_nonnull_new)] #![feature(const_pointer_is_aligned)] diff --git a/tests/ui/consts/const-eval/parse_ints.rs b/tests/ui/consts/const-eval/parse_ints.rs index ff9fc47e65c3..cb9a3eb43129 100644 --- a/tests/ui/consts/const-eval/parse_ints.rs +++ b/tests/ui/consts/const-eval/parse_ints.rs @@ -1,5 +1,3 @@ -#![feature(const_int_from_str)] - const _OK: () = match i32::from_str_radix("-1234", 10) { Ok(x) => assert!(x == -1234), Err(_) => panic!(), diff --git a/tests/ui/consts/const-eval/parse_ints.stderr b/tests/ui/consts/const-eval/parse_ints.stderr index 9e49fe433a12..ec9249ece8e3 100644 --- a/tests/ui/consts/const-eval/parse_ints.stderr +++ b/tests/ui/consts/const-eval/parse_ints.stderr @@ -6,7 +6,7 @@ error[E0080]: evaluation of constant value failed note: inside `core::num::::from_str_radix` --> $SRC_DIR/core/src/num/mod.rs:LL:COL note: inside `_TOO_LOW` - --> $DIR/parse_ints.rs:7:24 + --> $DIR/parse_ints.rs:5:24 | LL | const _TOO_LOW: () = { u64::from_str_radix("12345ABCD", 1); }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ error[E0080]: evaluation of constant value failed note: inside `core::num::::from_str_radix` --> $SRC_DIR/core/src/num/mod.rs:LL:COL note: inside `_TOO_HIGH` - --> $DIR/parse_ints.rs:8:25 + --> $DIR/parse_ints.rs:6:25 | LL | const _TOO_HIGH: () = { u64::from_str_radix("12345ABCD", 37); }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From eb799cf634a811d1e0d719d30cba83d5611f87c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 4 Jul 2024 20:51:50 +0200 Subject: [PATCH 027/734] mark `can_not_overflow` as `#[rustc_const_stable(...)]` see https://github.com/rust-lang/rust/pull/124941#discussion_r1664676739 --- library/core/src/num/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 6010f7cee06e..0522365e22e0 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1387,7 +1387,7 @@ from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } #[doc(hidden)] #[inline(always)] #[unstable(issue = "none", feature = "std_internals")] -#[rustc_const_unstable(issue = "none", feature = "const_int_cannot_overflow")] +#[rustc_const_stable(feature = "const_int_from_str", since = "CURRENT_RUSTC_VERSION")] pub const fn can_not_overflow(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool { radix <= 16 && digits.len() <= mem::size_of::() * 2 - is_signed_ty as usize } @@ -1411,7 +1411,6 @@ const fn from_str_radix_panic(radix: u32) { intrinsics::const_eval_select((radix,), from_str_radix_panic_ct, from_str_radix_panic_rt); } -#[allow_internal_unstable(const_int_cannot_overflow)] macro_rules! from_str_radix { ($($int_ty:ty)+) => {$( impl $int_ty { From f99df29d9dcc1c313593967c8c390fae39d462d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 4 Jul 2024 21:23:55 +0200 Subject: [PATCH 028/734] fix tests after rebase --- src/tools/clippy/tests/ui/from_str_radix_10.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.rs b/src/tools/clippy/tests/ui/from_str_radix_10.rs index 2d5b351f8da3..0df6a0a202ae 100644 --- a/src/tools/clippy/tests/ui/from_str_radix_10.rs +++ b/src/tools/clippy/tests/ui/from_str_radix_10.rs @@ -1,4 +1,3 @@ -#![feature(const_int_from_str)] #![warn(clippy::from_str_radix_10)] mod some_mod { @@ -61,7 +60,8 @@ fn main() -> Result<(), Box> { Ok(()) } -fn issue_12732() { +// https://github.com/rust-lang/rust-clippy/issues/12731 +fn issue_12731() { const A: Result = u32::from_str_radix("123", 10); const B: () = { let _ = u32::from_str_radix("123", 10); From 404519a6e5a2e95d0b8f057e35a7d6280fb9c562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 4 Jul 2024 22:31:53 +0200 Subject: [PATCH 029/734] bless tests --- .../clippy/tests/ui/from_str_radix_10.fixed | 4 ++-- .../clippy/tests/ui/from_str_radix_10.stderr | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.fixed b/src/tools/clippy/tests/ui/from_str_radix_10.fixed index f9ce1defda17..6c582190b442 100644 --- a/src/tools/clippy/tests/ui/from_str_radix_10.fixed +++ b/src/tools/clippy/tests/ui/from_str_radix_10.fixed @@ -1,4 +1,3 @@ -#![feature(const_int_from_str)] #![warn(clippy::from_str_radix_10)] mod some_mod { @@ -61,7 +60,8 @@ fn main() -> Result<(), Box> { Ok(()) } -fn issue_12732() { +// https://github.com/rust-lang/rust-clippy/issues/12731 +fn issue_12731() { const A: Result = u32::from_str_radix("123", 10); const B: () = { let _ = u32::from_str_radix("123", 10); diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.stderr b/src/tools/clippy/tests/ui/from_str_radix_10.stderr index 01a1bf8940a1..4aa84eca2612 100644 --- a/src/tools/clippy/tests/ui/from_str_radix_10.stderr +++ b/src/tools/clippy/tests/ui/from_str_radix_10.stderr @@ -1,5 +1,5 @@ error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:29:5 + --> tests/ui/from_str_radix_10.rs:28:5 | LL | u32::from_str_radix("30", 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"30".parse::()` @@ -8,43 +8,43 @@ LL | u32::from_str_radix("30", 10)?; = help: to override `-D warnings` add `#[allow(clippy::from_str_radix_10)]` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:32:5 + --> tests/ui/from_str_radix_10.rs:31:5 | LL | i64::from_str_radix("24", 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"24".parse::()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:34:5 + --> tests/ui/from_str_radix_10.rs:33:5 | LL | isize::from_str_radix("100", 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"100".parse::()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:36:5 + --> tests/ui/from_str_radix_10.rs:35:5 | LL | u8::from_str_radix("7", 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"7".parse::()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:38:5 + --> tests/ui/from_str_radix_10.rs:37:5 | LL | u16::from_str_radix(&("10".to_owned() + "5"), 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `("10".to_owned() + "5").parse::()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:40:5 + --> tests/ui/from_str_radix_10.rs:39:5 | LL | i128::from_str_radix(Test + Test, 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(Test + Test).parse::()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:44:5 + --> tests/ui/from_str_radix_10.rs:43:5 | LL | i32::from_str_radix(string, 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.parse::()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:48:5 + --> tests/ui/from_str_radix_10.rs:47:5 | LL | i32::from_str_radix(&stringier, 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `stringier.parse::()` From 52fb17a25616f870b5049aa65e3ebc351c4737c7 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Thu, 4 Jul 2024 13:00:55 -0700 Subject: [PATCH 030/734] Move a few intrinsics to use Rust abi Move a few more intrinsic functions to the convention added in #121192 where they have Rust abi but are tagged with `rustc_intrinsic`. --- library/core/src/intrinsics.rs | 203 ++++++++++++++++++++++++--------- 1 file changed, 146 insertions(+), 57 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 720da0feecee..255bc60f7a3c 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -947,7 +947,6 @@ extern "rust-intrinsic" { #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")] #[rustc_nounwind] pub fn unreachable() -> !; - } /// Informs the optimizer that a condition is always true. @@ -1018,78 +1017,40 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn breakpoint(); - /// The size of a type in bytes. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// More specifically, this is the offset in bytes between successive - /// items of the same type, including alignment padding. - /// - /// The stabilized version of this intrinsic is [`core::mem::size_of`]. + #[cfg(bootstrap)] #[rustc_const_stable(feature = "const_size_of", since = "1.40.0")] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn size_of() -> usize; - /// The minimum alignment of a type. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is [`core::mem::align_of`]. + #[cfg(bootstrap)] #[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn min_align_of() -> usize; - /// The preferred alignment of a type. - /// - /// This intrinsic does not have a stable counterpart. - /// It's "tracking issue" is [#91971](https://github.com/rust-lang/rust/issues/91971). + + #[cfg(bootstrap)] #[rustc_const_unstable(feature = "const_pref_align_of", issue = "91971")] #[rustc_nounwind] pub fn pref_align_of() -> usize; - /// The size of the referenced value in bytes. - /// - /// The stabilized version of this intrinsic is [`crate::mem::size_of_val`]. + #[cfg(bootstrap)] #[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")] #[rustc_nounwind] pub fn size_of_val(_: *const T) -> usize; - /// The required alignment of the referenced value. - /// - /// The stabilized version of this intrinsic is [`core::mem::align_of_val`]. + + #[cfg(bootstrap)] #[rustc_const_unstable(feature = "const_align_of_val", issue = "46571")] #[rustc_nounwind] pub fn min_align_of_val(_: *const T) -> usize; - /// Gets a static string slice containing the name of a type. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is [`core::any::type_name`]. + #[cfg(bootstrap)] #[rustc_const_unstable(feature = "const_type_name", issue = "63084")] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn type_name() -> &'static str; - /// Gets an identifier which is globally unique to the specified type. This - /// function will return the same value for a type regardless of whichever - /// crate it is invoked in. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is [`core::any::TypeId::of`]. + #[cfg(bootstrap)] #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] #[rustc_safe_intrinsic] #[rustc_nounwind] @@ -2424,15 +2385,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn discriminant_value(v: &T) -> ::Discriminant; - /// Returns the number of variants of the type `T` cast to a `usize`; - /// if `T` has no variants, returns `0`. Uninhabited variants will be counted. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The to-be-stabilized version of this intrinsic is [`crate::mem::variant_count`]. + #[cfg(bootstrap)] #[rustc_const_unstable(feature = "variant_count", issue = "73662")] #[rustc_safe_intrinsic] #[rustc_nounwind] @@ -2793,6 +2746,142 @@ pub unsafe fn vtable_align(_ptr: *const ()) -> usize { unreachable!() } +/// The size of a type in bytes. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// More specifically, this is the offset in bytes between successive +/// items of the same type, including alignment padding. +/// +/// The stabilized version of this intrinsic is [`core::mem::size_of`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_stable(feature = "const_size_of", since = "1.40.0")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const fn size_of() -> usize { + unreachable!() +} + +/// The minimum alignment of a type. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is [`core::mem::align_of`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const fn min_align_of() -> usize { + unreachable!() +} + +/// The preferred alignment of a type. +/// +/// This intrinsic does not have a stable counterpart. +/// It's "tracking issue" is [#91971](https://github.com/rust-lang/rust/issues/91971). +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "const_pref_align_of", issue = "91971")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const unsafe fn pref_align_of() -> usize { + unreachable!() +} + +/// Returns the number of variants of the type `T` cast to a `usize`; +/// if `T` has no variants, returns `0`. Uninhabited variants will be counted. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The to-be-stabilized version of this intrinsic is [`crate::mem::variant_count`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "variant_count", issue = "73662")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const fn variant_count() -> usize { + unreachable!() +} + +/// The size of the referenced value in bytes. +/// +/// The stabilized version of this intrinsic is [`crate::mem::size_of_val`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const unsafe fn size_of_val(_ptr: *const T) -> usize { + unreachable!() +} + +/// The required alignment of the referenced value. +/// +/// The stabilized version of this intrinsic is [`core::mem::align_of_val`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "const_align_of_val", issue = "46571")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const unsafe fn min_align_of_val(_ptr: *const T) -> usize { + unreachable!() +} + +/// Gets a static string slice containing the name of a type. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is [`core::any::type_name`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "const_type_name", issue = "63084")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const fn type_name() -> &'static str { + unreachable!() +} + +/// Gets an identifier which is globally unique to the specified type. This +/// function will return the same value for a type regardless of whichever +/// crate it is invoked in. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is [`core::any::TypeId::of`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "const_type_id", issue = "77125")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const fn type_id() -> u128 { + unreachable!() +} + /// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`. /// /// This is used to implement functions like `slice::from_raw_parts_mut` and From f27023ad8df2779351054a10dda6f3379aa43d6b Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Thu, 4 Jul 2024 13:44:59 -0700 Subject: [PATCH 031/734] Document safety of a few intrinsics --- library/core/src/intrinsics.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 255bc60f7a3c..c4c638833894 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2726,8 +2726,11 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) // Runtime NOP } -/// `ptr` must point to a vtable. /// The intrinsic will return the size stored in that vtable. +/// +/// # Safety +/// +/// `ptr` must point to a vtable. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] @@ -2736,8 +2739,11 @@ pub unsafe fn vtable_size(_ptr: *const ()) -> usize { unreachable!() } -/// `ptr` must point to a vtable. /// The intrinsic will return the alignment stored in that vtable. +/// +/// # Safety +/// +/// `ptr` must point to a vtable. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] @@ -2821,6 +2827,10 @@ pub const fn variant_count() -> usize { /// The size of the referenced value in bytes. /// /// The stabilized version of this intrinsic is [`crate::mem::size_of_val`]. +/// +/// # Safety +/// +/// See [`crate::mem::size_of_val_raw`] for safety conditions. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")] @@ -2834,6 +2844,10 @@ pub const unsafe fn size_of_val(_ptr: *const T) -> usize { /// The required alignment of the referenced value. /// /// The stabilized version of this intrinsic is [`core::mem::align_of_val`]. +/// +/// # Safety +/// +/// See [`crate::mem::align_of_val_raw`] for safety conditions. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_const_unstable(feature = "const_align_of_val", issue = "46571")] From b096c08a86aa3d51b91a0d7bbf917119e2fd2e76 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Thu, 4 Jul 2024 16:12:52 -0700 Subject: [PATCH 032/734] Fix tests after intrinsic Abi change --- ...ower_intrinsics.non_const.LowerIntrinsics.panic-abort.diff | 4 ++-- ...wer_intrinsics.non_const.LowerIntrinsics.panic-unwind.diff | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.panic-abort.diff index 801e28ff2f4f..069a82b95215 100644 --- a/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.panic-abort.diff +++ b/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.panic-abort.diff @@ -3,8 +3,8 @@ fn non_const() -> usize { let mut _0: usize; - let _1: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}; - let mut _2: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}; + let _1: fn() -> usize {std::intrinsics::size_of::}; + let mut _2: fn() -> usize {std::intrinsics::size_of::}; scope 1 { debug size_of_t => _1; } diff --git a/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.panic-unwind.diff index 801e28ff2f4f..069a82b95215 100644 --- a/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.panic-unwind.diff +++ b/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.panic-unwind.diff @@ -3,8 +3,8 @@ fn non_const() -> usize { let mut _0: usize; - let _1: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}; - let mut _2: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}; + let _1: fn() -> usize {std::intrinsics::size_of::}; + let mut _2: fn() -> usize {std::intrinsics::size_of::}; scope 1 { debug size_of_t => _1; } From 5834772177540912b53dc4f19413a4ba3c804ea4 Mon Sep 17 00:00:00 2001 From: Veera Date: Thu, 4 Jul 2024 19:16:47 -0400 Subject: [PATCH 033/734] Update Tests --- ...ced-return-type-complex-type-issue-126311.rs | 5 +++++ ...return-type-complex-type-issue-126311.stderr | 14 ++++++++++++++ .../misplaced-return-type-issue-126311.rs | 5 +++++ .../misplaced-return-type-issue-126311.stderr | 14 ++++++++++++++ ...turn-type-where-in-next-line-issue-126311.rs | 11 +++++++++++ ...-type-where-in-next-line-issue-126311.stderr | 17 +++++++++++++++++ ...ced-return-type-without-type-issue-126311.rs | 6 ++++++ ...return-type-without-type-issue-126311.stderr | 8 ++++++++ ...ed-return-type-without-where-issue-126311.rs | 4 ++++ ...eturn-type-without-where-issue-126311.stderr | 8 ++++++++ 10 files changed, 92 insertions(+) create mode 100644 tests/ui/parser/issues/misplaced-return-type-complex-type-issue-126311.rs create mode 100644 tests/ui/parser/issues/misplaced-return-type-complex-type-issue-126311.stderr create mode 100644 tests/ui/parser/issues/misplaced-return-type-issue-126311.rs create mode 100644 tests/ui/parser/issues/misplaced-return-type-issue-126311.stderr create mode 100644 tests/ui/parser/issues/misplaced-return-type-where-in-next-line-issue-126311.rs create mode 100644 tests/ui/parser/issues/misplaced-return-type-where-in-next-line-issue-126311.stderr create mode 100644 tests/ui/parser/issues/misplaced-return-type-without-type-issue-126311.rs create mode 100644 tests/ui/parser/issues/misplaced-return-type-without-type-issue-126311.stderr create mode 100644 tests/ui/parser/issues/misplaced-return-type-without-where-issue-126311.rs create mode 100644 tests/ui/parser/issues/misplaced-return-type-without-where-issue-126311.stderr diff --git a/tests/ui/parser/issues/misplaced-return-type-complex-type-issue-126311.rs b/tests/ui/parser/issues/misplaced-return-type-complex-type-issue-126311.rs new file mode 100644 index 000000000000..722303dd0348 --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-complex-type-issue-126311.rs @@ -0,0 +1,5 @@ +fn foo() where T: Default -> impl Default + 'static {} +//~^ ERROR return type should be specified after the function parameters +//~| HELP place the return type after the function parameters + +fn main() {} diff --git a/tests/ui/parser/issues/misplaced-return-type-complex-type-issue-126311.stderr b/tests/ui/parser/issues/misplaced-return-type-complex-type-issue-126311.stderr new file mode 100644 index 000000000000..2ce3b78bb8ba --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-complex-type-issue-126311.stderr @@ -0,0 +1,14 @@ +error: return type should be specified after the function parameters + --> $DIR/misplaced-return-type-complex-type-issue-126311.rs:1:30 + | +LL | fn foo() where T: Default -> impl Default + 'static {} + | ^^ expected one of `(`, `+`, `,`, `::`, `<`, or `{` + | +help: place the return type after the function parameters + | +LL - fn foo() where T: Default -> impl Default + 'static {} +LL + fn foo() -> impl Default + 'static where T: Default {} + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/issues/misplaced-return-type-issue-126311.rs b/tests/ui/parser/issues/misplaced-return-type-issue-126311.rs new file mode 100644 index 000000000000..ad164f77beea --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-issue-126311.rs @@ -0,0 +1,5 @@ +fn foo() where T: Default -> u8 {} +//~^ ERROR return type should be specified after the function parameters +//~| HELP place the return type after the function parameters + +fn main() {} diff --git a/tests/ui/parser/issues/misplaced-return-type-issue-126311.stderr b/tests/ui/parser/issues/misplaced-return-type-issue-126311.stderr new file mode 100644 index 000000000000..e473b902ce3e --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-issue-126311.stderr @@ -0,0 +1,14 @@ +error: return type should be specified after the function parameters + --> $DIR/misplaced-return-type-issue-126311.rs:1:30 + | +LL | fn foo() where T: Default -> u8 {} + | ^^ expected one of `(`, `+`, `,`, `::`, `<`, or `{` + | +help: place the return type after the function parameters + | +LL - fn foo() where T: Default -> u8 {} +LL + fn foo() -> u8 where T: Default {} + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/issues/misplaced-return-type-where-in-next-line-issue-126311.rs b/tests/ui/parser/issues/misplaced-return-type-where-in-next-line-issue-126311.rs new file mode 100644 index 000000000000..782d7d5ee490 --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-where-in-next-line-issue-126311.rs @@ -0,0 +1,11 @@ +fn foo() +//~^ HELP place the return type after the function parameters +where + T: Default, + K: Clone, -> Result +//~^ ERROR return type should be specified after the function parameters +{ + Ok(0) +} + +fn main() {} diff --git a/tests/ui/parser/issues/misplaced-return-type-where-in-next-line-issue-126311.stderr b/tests/ui/parser/issues/misplaced-return-type-where-in-next-line-issue-126311.stderr new file mode 100644 index 000000000000..196a46d7ea54 --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-where-in-next-line-issue-126311.stderr @@ -0,0 +1,17 @@ +error: return type should be specified after the function parameters + --> $DIR/misplaced-return-type-where-in-next-line-issue-126311.rs:5:15 + | +LL | K: Clone, -> Result + | ^^ expected one of `{`, lifetime, or type + | +help: place the return type after the function parameters + | +LL ~ fn foo() -> Result +LL | +LL | where +LL | T: Default, +LL ~ K: Clone, + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/issues/misplaced-return-type-without-type-issue-126311.rs b/tests/ui/parser/issues/misplaced-return-type-without-type-issue-126311.rs new file mode 100644 index 000000000000..2c09edbc7926 --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-without-type-issue-126311.rs @@ -0,0 +1,6 @@ +fn foo() where T: Default -> { +//~^ ERROR expected one of `(`, `+`, `,`, `::`, `<`, or `{`, found `->` + 0 +} + +fn main() {} diff --git a/tests/ui/parser/issues/misplaced-return-type-without-type-issue-126311.stderr b/tests/ui/parser/issues/misplaced-return-type-without-type-issue-126311.stderr new file mode 100644 index 000000000000..0eb3bb7d8126 --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-without-type-issue-126311.stderr @@ -0,0 +1,8 @@ +error: expected one of `(`, `+`, `,`, `::`, `<`, or `{`, found `->` + --> $DIR/misplaced-return-type-without-type-issue-126311.rs:1:30 + | +LL | fn foo() where T: Default -> { + | ^^ expected one of `(`, `+`, `,`, `::`, `<`, or `{` + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/issues/misplaced-return-type-without-where-issue-126311.rs b/tests/ui/parser/issues/misplaced-return-type-without-where-issue-126311.rs new file mode 100644 index 000000000000..672233674a05 --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-without-where-issue-126311.rs @@ -0,0 +1,4 @@ +fn bar() -> u8 -> u64 {} +//~^ ERROR expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found `->` + +fn main() {} diff --git a/tests/ui/parser/issues/misplaced-return-type-without-where-issue-126311.stderr b/tests/ui/parser/issues/misplaced-return-type-without-where-issue-126311.stderr new file mode 100644 index 000000000000..730904d3671f --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-without-where-issue-126311.stderr @@ -0,0 +1,8 @@ +error: expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found `->` + --> $DIR/misplaced-return-type-without-where-issue-126311.rs:1:19 + | +LL | fn bar() -> u8 -> u64 {} + | ^^ expected one of 7 possible tokens + +error: aborting due to 1 previous error + From dd9e8c835afffc67f0d694abb78bf8b40f87aa97 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 8 Jun 2024 18:50:07 -0400 Subject: [PATCH 034/734] Refactor `arc_with_non_send_sync` * Check HIR beffore type checking * Only lint when `Arc::new` is called --- clippy_lints/src/arc_with_non_send_sync.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs index d57ab539fff4..4eafa330fafa 100644 --- a/clippy_lints/src/arc_with_non_send_sync.rs +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_from_proc_macro; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{is_from_proc_macro, last_path_segment}; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; @@ -42,12 +42,11 @@ declare_lint_pass!(ArcWithNonSendSync => [ARC_WITH_NON_SEND_SYNC]); impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if !expr.span.from_expansion() - && let ty = cx.typeck_results().expr_ty(expr) - && is_type_diagnostic_item(cx, ty, sym::Arc) - && let ExprKind::Call(func, [arg]) = expr.kind - && let ExprKind::Path(func_path) = func.kind - && last_path_segment(&func_path).ident.name == sym::new + if let ExprKind::Call(func, [arg]) = expr.kind + && let ExprKind::Path(QPath::TypeRelative(func_ty, func_name)) = func.kind + && func_name.ident.name == sym::new + && !expr.span.from_expansion() + && is_type_diagnostic_item(cx, cx.typeck_results().node_type(func_ty.hir_id), sym::Arc) && let arg_ty = cx.typeck_results().expr_ty(arg) // make sure that the type is not and does not contain any type parameters && arg_ty.walk().all(|arg| { From 01f53c2c160a6efe3080a2fe01b87c5732f860d1 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 8 Jun 2024 22:15:01 -0400 Subject: [PATCH 035/734] Refactor `borrow_deref_ref`: Match HIR tree before checking for macros. --- clippy_lints/src/borrow_deref_ref.rs | 44 +++++++++++++--------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index 0ca4a0e067d3..bd123a725a73 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -49,35 +49,31 @@ declare_lint_pass!(BorrowDerefRef => [BORROW_DEREF_REF]); impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) { - if !e.span.from_expansion() - && let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind - && !addrof_target.span.from_expansion() + if let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind && let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind - && !deref_target.span.from_expansion() && !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..)) + && !e.span.from_expansion() + && !deref_target.span.from_expansion() + && !addrof_target.span.from_expansion() && let ref_ty = cx.typeck_results().expr_ty(deref_target) && let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind() + && get_parent_expr(cx, e).map_or(true, |parent| { + match parent.kind { + // `*&*foo` should lint `deref_addrof` instead. + ExprKind::Unary(UnOp::Deref, _) => is_lint_allowed(cx, DEREF_ADDROF, parent.hir_id), + // `&*foo` creates a distinct temporary from `foo` + ExprKind::AddrOf(_, Mutability::Mut, _) => !matches!( + deref_target.kind, + ExprKind::Path(..) + | ExprKind::Field(..) + | ExprKind::Index(..) + | ExprKind::Unary(UnOp::Deref, ..) + ), + _ => true, + } + }) + && !is_from_proc_macro(cx, e) { - if let Some(parent_expr) = get_parent_expr(cx, e) { - if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..)) - && !is_lint_allowed(cx, DEREF_ADDROF, parent_expr.hir_id) - { - return; - } - - // modification to `&mut &*x` is different from `&mut x` - if matches!( - deref_target.kind, - ExprKind::Path(..) | ExprKind::Field(..) | ExprKind::Index(..) | ExprKind::Unary(UnOp::Deref, ..) - ) && matches!(parent_expr.kind, ExprKind::AddrOf(_, Mutability::Mut, _)) - { - return; - } - } - if is_from_proc_macro(cx, e) { - return; - } - span_lint_and_then( cx, BORROW_DEREF_REF, From 39cd58ee7557cd0d45b547e9a57fee711fe0e3a0 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 8 Jun 2024 23:14:44 -0400 Subject: [PATCH 036/734] Refactor `collapsible_if`: Check AST before checking for macros --- clippy_lints/src/collapsible_if.rs | 33 +++++++++++------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 07b02c98df15..f311c052ad6e 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -93,20 +93,14 @@ declare_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF, COLLAPSIBLE_ELSE_IF]); impl EarlyLintPass for CollapsibleIf { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { - if !expr.span.from_expansion() { - check_if(cx, expr); - } - } -} - -fn check_if(cx: &EarlyContext<'_>, expr: &ast::Expr) { - if let ast::ExprKind::If(check, then, else_) = &expr.kind { - if let Some(else_) = else_ { - check_collapsible_maybe_if_let(cx, then.span, else_); - } else if let ast::ExprKind::Let(..) = check.kind { - // Prevent triggering on `if let a = b { if c { .. } }`. - } else { - check_collapsible_no_if_let(cx, expr, check, then); + if let ast::ExprKind::If(cond, then, else_) = &expr.kind + && !expr.span.from_expansion() + { + if let Some(else_) = else_ { + check_collapsible_maybe_if_let(cx, then.span, else_); + } else if !matches!(cond.kind, ast::ExprKind::Let(..)) { + check_collapsible_no_if_let(cx, expr, cond, then); + } } } } @@ -189,13 +183,10 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: & /// If the block contains only one expression, return it. fn expr_block(block: &ast::Block) -> Option<&ast::Expr> { - let mut it = block.stmts.iter(); - - if let (Some(stmt), None) = (it.next(), it.next()) { - match stmt.kind { - ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => Some(expr), - _ => None, - } + if let [stmt] = &*block.stmts + && let ast::StmtKind::Expr(expr) | ast::StmtKind::Semi(expr) = &stmt.kind + { + Some(expr) } else { None } From 1f530ab7e2bd74efdfc5c0ac7f1c0d9f8df8c029 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 8 Jun 2024 23:56:24 -0400 Subject: [PATCH 037/734] Refactor `collection_is_never_read`: Check HIR tree before checking types. --- clippy_lints/src/collection_is_never_read.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index 28d9f68d504c..eebda3ff76fd 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -59,9 +59,9 @@ static COLLECTIONS: [Symbol; 9] = [ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { - // Look for local variables whose type is a container. Search surrounding bock for read access. - if match_acceptable_type(cx, local, &COLLECTIONS) - && let PatKind::Binding(_, local_id, _, _) = local.pat.kind + // Look for local variables whose type is a container. Search surrounding block for read access. + if let PatKind::Binding(_, local_id, _, _) = local.pat.kind + && match_acceptable_type(cx, local, &COLLECTIONS) && let Some(enclosing_block) = get_enclosing_block(cx, local.hir_id) && has_no_read_access(cx, local_id, enclosing_block) { From d15ec0ff852f8e1befc34e83dc2865b78f506898 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 9 Jun 2024 00:03:20 -0400 Subject: [PATCH 038/734] Refactor `crate_in_macro_def`: * Don't clone the token stream * Check the HIR tree before reading attributes --- clippy_lints/src/crate_in_macro_def.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs index adf6f7c47375..678bdbc0ffb8 100644 --- a/clippy_lints/src/crate_in_macro_def.rs +++ b/clippy_lints/src/crate_in_macro_def.rs @@ -53,10 +53,9 @@ declare_lint_pass!(CrateInMacroDef => [CRATE_IN_MACRO_DEF]); impl EarlyLintPass for CrateInMacroDef { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if item.attrs.iter().any(is_macro_export) - && let ItemKind::MacroDef(macro_def) = &item.kind - && let tts = macro_def.body.tokens.clone() - && let Some(span) = contains_unhygienic_crate_reference(&tts) + if let ItemKind::MacroDef(macro_def) = &item.kind + && item.attrs.iter().any(is_macro_export) + && let Some(span) = contains_unhygienic_crate_reference(¯o_def.body.tokens) { span_lint_and_sugg( cx, From 441500b55b4529e8ba231c8b7165f8686f32e67c Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 9 Jun 2024 22:29:11 -0400 Subject: [PATCH 039/734] Refactor `else_if_without_else`: Check the AST before the macro check. --- clippy_lints/src/else_if_without_else.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index bb6f9aac2236..7a6dc4697276 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -50,12 +50,9 @@ declare_lint_pass!(ElseIfWithoutElse => [ELSE_IF_WITHOUT_ELSE]); impl EarlyLintPass for ElseIfWithoutElse { fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) { - if in_external_macro(cx.sess(), item.span) { - return; - } - if let ExprKind::If(_, _, Some(ref els)) = item.kind && let ExprKind::If(_, _, None) = els.kind + && !in_external_macro(cx.sess(), item.span) { span_lint_and_help( cx, From d1dcd918e72e62bbf81c01c1b4cebaf1d9a4eb6f Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 10 Jun 2024 01:40:06 -0400 Subject: [PATCH 040/734] `equatable_if_let`: Check HIR tree before checking for macros. --- clippy_lints/src/equatable_if_let.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index 37442bf3e286..fb9f2b1526e3 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -70,9 +70,9 @@ fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: T impl<'tcx> LateLintPass<'tcx> for PatternEquality { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if !in_external_macro(cx.sess(), expr.span) - && let ExprKind::Let(let_expr) = expr.kind + if let ExprKind::Let(let_expr) = expr.kind && unary_pattern(let_expr.pat) + && !in_external_macro(cx.sess(), expr.span) { let exp_ty = cx.typeck_results().expr_ty(let_expr.init); let pat_ty = cx.typeck_results().pat_ty(let_expr.pat); From 672b8b512a7c5bd6c30091647a637cfede97f8aa Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 9 Jun 2024 22:32:55 -0400 Subject: [PATCH 041/734] Refactor `empty_enums`: Check the HIR tree before the feature check. --- clippy_lints/src/empty_enum.rs | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index d16714695cb7..1869faab1d32 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -64,25 +64,21 @@ declare_lint_pass!(EmptyEnum => [EMPTY_ENUM]); impl<'tcx> LateLintPass<'tcx> for EmptyEnum { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - // Only suggest the `never_type` if the feature is enabled - if !cx.tcx.features().never_type { - return; - } - - if let ItemKind::Enum(..) = item.kind { - let ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); - let adt = ty.ty_adt_def().expect("already checked whether this is an enum"); - if adt.variants().is_empty() { - span_lint_and_help( - cx, - EMPTY_ENUM, - item.span, - "enum with no variants", - None, - "consider using the uninhabited type `!` (never type) or a wrapper \ - around it to introduce a type which can't be instantiated", - ); - } + if let ItemKind::Enum(..) = item.kind + // Only suggest the `never_type` if the feature is enabled + && cx.tcx.features().never_type + && let Some(adt) = cx.tcx.type_of(item.owner_id).instantiate_identity().ty_adt_def() + && adt.variants().is_empty() + { + span_lint_and_help( + cx, + EMPTY_ENUM, + item.span, + "enum with no variants", + None, + "consider using the uninhabited type `!` (never type) or a wrapper \ + around it to introduce a type which can't be instantiated", + ); } } } From 5b0dac6fe2fb574a6828d0a8d923e542ffd83d74 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 10 Jun 2024 02:26:28 -0400 Subject: [PATCH 042/734] `error_impl_error`: Get `Error` `DefId` after checking the HIR tree. --- clippy_lints/src/error_impl_error.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/error_impl_error.rs b/clippy_lints/src/error_impl_error.rs index 8e49138cd26b..1e6447dc2537 100644 --- a/clippy_lints/src/error_impl_error.rs +++ b/clippy_lints/src/error_impl_error.rs @@ -36,15 +36,12 @@ declare_lint_pass!(ErrorImplError => [ERROR_IMPL_ERROR]); impl<'tcx> LateLintPass<'tcx> for ErrorImplError { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error) else { - return; - }; - match item.kind { ItemKind::TyAlias(..) if item.ident.name == sym::Error && is_visible_outside_module(cx, item.owner_id.def_id) && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() + && let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error) && implements_trait(cx, ty, error_def_id, &[]) => { span_lint( @@ -56,9 +53,9 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError { }, ItemKind::Impl(imp) if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id()) + && let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error) && error_def_id == trait_def_id && let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local) - && let hir_id = cx.tcx.local_def_id_to_hir_id(def_id) && let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id()) && ident.name == sym::Error && is_visible_outside_module(cx, def_id) => @@ -66,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError { span_lint_hir_and_then( cx, ERROR_IMPL_ERROR, - hir_id, + cx.tcx.local_def_id_to_hir_id(def_id), ident.span, "exported type named `Error` that implements `Error`", |diag| { From 53688950775bfa2c986dc085fefdf1ba8ffe0932 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 11 Jun 2024 00:39:51 -0400 Subject: [PATCH 043/734] `exhaustive_items`: Don't check the item kind twice. --- clippy_lints/src/exhaustive_items.rs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs index 436dc8611bde..0f4176ec73bb 100644 --- a/clippy_lints/src/exhaustive_items.rs +++ b/clippy_lints/src/exhaustive_items.rs @@ -70,20 +70,24 @@ declare_lint_pass!(ExhaustiveItems => [EXHAUSTIVE_ENUMS, EXHAUSTIVE_STRUCTS]); impl LateLintPass<'_> for ExhaustiveItems { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind - && cx.effective_visibilities.is_exported(item.owner_id.def_id) + let (lint, msg, fields) = match item.kind { + ItemKind::Enum(..) => ( + EXHAUSTIVE_ENUMS, + "exported enums should not be exhaustive", + [].as_slice(), + ), + ItemKind::Struct(v, ..) => ( + EXHAUSTIVE_STRUCTS, + "exported structs should not be exhaustive", + v.fields(), + ), + _ => return, + }; + if cx.effective_visibilities.is_exported(item.owner_id.def_id) && let attrs = cx.tcx.hir().attrs(item.hir_id()) && !attrs.iter().any(|a| a.has_name(sym::non_exhaustive)) + && fields.iter().all(|f| cx.tcx.visibility(f.def_id).is_public()) { - let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind { - if v.fields().iter().any(|f| !cx.tcx.visibility(f.def_id).is_public()) { - // skip structs with private fields - return; - } - (EXHAUSTIVE_STRUCTS, "exported structs should not be exhaustive") - } else { - (EXHAUSTIVE_ENUMS, "exported enums should not be exhaustive") - }; let suggestion_span = item.span.shrink_to_lo(); let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0)); span_lint_and_then(cx, lint, item.span, msg, |diag| { From ca7e5c135327f3dadf5611e146400186216cdb85 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 11 Jun 2024 00:43:58 -0400 Subject: [PATCH 044/734] `exit`: Use `OwnerNode`. --- clippy_lints/src/exit.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index 91c94d66458d..f37d11f7eb9b 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_entrypoint_fn; -use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; +use rustc_hir::{Expr, ExprKind, Item, ItemKind, OwnerNode}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::sym; @@ -47,8 +47,8 @@ impl<'tcx> LateLintPass<'tcx> for Exit { && let ExprKind::Path(ref path) = path_expr.kind && let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id() && cx.tcx.is_diagnostic_item(sym::process_exit, def_id) - && let parent = cx.tcx.hir().get_parent_item(e.hir_id).def_id - && let Node::Item(Item{kind: ItemKind::Fn(..), ..}) = cx.tcx.hir_node_by_def_id(parent) + && let parent = cx.tcx.hir().get_parent_item(e.hir_id) + && let OwnerNode::Item(Item{kind: ItemKind::Fn(..), ..}) = cx.tcx.hir_owner_node(parent) // If the next item up is a function we check if it is an entry point // and only then emit a linter warning && !is_entrypoint_fn(cx, parent.to_def_id()) From 278e8371e64e09b684127054a78b0166074b5e9b Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 11 Jun 2024 13:30:26 -0400 Subject: [PATCH 045/734] `float_literal`: Check HIR tree before checking types. --- clippy_lints/src/float_literal.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 2261fcdbdabc..6adcd2235dc5 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -62,10 +62,9 @@ declare_lint_pass!(FloatLiteral => [EXCESSIVE_PRECISION, LOSSY_FLOAT_LITERAL]); impl<'tcx> LateLintPass<'tcx> for FloatLiteral { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - let ty = cx.typeck_results().expr_ty(expr); - if let ty::Float(fty) = *ty.kind() - && let hir::ExprKind::Lit(lit) = expr.kind + if let hir::ExprKind::Lit(lit) = expr.kind && let LitKind::Float(sym, lit_float_ty) = lit.node + && let ty::Float(fty) = *cx.typeck_results().expr_ty(expr).kind() { let sym_str = sym.as_str(); let formatter = FloatFormat::new(sym_str); From 3fcac2cba8ec697a8377336e765d704d710c8e60 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 11 Jun 2024 14:10:10 -0400 Subject: [PATCH 046/734] `from_over_into`: Check HIR tree first. --- clippy_lints/src/from_over_into.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 93527bcdf5ce..618530136e20 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -64,10 +64,6 @@ impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]); impl<'tcx> LateLintPass<'tcx> for FromOverInto { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if !self.msrv.meets(msrvs::RE_REBALANCING_COHERENCE) || !span_is_local(item.span) { - return; - } - if let ItemKind::Impl(Impl { of_trait: Some(hir_trait_ref), self_ty, @@ -77,6 +73,8 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto { && let Some(into_trait_seg) = hir_trait_ref.path.segments.last() // `impl Into for self_ty` && let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args + && self.msrv.meets(msrvs::RE_REBALANCING_COHERENCE) + && span_is_local(item.span) && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id) .map(ty::EarlyBinder::instantiate_identity) && cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id) From 9f59e9a777e4807374aaf0254c04c409850826fb Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 11 Jun 2024 14:17:38 -0400 Subject: [PATCH 047/734] `from_str_radix_10` : Reorder checks --- clippy_lints/src/from_str_radix_10.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index 82ce501bac59..9acb72b2e372 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -47,9 +47,13 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) { if let ExprKind::Call(maybe_path, [src, radix]) = &exp.kind && let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind - // do not lint in constant context, because the suggestion won't work. - // NB: keep this check until a new `const_trait_impl` is available and stablized. - && !in_constant(cx, exp.hir_id) + + // check if the second argument is a primitive `10` + && is_integer_literal(radix, 10) + + // check if the second part of the path indeed calls the associated + // function `from_str_radix` + && pathseg.ident.name.as_str() == "from_str_radix" // check if the first part of the path is some integer primitive && let TyKind::Path(ty_qpath) = &ty.kind @@ -57,12 +61,9 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { && let def::Res::PrimTy(prim_ty) = ty_res && matches!(prim_ty, PrimTy::Int(_) | PrimTy::Uint(_)) - // check if the second part of the path indeed calls the associated - // function `from_str_radix` - && pathseg.ident.name.as_str() == "from_str_radix" - - // check if the second argument is a primitive `10` - && is_integer_literal(radix, 10) + // do not lint in constant context, because the suggestion won't work. + // NB: keep this check until a new `const_trait_impl` is available and stablized. + && !in_constant(cx, exp.hir_id) { let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind { let ty = cx.typeck_results().expr_ty(expr); From ae144bfff0fa7e20edf75dd70251ede5f6831a1b Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 5 Jul 2024 16:25:28 -0400 Subject: [PATCH 048/734] rewrite raw-dylib-inline-cross-dylib to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../raw-dylib-inline-cross-dylib/Makefile | 30 --------- .../raw-dylib-inline-cross-dylib/rmake.rs | 61 +++++++++++++++++++ 3 files changed, 61 insertions(+), 31 deletions(-) delete mode 100644 tests/run-make/raw-dylib-inline-cross-dylib/Makefile create mode 100644 tests/run-make/raw-dylib-inline-cross-dylib/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 70c1b055c6e4..6d65b2e24e16 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -121,7 +121,6 @@ run-make/raw-dylib-alt-calling-convention/Makefile run-make/raw-dylib-c/Makefile run-make/raw-dylib-custom-dlltool/Makefile run-make/raw-dylib-import-name-type/Makefile -run-make/raw-dylib-inline-cross-dylib/Makefile run-make/raw-dylib-link-ordinal/Makefile run-make/raw-dylib-stdcall-ordinal/Makefile run-make/redundant-libs/Makefile diff --git a/tests/run-make/raw-dylib-inline-cross-dylib/Makefile b/tests/run-make/raw-dylib-inline-cross-dylib/Makefile deleted file mode 100644 index 6b44b40e253e..000000000000 --- a/tests/run-make/raw-dylib-inline-cross-dylib/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# Regression test for calling an inline function that uses a raw-dylib function. - -# only-windows - -include ../tools.mk - -# We'd be using the llvm-objdump instead of the system objdump to ensure compatibility -# with the LLVM bitcode generated by rustc but on Windows piping/IO redirection under MSYS2 is wonky with llvm-objdump. -OBJDUMP = objdump - -all: - $(RUSTC) --crate-type dylib --crate-name raw_dylib_test lib.rs -C prefer-dynamic - $(RUSTC) --crate-type dylib --crate-name raw_dylib_test_wrapper lib_wrapper.rs -C prefer-dynamic - $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" -C prefer-dynamic - # Make sure we don't find an import to the functions we expect to be inlined. - $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function" - $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function_calls_inline" - # Make sure we do find an import to the functions we expect to be imported. - $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -e "library_function" - $(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c) - $(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c) -ifdef IS_MSVC - $(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll -noimplib - $(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll -noimplib -else - $(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll - $(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll -endif - $(call RUN,driver) | tr -d '\r' > "$(TMPDIR)"/output.txt - $(RUSTC_TEST_OP) "$(TMPDIR)"/output.txt output.txt diff --git a/tests/run-make/raw-dylib-inline-cross-dylib/rmake.rs b/tests/run-make/raw-dylib-inline-cross-dylib/rmake.rs new file mode 100644 index 000000000000..b0cdc0aa4af5 --- /dev/null +++ b/tests/run-make/raw-dylib-inline-cross-dylib/rmake.rs @@ -0,0 +1,61 @@ +// When we generate the import library for a dylib or bin crate, we should generate it +// for the symbols both for the current crate and all upstream crates. This allows for +// using the link kind `raw-dylib` inside inline functions successfully. This test checks +// that the import symbols in the object files match this convention, and that execution +// of the binary results in all function names exported successfully. +// See https://github.com/rust-lang/rust/pull/102988 + +//@ only-windows + +use run_make_support::{cc, diff, is_msvc, llvm_objdump, run, rustc}; + +fn main() { + rustc() + .crate_type("dylib") + .crate_name("raw_dylib_test") + .input("lib.rs") + .arg("-Cprefer-dynamic") + .run(); + rustc() + .crate_type("dylib") + .crate_name("raw_dylib_test_wrapper") + .input("lib_wrapper.rs") + .arg("-Cprefer-dynamic") + .run(); + rustc().crate_type("bin").input("driver.rs").arg("-Cprefer-dynamic").run(); + llvm_objdump() + .arg("--private-headers") + .input("driver.exe") + .run() + // Make sure we don't find an import to the functions we expect to be inlined. + .assert_stdout_not_contains("inline_library_function") + // Make sure we do find an import to the functions we expect to be imported. + .assert_stdout_contains("library_function"); + if is_msvc() { + cc().arg("-c").out_exe("extern_1.obj").input("extern_1.c").run(); + cc().arg("-c").out_exe("extern_2.obj").input("extern_2.c").run(); + cc().input("extern_1.obj") + .arg("-link") + .arg("-dll") + .arg("-out:extern_1.dll") + .arg("-noimplib") + .run(); + cc().input("extern_2.obj") + .arg("-link") + .arg("-dll") + .arg("-out:extern_2.dll") + .arg("-noimplib") + .run(); + } else { + cc().arg("-v").arg("-c").out_exe("extern_1.obj").input("extern_1.c").run(); + cc().arg("-v").arg("-c").out_exe("extern_2.obj").input("extern_2.c").run(); + cc().input("extern_1.obj").out_exe("extern_1.dll").arg("-shared").run(); + cc().input("extern_2.obj").out_exe("extern_2.dll").arg("-shared").run(); + } + let out = run("driver").stdout_utf8(); + diff() + .expected_file("output.txt") + .actual_text("actual_output", out) + .normalize(r#"\\r"#, "") + .run(); +} From 2c14dd3b12d29749465a84429a4643da5c4e3934 Mon Sep 17 00:00:00 2001 From: Aljoscha Meyer Date: Sat, 6 Jul 2024 09:09:10 +0200 Subject: [PATCH 049/734] Add missing try_new_uninit_slice_in and try_new_zeroed_slice_in The methods for fallible slice allocation in a given allocator were missing, which was an oversight according to https://github.com/rust-lang/wg-allocators/issues/130 This PR adds them as `try_new_uninit_slice_in` and `try_new_zeroed_slice_in`. Also adds missing punctuation to the doc comments of ` try_new_uninit_slice` and `try_new_zeroed_slice` --- library/alloc/src/boxed.rs | 77 +++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 1ec095a46f70..d67b0ac37eb1 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -704,7 +704,7 @@ impl Box<[T]> { } /// Constructs a new boxed slice with uninitialized contents. Returns an error if - /// the allocation fails + /// the allocation fails. /// /// # Examples /// @@ -739,7 +739,7 @@ impl Box<[T]> { } /// Constructs a new boxed slice with uninitialized contents, with the memory - /// being filled with `0` bytes. Returns an error if the allocation fails + /// being filled with `0` bytes. Returns an error if the allocation fails. /// /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage /// of this method. @@ -831,6 +831,79 @@ impl Box<[T], A> { pub fn new_zeroed_slice_in(len: usize, alloc: A) -> Box<[mem::MaybeUninit], A> { unsafe { RawVec::with_capacity_zeroed_in(len, alloc).into_box(len) } } + + /// Constructs a new boxed slice with uninitialized contents in the provided allocator. Returns an error if + /// the allocation fails. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, new_uninit)] + /// + /// use std::alloc::System; + /// + /// let mut values = Box::<[u32]>::try_new_uninit_slice(3, System)?; + /// let values = unsafe { + /// // Deferred initialization: + /// values[0].as_mut_ptr().write(1); + /// values[1].as_mut_ptr().write(2); + /// values[2].as_mut_ptr().write(3); + /// values.assume_init() + /// }; + /// + /// assert_eq!(*values, [1, 2, 3]); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn try_new_uninit_slice_in(len: usize, alloc: A) -> Result], A>, AllocError> { + let ptr = if T::IS_ZST || len == 0 { + NonNull::dangling() + } else { + let layout = match Layout::array::>(len) { + Ok(l) => l, + Err(_) => return Err(AllocError), + }; + Global.allocate(layout)?.cast() + }; + unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, alloc).into_box(len)) } + } + + /// Constructs a new boxed slice with uninitialized contents in the provided allocator, with the memory + /// being filled with `0` bytes. Returns an error if the allocation fails. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage + /// of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, new_uninit)] + /// + /// use std::alloc::System; + /// + /// let values = Box::<[u32]>::try_new_zeroed_slice(3, System)?; + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [0, 0, 0]); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn try_new_zeroed_slice_in(len: usize, alloc: A) -> Result], A>, AllocError> { + let ptr = if T::IS_ZST || len == 0 { + NonNull::dangling() + } else { + let layout = match Layout::array::>(len) { + Ok(l) => l, + Err(_) => return Err(AllocError), + }; + Global.allocate_zeroed(layout)?.cast() + }; + unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, alloc).into_box(len)) } + } } impl Box, A> { From 9bfdeb592c422b355ac96086dbac8a6dfdaa6c73 Mon Sep 17 00:00:00 2001 From: Aljoscha Meyer Date: Sat, 6 Jul 2024 14:38:00 +0200 Subject: [PATCH 050/734] Run formatter on alloc/src/boxed.rs --- library/alloc/src/boxed.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index d67b0ac37eb1..b817cf855a5e 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -839,7 +839,7 @@ impl Box<[T], A> { /// /// ``` /// #![feature(allocator_api, new_uninit)] - /// + /// /// use std::alloc::System; /// /// let mut values = Box::<[u32]>::try_new_uninit_slice(3, System)?; @@ -856,7 +856,10 @@ impl Box<[T], A> { /// ``` #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn try_new_uninit_slice_in(len: usize, alloc: A) -> Result], A>, AllocError> { + pub fn try_new_uninit_slice_in( + len: usize, + alloc: A, + ) -> Result], A>, AllocError> { let ptr = if T::IS_ZST || len == 0 { NonNull::dangling() } else { @@ -879,7 +882,7 @@ impl Box<[T], A> { /// /// ``` /// #![feature(allocator_api, new_uninit)] - /// + /// /// use std::alloc::System; /// /// let values = Box::<[u32]>::try_new_zeroed_slice(3, System)?; @@ -892,7 +895,10 @@ impl Box<[T], A> { /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn try_new_zeroed_slice_in(len: usize, alloc: A) -> Result], A>, AllocError> { + pub fn try_new_zeroed_slice_in( + len: usize, + alloc: A, + ) -> Result], A>, AllocError> { let ptr = if T::IS_ZST || len == 0 { NonNull::dangling() } else { From 6b5da82d12a81e4905a9e01a33d4831fe6fea9ec Mon Sep 17 00:00:00 2001 From: Aljoscha Meyer Date: Sat, 6 Jul 2024 18:50:03 +0200 Subject: [PATCH 051/734] Fix doc examples --- library/alloc/src/boxed.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index b817cf855a5e..847594103d50 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -842,7 +842,7 @@ impl Box<[T], A> { /// /// use std::alloc::System; /// - /// let mut values = Box::<[u32]>::try_new_uninit_slice(3, System)?; + /// let mut values = Box::<[u32]>::try_new_uninit_slice_in(3, System)?; /// let values = unsafe { /// // Deferred initialization: /// values[0].as_mut_ptr().write(1); @@ -885,7 +885,7 @@ impl Box<[T], A> { /// /// use std::alloc::System; /// - /// let values = Box::<[u32]>::try_new_zeroed_slice(3, System)?; + /// let values = Box::<[u32]>::try_new_zeroed_slice_in(3, System)?; /// let values = unsafe { values.assume_init() }; /// /// assert_eq!(*values, [0, 0, 0]); From 497ef498053be7e6ef9e8af1bf7dc1e8800674c1 Mon Sep 17 00:00:00 2001 From: Aljoscha Meyer Date: Sat, 6 Jul 2024 19:13:53 +0200 Subject: [PATCH 052/734] Fix them doc examples some more Apologies for the many attempts, my dev loop for this consists of editing on github, committing, and then waiting for the CI failure log to yell at me. --- library/alloc/src/boxed.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 847594103d50..322c0756abdb 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -842,7 +842,7 @@ impl Box<[T], A> { /// /// use std::alloc::System; /// - /// let mut values = Box::<[u32]>::try_new_uninit_slice_in(3, System)?; + /// let mut values = Box::<[u32], _>::try_new_uninit_slice_in(3, System)?; /// let values = unsafe { /// // Deferred initialization: /// values[0].as_mut_ptr().write(1); @@ -885,7 +885,7 @@ impl Box<[T], A> { /// /// use std::alloc::System; /// - /// let values = Box::<[u32]>::try_new_zeroed_slice_in(3, System)?; + /// let values = Box::<[u32], _>::try_new_zeroed_slice_in(3, System)?; /// let values = unsafe { values.assume_init() }; /// /// assert_eq!(*values, [0, 0, 0]); From 65b9fae5655f4cfe989efa685700e89ecfcc77f9 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 8 Jun 2024 23:45:59 -0400 Subject: [PATCH 053/734] Refactor `checked_conversions`: * Check HIR tree before checking macros, msrv and constness * Remove redundant HIR tree matching --- clippy_lints/src/checked_conversions.rs | 133 +++++++++++------------- 1 file changed, 59 insertions(+), 74 deletions(-) diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 92810ea2aa0f..1ec4b831a2c4 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -5,7 +5,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{in_constant, is_integer_literal, SpanlessEq}; use rustc_errors::Applicability; -use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind}; +use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; @@ -50,61 +50,54 @@ impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]); impl<'tcx> LateLintPass<'tcx> for CheckedConversions { fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { - if !self.msrv.meets(msrvs::TRY_FROM) { - return; - } - - let result = if !in_constant(cx, item.hir_id) + if let ExprKind::Binary(op, lhs, rhs) = item.kind + && let (lt1, gt1, op2) = match op.node { + BinOpKind::Le => (lhs, rhs, None), + BinOpKind::Ge => (rhs, lhs, None), + BinOpKind::And + if let ExprKind::Binary(op1, lhs1, rhs1) = lhs.kind + && let ExprKind::Binary(op2, lhs2, rhs2) = rhs.kind + && let Some((lt1, gt1)) = read_le_ge(op1.node, lhs1, rhs1) + && let Some((lt2, gt2)) = read_le_ge(op2.node, lhs2, rhs2) => + { + (lt1, gt1, Some((lt2, gt2))) + }, + _ => return, + } && !in_external_macro(cx.sess(), item.span) - && let ExprKind::Binary(op, left, right) = &item.kind + && !in_constant(cx, item.hir_id) + && self.msrv.meets(msrvs::TRY_FROM) + && let Some(cv) = match op2 { + // todo: check for case signed -> larger unsigned == only x >= 0 + None => check_upper_bound(lt1, gt1).filter(|cv| cv.cvt == ConversionType::FromUnsigned), + Some((lt2, gt2)) => { + let upper_lower = |lt1, gt1, lt2, gt2| { + check_upper_bound(lt1, gt1) + .zip(check_lower_bound(lt2, gt2)) + .and_then(|(l, r)| l.combine(r, cx)) + }; + upper_lower(lt1, gt1, lt2, gt2).or_else(|| upper_lower(lt2, gt2, lt1, gt1)) + }, + } + && let Some(to_type) = cv.to_type { - match op.node { - BinOpKind::Ge | BinOpKind::Le => single_check(item), - BinOpKind::And => double_check(cx, left, right), - _ => None, - } - } else { - None - }; - - if let Some(cv) = result { - if let Some(to_type) = cv.to_type { - let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability); - span_lint_and_sugg( - cx, - CHECKED_CONVERSIONS, - item.span, - "checked cast can be simplified", - "try", - format!("{to_type}::try_from({snippet}).is_ok()"), - applicability, - ); - } + let mut applicability = Applicability::MachineApplicable; + let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability); + span_lint_and_sugg( + cx, + CHECKED_CONVERSIONS, + item.span, + "checked cast can be simplified", + "try", + format!("{to_type}::try_from({snippet}).is_ok()"), + applicability, + ); } } extract_msrv_attr!(LateContext); } -/// Searches for a single check from unsigned to _ is done -/// todo: check for case signed -> larger unsigned == only x >= 0 -fn single_check<'tcx>(expr: &'tcx Expr<'tcx>) -> Option> { - check_upper_bound(expr).filter(|cv| cv.cvt == ConversionType::FromUnsigned) -} - -/// Searches for a combination of upper & lower bound checks -fn double_check<'a>(cx: &LateContext<'_>, left: &'a Expr<'_>, right: &'a Expr<'_>) -> Option> { - let upper_lower = |l, r| { - let upper = check_upper_bound(l); - let lower = check_lower_bound(r); - - upper.zip(lower).and_then(|(l, r)| l.combine(r, cx)) - }; - - upper_lower(left, right).or_else(|| upper_lower(right, left)) -} - /// Contains the result of a tried conversion check #[derive(Clone, Debug)] struct Conversion<'a> { @@ -121,6 +114,19 @@ enum ConversionType { FromUnsigned, } +/// Attempts to read either `<=` or `>=` with a normalized operand order. +fn read_le_ge<'tcx>( + op: BinOpKind, + lhs: &'tcx Expr<'tcx>, + rhs: &'tcx Expr<'tcx>, +) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { + match op { + BinOpKind::Le => Some((lhs, rhs)), + BinOpKind::Ge => Some((rhs, lhs)), + _ => None, + } +} + impl<'a> Conversion<'a> { /// Combine multiple conversions if the are compatible pub fn combine(self, other: Self, cx: &LateContext<'_>) -> Option> { @@ -188,29 +194,17 @@ impl ConversionType { } /// Check for `expr <= (to_type::MAX as from_type)` -fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option> { - if let ExprKind::Binary(ref op, left, right) = &expr.kind - && let Some((candidate, check)) = normalize_le_ge(op, left, right) - && let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX") - { - Conversion::try_new(candidate, from, to) +fn check_upper_bound<'tcx>(lt: &'tcx Expr<'tcx>, gt: &'tcx Expr<'tcx>) -> Option> { + if let Some((from, to)) = get_types_from_cast(gt, INTS, "max_value", "MAX") { + Conversion::try_new(lt, from, to) } else { None } } /// Check for `expr >= 0|(to_type::MIN as from_type)` -fn check_lower_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option> { - fn check_function<'a>(candidate: &'a Expr<'a>, check: &'a Expr<'a>) -> Option> { - (check_lower_bound_zero(candidate, check)).or_else(|| (check_lower_bound_min(candidate, check))) - } - - // First of we need a binary containing the expression & the cast - if let ExprKind::Binary(ref op, left, right) = &expr.kind { - normalize_le_ge(op, right, left).and_then(|(l, r)| check_function(l, r)) - } else { - None - } +fn check_lower_bound<'tcx>(lt: &'tcx Expr<'tcx>, gt: &'tcx Expr<'tcx>) -> Option> { + check_lower_bound_zero(gt, lt).or_else(|| check_lower_bound_min(gt, lt)) } /// Check for `expr >= 0` @@ -309,15 +303,6 @@ fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> { } } -/// Will return the expressions as if they were expr1 <= expr2 -fn normalize_le_ge<'a>(op: &BinOp, left: &'a Expr<'a>, right: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> { - match op.node { - BinOpKind::Le => Some((left, right)), - BinOpKind::Ge => Some((right, left)), - _ => None, - } -} - // Constants const UINTS: &[&str] = &["u8", "u16", "u32", "u64", "usize"]; const SINTS: &[&str] = &["i8", "i16", "i32", "i64", "isize"]; From 0a25df87efd5fdf1543d26764c929d8d6e00a48a Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 9 Jun 2024 22:27:39 -0400 Subject: [PATCH 054/734] Refactor `double_parens`: * Merge control flow before emission * Check the AST before the macro check --- clippy_lints/src/double_parens.rs | 48 ++++++++++++++----------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index b51bb7951b74..4dd8f01ee709 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -40,35 +40,29 @@ declare_lint_pass!(DoubleParens => [DOUBLE_PARENS]); impl EarlyLintPass for DoubleParens { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if expr.span.from_expansion() { - return; - } - - let msg: &str = "consider removing unnecessary double parentheses"; - - match expr.kind { - ExprKind::Paren(ref in_paren) => match in_paren.kind { - ExprKind::Paren(_) | ExprKind::Tup(_) => { - span_lint(cx, DOUBLE_PARENS, expr.span, msg); - }, - _ => {}, + let span = match &expr.kind { + ExprKind::Paren(in_paren) if matches!(in_paren.kind, ExprKind::Paren(_) | ExprKind::Tup(_)) => expr.span, + ExprKind::Call(_, params) + if let [param] = &**params + && let ExprKind::Paren(_) = param.kind => + { + param.span }, - ExprKind::Call(_, ref params) => { - if params.len() == 1 { - let param = ¶ms[0]; - if let ExprKind::Paren(_) = param.kind { - span_lint(cx, DOUBLE_PARENS, param.span, msg); - } - } + ExprKind::MethodCall(call) + if let [arg] = &*call.args + && let ExprKind::Paren(_) = arg.kind => + { + arg.span }, - ExprKind::MethodCall(ref call) => { - if let [ref arg] = call.args[..] { - if let ExprKind::Paren(_) = arg.kind { - span_lint(cx, DOUBLE_PARENS, arg.span, msg); - } - } - }, - _ => {}, + _ => return, + }; + if !expr.span.from_expansion() { + span_lint( + cx, + DOUBLE_PARENS, + span, + "consider removing unnecessary double parentheses", + ); } } } From e864519fbcaef5141e8fda7fdfac1a2c8d363cd2 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 7 Jul 2024 08:11:32 +0700 Subject: [PATCH 055/734] Add test for manual_unwrap_or in issue 13018 --- tests/ui/manual_unwrap_or.fixed | 9 +++++++++ tests/ui/manual_unwrap_or.rs | 13 +++++++++++++ tests/ui/manual_unwrap_or.stderr | 12 +++++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/tests/ui/manual_unwrap_or.fixed b/tests/ui/manual_unwrap_or.fixed index 74afa00e12f2..2899c3518de8 100644 --- a/tests/ui/manual_unwrap_or.fixed +++ b/tests/ui/manual_unwrap_or.fixed @@ -234,4 +234,13 @@ fn implicit_deref_ref() { }; } +mod issue_13018 { + use std::collections::HashMap; + + type RefName = i32; + pub fn get(index: &HashMap>, id: usize) -> &[RefName] { + index.get(&id).unwrap_or(&[]) + } +} + fn main() {} diff --git a/tests/ui/manual_unwrap_or.rs b/tests/ui/manual_unwrap_or.rs index 2d01b8ceaaa7..e2c04b01ed96 100644 --- a/tests/ui/manual_unwrap_or.rs +++ b/tests/ui/manual_unwrap_or.rs @@ -284,4 +284,17 @@ fn implicit_deref_ref() { }; } +mod issue_13018 { + use std::collections::HashMap; + + type RefName = i32; + pub fn get(index: &HashMap>, id: usize) -> &[RefName] { + if let Some(names) = index.get(&id) { + names + } else { + &[] + } + } +} + fn main() {} diff --git a/tests/ui/manual_unwrap_or.stderr b/tests/ui/manual_unwrap_or.stderr index c93a8952a080..28b59df161df 100644 --- a/tests/ui/manual_unwrap_or.stderr +++ b/tests/ui/manual_unwrap_or.stderr @@ -172,5 +172,15 @@ LL | | None => 0, LL | | }; | |_________^ help: replace with: `some_macro!().unwrap_or(0)` -error: aborting due to 16 previous errors +error: this pattern reimplements `Option::unwrap_or` + --> tests/ui/manual_unwrap_or.rs:292:9 + | +LL | / if let Some(names) = index.get(&id) { +LL | | names +LL | | } else { +LL | | &[] +LL | | } + | |_________^ help: replace with: `index.get(&id).unwrap_or(&[])` + +error: aborting due to 17 previous errors From c46c1f6da6725e0aa33e7738e9e0eb2f58b46eb6 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 7 Jul 2024 20:41:55 +0700 Subject: [PATCH 056/734] Fix 13018: self should be T with `Option::unwrap_or(self, T) -> T`. --- clippy_lints/src/matches/manual_unwrap_or.rs | 11 +++++++++++ tests/ui/manual_unwrap_or.fixed | 9 ++++++++- tests/ui/manual_unwrap_or.rs | 11 +++++++---- tests/ui/manual_unwrap_or.stderr | 12 +----------- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index 0940fc3219bb..85a08f81c2f3 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -35,6 +35,17 @@ pub(super) fn check_if_let<'tcx>( else_expr: &'tcx Expr<'_>, ) { let ty = cx.typeck_results().expr_ty(let_expr); + let then_ty = cx.typeck_results().expr_ty(then_expr); + // The signature is `fn unwrap_or(self: Option, default: T) -> T`. + // When `expr_adjustments(then_expr).is_empty()`, `T` should equate to `default`'s type. + // Otherwise, type error will occur. + if cx.typeck_results().expr_adjustments(then_expr).is_empty() + && let rustc_middle::ty::Adt(_did, args) = ty.kind() + && let Some(some_ty) = args.first().and_then(|arg| arg.as_type()) + && some_ty != then_ty + { + return; + } check_and_lint(cx, expr, let_pat, let_expr, then_expr, peel_blocks(else_expr), ty); } diff --git a/tests/ui/manual_unwrap_or.fixed b/tests/ui/manual_unwrap_or.fixed index 2899c3518de8..07e4bdd483a8 100644 --- a/tests/ui/manual_unwrap_or.fixed +++ b/tests/ui/manual_unwrap_or.fixed @@ -239,7 +239,14 @@ mod issue_13018 { type RefName = i32; pub fn get(index: &HashMap>, id: usize) -> &[RefName] { - index.get(&id).unwrap_or(&[]) + if let Some(names) = index.get(&id) { names } else { &[] } + } + + pub fn get_match(index: &HashMap>, id: usize) -> &[RefName] { + match index.get(&id) { + Some(names) => names, + None => &[], + } } } diff --git a/tests/ui/manual_unwrap_or.rs b/tests/ui/manual_unwrap_or.rs index e2c04b01ed96..cdbe51a41212 100644 --- a/tests/ui/manual_unwrap_or.rs +++ b/tests/ui/manual_unwrap_or.rs @@ -289,10 +289,13 @@ mod issue_13018 { type RefName = i32; pub fn get(index: &HashMap>, id: usize) -> &[RefName] { - if let Some(names) = index.get(&id) { - names - } else { - &[] + if let Some(names) = index.get(&id) { names } else { &[] } + } + + pub fn get_match(index: &HashMap>, id: usize) -> &[RefName] { + match index.get(&id) { + Some(names) => names, + None => &[], } } } diff --git a/tests/ui/manual_unwrap_or.stderr b/tests/ui/manual_unwrap_or.stderr index 28b59df161df..c93a8952a080 100644 --- a/tests/ui/manual_unwrap_or.stderr +++ b/tests/ui/manual_unwrap_or.stderr @@ -172,15 +172,5 @@ LL | | None => 0, LL | | }; | |_________^ help: replace with: `some_macro!().unwrap_or(0)` -error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:292:9 - | -LL | / if let Some(names) = index.get(&id) { -LL | | names -LL | | } else { -LL | | &[] -LL | | } - | |_________^ help: replace with: `index.get(&id).unwrap_or(&[])` - -error: aborting due to 17 previous errors +error: aborting due to 16 previous errors From 58e551433d692579faf4ad59fb7f192aa9001677 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 16 Apr 2024 18:31:43 +0000 Subject: [PATCH 057/734] Sync ar_archive_writer to LLVM 18.1.3 From LLVM 15.0.0-rc3. This adds support for COFF archives containing Arm64EC object files and has various fixes for AIX big archive files. --- Cargo.lock | 15 +- .../rustc_codegen_cranelift/src/archive.rs | 4 +- compiler/rustc_codegen_gcc/src/archive.rs | 4 +- .../rustc_codegen_llvm/src/back/archive.rs | 117 +++++++++------- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 4 + compiler/rustc_codegen_ssa/Cargo.toml | 2 +- .../rustc_codegen_ssa/src/back/archive.rs | 25 ++-- .../rustc_llvm/llvm-wrapper/SymbolWrapper.cpp | 128 +++++++++++++----- 8 files changed, 201 insertions(+), 98 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index afeb9faec097..f3c6a1d5eb44 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -236,11 +236,11 @@ checksum = "d67af77d68a931ecd5cbd8a3b5987d63a1d1d1278f7f6a60ae33db485cdebb69" [[package]] name = "ar_archive_writer" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c269894b6fe5e9d7ada0cf69b5bf847ff35bc25fc271f08e1d080fce80339a" +checksum = "f8412a2d690663356cba5a2532f3ed55d1e8090743bc6695b88403b27df67733" dependencies = [ - "object 0.32.2", + "object 0.35.0", ] [[package]] @@ -2637,6 +2637,15 @@ dependencies = [ "ruzstd 0.6.0", ] +[[package]] +name = "object" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" +dependencies = [ + "memchr", +] + [[package]] name = "object" version = "0.36.0" diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index 414d3db1c51a..26db93a75795 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -1,7 +1,7 @@ use std::path::{Path, PathBuf}; use rustc_codegen_ssa::back::archive::{ - get_native_object_symbols, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, + ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, }; use rustc_session::Session; @@ -9,7 +9,7 @@ pub(crate) struct ArArchiveBuilderBuilder; impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box { - Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols)) + Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER)) } fn create_dll_import_lib( diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs index 73ff0c37b665..21676f5dbb6a 100644 --- a/compiler/rustc_codegen_gcc/src/archive.rs +++ b/compiler/rustc_codegen_gcc/src/archive.rs @@ -1,7 +1,7 @@ use std::path::{Path, PathBuf}; use rustc_codegen_ssa::back::archive::{ - get_native_object_symbols, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, + ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, }; use rustc_session::Session; @@ -11,7 +11,7 @@ pub(crate) struct ArArchiveBuilderBuilder; impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box { - Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols)) + Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER)) } fn create_dll_import_lib( diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index a354f3d35361..f46c6b1c4980 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -15,8 +15,8 @@ use crate::errors::{ use crate::llvm::archive_ro::{ArchiveRO, Child}; use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport}; use rustc_codegen_ssa::back::archive::{ - get_native_object_symbols, try_extract_macho_fat_archive, ArArchiveBuilder, - ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, UnknownArchiveKind, + try_extract_macho_fat_archive, ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder, + ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind, DEFAULT_OBJECT_READER, }; use tracing::trace; @@ -115,7 +115,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { if true { Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() }) } else { - Box::new(ArArchiveBuilder::new(sess, get_llvm_object_symbols)) + Box::new(ArArchiveBuilder::new(sess, &LLVM_OBJECT_READER)) } } @@ -291,57 +291,82 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { // The object crate doesn't know how to get symbols for LLVM bitcode and COFF bigobj files. // As such we need to use LLVM for them. -#[deny(unsafe_op_in_unsafe_fn)] -fn get_llvm_object_symbols( - buf: &[u8], - f: &mut dyn FnMut(&[u8]) -> io::Result<()>, -) -> io::Result { + +static LLVM_OBJECT_READER: ObjectReader = ObjectReader { + get_symbols: get_llvm_object_symbols, + is_64_bit_object_file: llvm_is_64_bit_object_file, + is_ec_object_file: llvm_is_ec_object_file, + get_xcoff_member_alignment: DEFAULT_OBJECT_READER.get_xcoff_member_alignment, +}; + +fn should_use_llvm_reader(buf: &[u8]) -> bool { let is_bitcode = unsafe { llvm::LLVMRustIsBitcode(buf.as_ptr(), buf.len()) }; // COFF bigobj file, msvc LTO file or import library. See // https://github.com/llvm/llvm-project/blob/453f27bc9/llvm/lib/BinaryFormat/Magic.cpp#L38-L51 let is_unsupported_windows_obj_file = buf.get(0..4) == Some(b"\0\0\xFF\xFF"); - if is_bitcode || is_unsupported_windows_obj_file { - let mut state = Box::new(f); + is_bitcode || is_unsupported_windows_obj_file +} - let err = unsafe { - llvm::LLVMRustGetSymbols( - buf.as_ptr(), - buf.len(), - std::ptr::addr_of_mut!(*state) as *mut c_void, - callback, - error_callback, - ) - }; - - if err.is_null() { - return Ok(true); - } else { - return Err(unsafe { *Box::from_raw(err as *mut io::Error) }); - } - - unsafe extern "C" fn callback( - state: *mut c_void, - symbol_name: *const c_char, - ) -> *mut c_void { - let f = unsafe { &mut *(state as *mut &mut dyn FnMut(&[u8]) -> io::Result<()>) }; - match f(unsafe { CStr::from_ptr(symbol_name) }.to_bytes()) { - Ok(()) => std::ptr::null_mut(), - Err(err) => Box::into_raw(Box::new(err)) as *mut c_void, - } - } - - unsafe extern "C" fn error_callback(error: *const c_char) -> *mut c_void { - let error = unsafe { CStr::from_ptr(error) }; - Box::into_raw(Box::new(io::Error::new( - io::ErrorKind::Other, - format!("LLVM error: {}", error.to_string_lossy()), - ))) as *mut c_void - } - } else { - get_native_object_symbols(buf, f) +#[deny(unsafe_op_in_unsafe_fn)] +fn get_llvm_object_symbols( + buf: &[u8], + f: &mut dyn FnMut(&[u8]) -> io::Result<()>, +) -> io::Result { + if !should_use_llvm_reader(buf) { + return (DEFAULT_OBJECT_READER.get_symbols)(buf, f); } + + let mut state = Box::new(f); + + let err = unsafe { + llvm::LLVMRustGetSymbols( + buf.as_ptr(), + buf.len(), + std::ptr::addr_of_mut!(*state) as *mut c_void, + callback, + error_callback, + ) + }; + + if err.is_null() { + return Ok(true); + } else { + return Err(unsafe { *Box::from_raw(err as *mut io::Error) }); + } + + unsafe extern "C" fn callback(state: *mut c_void, symbol_name: *const c_char) -> *mut c_void { + let f = unsafe { &mut *(state as *mut &mut dyn FnMut(&[u8]) -> io::Result<()>) }; + match f(unsafe { CStr::from_ptr(symbol_name) }.to_bytes()) { + Ok(()) => std::ptr::null_mut(), + Err(err) => Box::into_raw(Box::new(err)) as *mut c_void, + } + } + + unsafe extern "C" fn error_callback(error: *const c_char) -> *mut c_void { + let error = unsafe { CStr::from_ptr(error) }; + Box::into_raw(Box::new(io::Error::new( + io::ErrorKind::Other, + format!("LLVM error: {}", error.to_string_lossy()), + ))) as *mut c_void + } +} + +fn llvm_is_64_bit_object_file(buf: &[u8]) -> bool { + if !should_use_llvm_reader(buf) { + return (DEFAULT_OBJECT_READER.is_64_bit_object_file)(buf); + } + + unsafe { llvm::LLVMRustIs64BitSymbolicFile(buf.as_ptr(), buf.len()) } +} + +fn llvm_is_ec_object_file(buf: &[u8]) -> bool { + if !should_use_llvm_reader(buf) { + return (DEFAULT_OBJECT_READER.is_ec_object_file)(buf); + } + + unsafe { llvm::LLVMRustIsECObject(buf.as_ptr(), buf.len()) } } impl<'a> LlvmArchiveBuilder<'a> { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 08e9e312827c..f56a8036c65f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2440,4 +2440,8 @@ extern "C" { callback: GetSymbolsCallback, error_callback: GetSymbolsErrorCallback, ) -> *mut c_void; + + pub fn LLVMRustIs64BitSymbolicFile(buf_ptr: *const u8, buf_len: usize) -> bool; + + pub fn LLVMRustIsECObject(buf_ptr: *const u8, buf_len: usize) -> bool; } diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 3771fc6b0a27..f7b5b0f310b6 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -ar_archive_writer = "0.2.0" +ar_archive_writer = "0.3.0" arrayvec = { version = "0.7", default-features = false } bitflags = "2.4.1" cc = "1.0.90" diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index c99118f5156d..f673675bdbb7 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -6,8 +6,8 @@ use rustc_span::symbol::Symbol; use super::metadata::search_for_section; -pub use ar_archive_writer::get_native_object_symbols; use ar_archive_writer::{write_archive_to_stream, ArchiveKind, NewArchiveMember}; +pub use ar_archive_writer::{ObjectReader, DEFAULT_OBJECT_READER}; use object::read::archive::ArchiveFile; use object::read::macho::FatArch; use tempfile::Builder as TempFileBuilder; @@ -89,8 +89,7 @@ pub trait ArchiveBuilder { #[must_use = "must call build() to finish building the archive"] pub struct ArArchiveBuilder<'a> { sess: &'a Session, - get_object_symbols: - fn(buf: &[u8], f: &mut dyn FnMut(&[u8]) -> io::Result<()>) -> io::Result, + object_reader: &'static ObjectReader, src_archives: Vec<(PathBuf, Mmap)>, // Don't use an `HashMap` here, as the order is important. `lib.rmeta` needs @@ -105,14 +104,8 @@ enum ArchiveEntry { } impl<'a> ArArchiveBuilder<'a> { - pub fn new( - sess: &'a Session, - get_object_symbols: fn( - buf: &[u8], - f: &mut dyn FnMut(&[u8]) -> io::Result<()>, - ) -> io::Result, - ) -> ArArchiveBuilder<'a> { - ArArchiveBuilder { sess, get_object_symbols, src_archives: vec![], entries: vec![] } + pub fn new(sess: &'a Session, object_reader: &'static ObjectReader) -> ArArchiveBuilder<'a> { + ArArchiveBuilder { sess, object_reader, src_archives: vec![], entries: vec![] } } } @@ -267,7 +260,7 @@ impl<'a> ArArchiveBuilder<'a> { entries.push(NewArchiveMember { buf: data, - get_symbols: self.get_object_symbols, + object_reader: self.object_reader, member_name: String::from_utf8(entry_name).unwrap(), mtime: 0, uid: 0, @@ -294,7 +287,13 @@ impl<'a> ArArchiveBuilder<'a> { let mut archive_tmpfile = File::create_new(&archive_tmpfile_path) .map_err(|err| io_error_context("couldn't create the temp file", err))?; - write_archive_to_stream(&mut archive_tmpfile, &entries, archive_kind, false)?; + write_archive_to_stream( + &mut archive_tmpfile, + &entries, + archive_kind, + false, + self.sess.target.arch == "arm64ec", + )?; let any_entries = !entries.is_empty(); drop(entries); diff --git a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp index a9d1362a338d..d13dcb137a1c 100644 --- a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp @@ -4,12 +4,15 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // Derived from: -// * https://github.com/llvm/llvm-project/blob/8ef3e895ad8ab1724e2b87cabad1dacdc7a397a3/llvm/include/llvm/Object/ArchiveWriter.h -// * https://github.com/llvm/llvm-project/blob/8ef3e895ad8ab1724e2b87cabad1dacdc7a397a3/llvm/lib/Object/ArchiveWriter.cpp +// * https://github.com/llvm/llvm-project/blob/ef6d1ec07c693352c4a60dd58db08d2d8558f6ea/llvm/include/llvm/Object/ArchiveWriter.h +// * https://github.com/llvm/llvm-project/blob/ef6d1ec07c693352c4a60dd58db08d2d8558f6ea/llvm/lib/Object/ArchiveWriter.cpp #include "SuppressLLVMWarnings.h" #include "llvm/ADT/SmallString.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/COFFImportFile.h" +#include "llvm/Object/IRObjectFile.h" #include "llvm/Object/ObjectFile.h" #include @@ -34,6 +37,26 @@ static bool isArchiveSymbol(const object::BasicSymbolRef &S) { typedef void *(*LLVMRustGetSymbolsCallback)(void *, const char *); typedef void *(*LLVMRustGetSymbolsErrorCallback)(const char *); +static Expected> +getSymbolicFile(MemoryBufferRef Buf, LLVMContext &Context) { + const file_magic Type = identify_magic(Buf.getBuffer()); + // Don't attempt to read non-symbolic file types. + if (!object::SymbolicFile::isSymbolicFile(Type, &Context)) + return nullptr; + if (Type == file_magic::bitcode) { + auto ObjOrErr = object::SymbolicFile::createSymbolicFile( + Buf, file_magic::bitcode, &Context); + if (!ObjOrErr) + return ObjOrErr.takeError(); + return std::move(*ObjOrErr); + } else { + auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf); + if (!ObjOrErr) + return ObjOrErr.takeError(); + return std::move(*ObjOrErr); + } +} + // Note: This is implemented in C++ instead of using the C api from Rust as // IRObjectFile doesn't implement getSymbolName, only printSymbolName, which is // inaccessible from the C api. @@ -49,36 +72,16 @@ LLVMRustGetSymbols(char *BufPtr, size_t BufLen, void *State, // In the scenario when LLVMContext is populated SymbolicFile will contain a // reference to it, thus SymbolicFile should be destroyed first. LLVMContext Context; - std::unique_ptr Obj; - - const file_magic Type = identify_magic(Buf->getBuffer()); - if (!object::SymbolicFile::isSymbolicFile(Type, &Context)) { - return 0; - } - - if (Type == file_magic::bitcode) { - auto ObjOrErr = object::SymbolicFile::createSymbolicFile( - Buf->getMemBufferRef(), file_magic::bitcode, &Context); - if (!ObjOrErr) { - Error E = ObjOrErr.takeError(); - SmallString<0> ErrorBuf; - auto Error = raw_svector_ostream(ErrorBuf); - Error << E << '\0'; - return ErrorCallback(Error.str().data()); - } - Obj = std::move(*ObjOrErr); - } else { - auto ObjOrErr = - object::SymbolicFile::createSymbolicFile(Buf->getMemBufferRef()); - if (!ObjOrErr) { - Error E = ObjOrErr.takeError(); - SmallString<0> ErrorBuf; - auto Error = raw_svector_ostream(ErrorBuf); - Error << E << '\0'; - return ErrorCallback(Error.str().data()); - } - Obj = std::move(*ObjOrErr); + Expected> ObjOrErr = + getSymbolicFile(Buf->getMemBufferRef(), Context); + if (!ObjOrErr) { + Error E = ObjOrErr.takeError(); + SmallString<0> ErrorBuf; + auto Error = raw_svector_ostream(ErrorBuf); + Error << E << '\0'; + return ErrorCallback(Error.str().data()); } + std::unique_ptr Obj = std::move(*ObjOrErr); for (const object::BasicSymbolRef &S : Obj->symbols()) { if (!isArchiveSymbol(S)) @@ -97,3 +100,66 @@ LLVMRustGetSymbols(char *BufPtr, size_t BufLen, void *State, } return 0; } + +// Encoding true and false as invalid pointer values +#define TRUE_PTR (void *)1 +#define FALSE_PTR (void *)0 + +extern "C" bool LLVMRustIs64BitSymbolicFile(char *BufPtr, size_t BufLen) { + std::unique_ptr Buf = MemoryBuffer::getMemBuffer( + StringRef(BufPtr, BufLen), StringRef("LLVMRustGetSymbolsObject"), false); + SmallString<0> SymNameBuf; + auto SymName = raw_svector_ostream(SymNameBuf); + + // In the scenario when LLVMContext is populated SymbolicFile will contain a + // reference to it, thus SymbolicFile should be destroyed first. + LLVMContext Context; + Expected> ObjOrErr = + getSymbolicFile(Buf->getMemBufferRef(), Context); + if (!ObjOrErr) { + return false; + } + std::unique_ptr Obj = std::move(*ObjOrErr); + + return Obj != nullptr ? Obj->is64Bit() : false; +} + +extern "C" bool LLVMRustIsECObject(char *BufPtr, size_t BufLen) { + std::unique_ptr Buf = MemoryBuffer::getMemBuffer( + StringRef(BufPtr, BufLen), StringRef("LLVMRustGetSymbolsObject"), false); + SmallString<0> SymNameBuf; + auto SymName = raw_svector_ostream(SymNameBuf); + + // In the scenario when LLVMContext is populated SymbolicFile will contain a + // reference to it, thus SymbolicFile should be destroyed first. + LLVMContext Context; + Expected> ObjOrErr = + getSymbolicFile(Buf->getMemBufferRef(), Context); + if (!ObjOrErr) { + return false; + } + std::unique_ptr Obj = std::move(*ObjOrErr); + + if (Obj == nullptr) { + return false; + } + + if (Obj->isCOFF()) + return cast(&*Obj)->getMachine() != + COFF::IMAGE_FILE_MACHINE_ARM64; + + if (Obj->isCOFFImportFile()) + return cast(&*Obj)->getMachine() != + COFF::IMAGE_FILE_MACHINE_ARM64; + + if (Obj->isIR()) { + Expected TripleStr = + getBitcodeTargetTriple(Obj->getMemoryBufferRef()); + if (!TripleStr) + return false; + Triple T(*TripleStr); + return T.isWindowsArm64EC() || T.getArch() == Triple::x86_64; + } + + return false; +} From 72223e205d91e4d689718a9f61b3f6c0346d19e8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 7 Jul 2024 17:00:04 +0000 Subject: [PATCH 058/734] Fix building on LLVM 17 --- compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp index d13dcb137a1c..37e9e41a8742 100644 --- a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp @@ -7,6 +7,7 @@ // * https://github.com/llvm/llvm-project/blob/ef6d1ec07c693352c4a60dd58db08d2d8558f6ea/llvm/include/llvm/Object/ArchiveWriter.h // * https://github.com/llvm/llvm-project/blob/ef6d1ec07c693352c4a60dd58db08d2d8558f6ea/llvm/lib/Object/ArchiveWriter.cpp +#include "LLVMWrapper.h" #include "SuppressLLVMWarnings.h" #include "llvm/ADT/SmallString.h" #include "llvm/IR/LLVMContext.h" @@ -148,9 +149,11 @@ extern "C" bool LLVMRustIsECObject(char *BufPtr, size_t BufLen) { return cast(&*Obj)->getMachine() != COFF::IMAGE_FILE_MACHINE_ARM64; +#if LLVM_VERSION_GE(18, 0) if (Obj->isCOFFImportFile()) return cast(&*Obj)->getMachine() != COFF::IMAGE_FILE_MACHINE_ARM64; +#endif if (Obj->isIR()) { Expected TripleStr = From cd3f2f68c042e2957fff85ca89ba10cb0f2f12b3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 7 Jul 2024 17:07:36 +0000 Subject: [PATCH 059/734] Fix review comments --- compiler/rustc_codegen_ssa/src/back/archive.rs | 2 +- compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index f673675bdbb7..ae649cd77c42 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -292,7 +292,7 @@ impl<'a> ArArchiveBuilder<'a> { &entries, archive_kind, false, - self.sess.target.arch == "arm64ec", + /* is_ec = */ self.sess.target.arch == "arm64ec", )?; let any_entries = !entries.is_empty(); diff --git a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp index 37e9e41a8742..ccf1a5429e2b 100644 --- a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp @@ -38,6 +38,7 @@ static bool isArchiveSymbol(const object::BasicSymbolRef &S) { typedef void *(*LLVMRustGetSymbolsCallback)(void *, const char *); typedef void *(*LLVMRustGetSymbolsErrorCallback)(const char *); +// This function is copied from ArchiveWriter.cpp. static Expected> getSymbolicFile(MemoryBufferRef Buf, LLVMContext &Context) { const file_magic Type = identify_magic(Buf.getBuffer()); @@ -112,6 +113,8 @@ extern "C" bool LLVMRustIs64BitSymbolicFile(char *BufPtr, size_t BufLen) { SmallString<0> SymNameBuf; auto SymName = raw_svector_ostream(SymNameBuf); + // Code starting from this line is copied from s64BitSymbolicFile in + // ArchiveWriter.cpp. // In the scenario when LLVMContext is populated SymbolicFile will contain a // reference to it, thus SymbolicFile should be destroyed first. LLVMContext Context; @@ -145,6 +148,8 @@ extern "C" bool LLVMRustIsECObject(char *BufPtr, size_t BufLen) { return false; } + // Code starting from this line is copied from isECObject in + // ArchiveWriter.cpp with an extra #if to work with LLVM 17. if (Obj->isCOFF()) return cast(&*Obj)->getMachine() != COFF::IMAGE_FILE_MACHINE_ARM64; From 1b0230cf2525d8c3653cab40d888d6c9b90c059f Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 10 Jun 2024 01:22:37 -0400 Subject: [PATCH 060/734] Refactor `endian_bytes`: * Merge code paths. * Check HIR tree before checking for macros. --- clippy_lints/src/endian_bytes.rs | 39 +++++++++++++------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs index bb766e963387..f11ac5f317c0 100644 --- a/clippy_lints/src/endian_bytes.rs +++ b/clippy_lints/src/endian_bytes.rs @@ -109,32 +109,27 @@ impl LintKind { impl LateLintPass<'_> for EndianBytes { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if in_external_macro(cx.sess(), expr.span) { - return; - } - - if let ExprKind::MethodCall(method_name, receiver, args, ..) = expr.kind - && args.is_empty() - && let ty = cx.typeck_results().expr_ty(receiver) - && ty.is_primitive_ty() - && maybe_lint_endian_bytes(cx, expr, Prefix::To, method_name.ident.name, ty) - { - return; - } - - if let ExprKind::Call(function, ..) = expr.kind - && let ExprKind::Path(qpath) = function.kind - && let Some(def_id) = cx.qpath_res(&qpath, function.hir_id).opt_def_id() - && let Some(function_name) = cx.get_def_path(def_id).last() - && let ty = cx.typeck_results().expr_ty(expr) + let (prefix, name, ty_expr) = match expr.kind { + ExprKind::MethodCall(method_name, receiver, [], ..) => (Prefix::To, method_name.ident.name, receiver), + ExprKind::Call(function, ..) + if let ExprKind::Path(qpath) = function.kind + && let Some(def_id) = cx.qpath_res(&qpath, function.hir_id).opt_def_id() + && let Some(function_name) = cx.get_def_path(def_id).last() => + { + (Prefix::From, *function_name, expr) + }, + _ => return, + }; + if !in_external_macro(cx.sess(), expr.span) + && let ty = cx.typeck_results().expr_ty(ty_expr) && ty.is_primitive_ty() { - maybe_lint_endian_bytes(cx, expr, Prefix::From, *function_name, ty); + maybe_lint_endian_bytes(cx, expr, prefix, name, ty); } } } -fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix, name: Symbol, ty: Ty<'_>) -> bool { +fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix, name: Symbol, ty: Ty<'_>) { let ne = LintKind::Host.as_name(prefix); let le = LintKind::Little.as_name(prefix); let be = LintKind::Big.as_name(prefix); @@ -143,7 +138,7 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix name if name == ne => ((&LintKind::Host), [(&LintKind::Little), (&LintKind::Big)]), name if name == le => ((&LintKind::Little), [(&LintKind::Host), (&LintKind::Big)]), name if name == be => ((&LintKind::Big), [(&LintKind::Host), (&LintKind::Little)]), - _ => return false, + _ => return, }; let mut help = None; @@ -208,6 +203,4 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix } }, ); - - true } From f178316ae24453cf85d3667fed164895d260a1aa Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 11 Jun 2024 00:25:17 -0400 Subject: [PATCH 061/734] Refactor `excessive_bools`: * Check HIR tree before checking for macros. * Check item count before checking for bools. --- clippy_lints/src/excessive_bools.rs | 97 +++++++++++++---------------- 1 file changed, 44 insertions(+), 53 deletions(-) diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 62d5ce24d40a..76e72eefa180 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -87,12 +87,6 @@ pub struct ExcessiveBools { max_fn_params_bools: u64, } -#[derive(Eq, PartialEq, Debug, Copy, Clone)] -enum Kind { - Struct, - Fn, -} - impl ExcessiveBools { #[must_use] pub fn new(max_struct_bools: u64, max_fn_params_bools: u64) -> Self { @@ -101,55 +95,50 @@ impl ExcessiveBools { max_fn_params_bools, } } - - fn too_many_bools<'tcx>(&self, tys: impl Iterator>, kind: Kind) -> bool { - if let Ok(bools) = tys.filter(|ty| is_bool(ty)).count().try_into() { - (if Kind::Fn == kind { - self.max_fn_params_bools - } else { - self.max_struct_bools - }) < bools - } else { - false - } - } - - fn check_fn_sig(&self, cx: &LateContext<'_>, fn_decl: &FnDecl<'_>, span: Span) { - if !span.from_expansion() && self.too_many_bools(fn_decl.inputs.iter(), Kind::Fn) { - span_lint_and_help( - cx, - FN_PARAMS_EXCESSIVE_BOOLS, - span, - format!("more than {} bools in function parameters", self.max_fn_params_bools), - None, - "consider refactoring bools into two-variant enums", - ); - } - } } impl_lint_pass!(ExcessiveBools => [STRUCT_EXCESSIVE_BOOLS, FN_PARAMS_EXCESSIVE_BOOLS]); +fn has_n_bools<'tcx>(iter: impl Iterator>, mut count: u64) -> bool { + iter.filter(|ty| is_bool(ty)).any(|_| { + let (x, overflow) = count.overflowing_sub(1); + count = x; + overflow + }) +} + +fn check_fn_decl(cx: &LateContext<'_>, decl: &FnDecl<'_>, sp: Span, max: u64) { + if has_n_bools(decl.inputs.iter(), max) && !sp.from_expansion() { + span_lint_and_help( + cx, + FN_PARAMS_EXCESSIVE_BOOLS, + sp, + format!("more than {max} bools in function parameters"), + None, + "consider refactoring bools into two-variant enums", + ); + } +} + impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if item.span.from_expansion() { - return; - } - if let ItemKind::Struct(variant_data, _) = &item.kind { - if has_repr_attr(cx, item.hir_id()) { - return; - } - - if self.too_many_bools(variant_data.fields().iter().map(|field| field.ty), Kind::Struct) { - span_lint_and_help( - cx, - STRUCT_EXCESSIVE_BOOLS, - item.span, - format!("more than {} bools in a struct", self.max_struct_bools), - None, - "consider using a state machine or refactoring bools into two-variant enums", - ); - } + if let ItemKind::Struct(variant_data, _) = &item.kind + && variant_data.fields().len() as u64 > self.max_struct_bools + && has_n_bools( + variant_data.fields().iter().map(|field| field.ty), + self.max_struct_bools, + ) + && !has_repr_attr(cx, item.hir_id()) + && !item.span.from_expansion() + { + span_lint_and_help( + cx, + STRUCT_EXCESSIVE_BOOLS, + item.span, + format!("more than {} bools in a struct", self.max_struct_bools), + None, + "consider using a state machine or refactoring bools into two-variant enums", + ); } } @@ -157,8 +146,9 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { // functions with a body are already checked by `check_fn` if let TraitItemKind::Fn(fn_sig, TraitFn::Required(_)) = &trait_item.kind && fn_sig.header.abi == Abi::Rust + && fn_sig.decl.inputs.len() as u64 > self.max_fn_params_bools { - self.check_fn_sig(cx, fn_sig.decl, fn_sig.span); + check_fn_decl(cx, fn_sig.decl, fn_sig.span, self.max_fn_params_bools); } } @@ -171,12 +161,13 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { span: Span, def_id: LocalDefId, ) { - let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); if let Some(fn_header) = fn_kind.header() && fn_header.abi == Abi::Rust - && get_parent_as_impl(cx.tcx, hir_id).map_or(true, |impl_item| impl_item.of_trait.is_none()) + && fn_decl.inputs.len() as u64 > self.max_fn_params_bools + && get_parent_as_impl(cx.tcx, cx.tcx.local_def_id_to_hir_id(def_id)) + .map_or(true, |impl_item| impl_item.of_trait.is_none()) { - self.check_fn_sig(cx, fn_decl, span); + check_fn_decl(cx, fn_decl, span, self.max_fn_params_bools); } } } From d409b5c700e1789a5b2d0b1dd1bd996bfd8bb320 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 11 Jun 2024 02:03:09 -0400 Subject: [PATCH 062/734] `extra_unused_type_parameters`: * Inline `is_empty_exported_or_macro`. * Check if there are any generic parameters before walking the signature. --- .../src/extra_unused_type_parameters.rs | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index 7484f772e082..843ab9d5d99a 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -50,21 +50,6 @@ impl ExtraUnusedTypeParameters { avoid_breaking_exported_api, } } - - /// Don't lint external macros or functions with empty bodies. Also, don't lint exported items - /// if the `avoid_breaking_exported_api` config option is set. - fn is_empty_exported_or_macro( - &self, - cx: &LateContext<'_>, - span: Span, - def_id: LocalDefId, - body_id: BodyId, - ) -> bool { - let body = cx.tcx.hir().body(body_id).value; - let fn_empty = matches!(&body.kind, ExprKind::Block(blk, None) if blk.stmts.is_empty() && blk.expr.is_none()); - let is_exported = cx.effective_visibilities.is_exported(def_id); - in_external_macro(cx.sess(), span) || fn_empty || (is_exported && self.avoid_breaking_exported_api) - } } impl_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]); @@ -266,10 +251,17 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { } } +fn is_empty_body(cx: &LateContext<'_>, body: BodyId) -> bool { + matches!(cx.tcx.hir().body(body).value.kind, ExprKind::Block(b, _) if b.stmts.is_empty() && b.expr.is_none()) +} + impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if let ItemKind::Fn(_, generics, body_id) = item.kind - && !self.is_empty_exported_or_macro(cx, item.span, item.owner_id.def_id, body_id) + && !generics.params.is_empty() + && !is_empty_body(cx, body_id) + && (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id)) + && !in_external_macro(cx.sess(), item.span) && !is_from_proc_macro(cx, item) { let mut walker = TypeWalker::new(cx, generics); @@ -281,8 +273,12 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) { // Only lint on inherent methods, not trait methods. if let ImplItemKind::Fn(.., body_id) = item.kind + && !item.generics.params.is_empty() && trait_ref_of_method(cx, item.owner_id.def_id).is_none() - && !self.is_empty_exported_or_macro(cx, item.span, item.owner_id.def_id, body_id) + && !is_empty_body(cx, body_id) + && (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id)) + && !in_external_macro(cx.sess(), item.span) + && !is_from_proc_macro(cx, item) { let mut walker = TypeWalker::new(cx, item.generics); walk_impl_item(&mut walker, item); From c32af26be02fb3c12d18c28e0c6f2b3c953fda3a Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 11 Jun 2024 14:22:03 -0400 Subject: [PATCH 063/734] Refactor `future_not_send` --- clippy_lints/src/future_not_send.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index cb1d0de1edff..9a43bc69764e 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -66,15 +66,11 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { let ret_ty = return_ty(cx, cx.tcx.local_def_id_to_hir_id(fn_def_id).expect_owner()); if let ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) = *ret_ty.kind() { let preds = cx.tcx.explicit_item_super_predicates(def_id); - let mut is_future = false; - for (p, _span) in preds.iter_instantiated_copied(cx.tcx, args) { - if let Some(trait_pred) = p.as_trait_clause() { - if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() { - is_future = true; - break; - } - } - } + let is_future = preds.iter_instantiated_copied(cx.tcx, args).any(|(p, _)| { + p.as_trait_clause().is_some_and(|trait_pred| { + Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() + }) + }); if is_future { let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap(); let span = decl.output.span(); From 776a5238b7e217fd187074751c19c668960b8fbb Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 11 Jun 2024 14:41:06 -0400 Subject: [PATCH 064/734] `if_let_mutex`: Use `for_each_expr`. --- clippy_lints/src/if_let_mutex.rs | 65 ++++++++------------------------ 1 file changed, 15 insertions(+), 50 deletions(-) diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index a55836a972fb..b38cc7b36a12 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -1,8 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{higher, SpanlessEq}; +use core::ops::ControlFlow; use rustc_errors::Diag; -use rustc_hir::intravisit::{self as visit, Visitor}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -44,8 +45,6 @@ declare_lint_pass!(IfLetMutex => [IF_LET_MUTEX]); impl<'tcx> LateLintPass<'tcx> for IfLetMutex { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - let mut arm_visit = ArmVisitor { found_mutex: None, cx }; - let mut op_visit = OppVisitor { found_mutex: None, cx }; if let Some(higher::IfLet { let_expr, if_then, @@ -53,12 +52,20 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex { .. }) = higher::IfLet::hir(cx, expr) { - op_visit.visit_expr(let_expr); - if let Some(op_mutex) = op_visit.found_mutex { - arm_visit.visit_expr(if_then); - arm_visit.visit_expr(if_else); + let is_mutex_lock = |e: &'tcx Expr<'tcx>| { + if let Some(mutex) = is_mutex_lock_call(cx, e) { + ControlFlow::Break(mutex) + } else { + ControlFlow::Continue(()) + } + }; - if let Some(arm_mutex) = arm_visit.found_mutex_if_same_as(op_mutex) { + let op_mutex = for_each_expr_without_closures(let_expr, is_mutex_lock); + if let Some(op_mutex) = op_mutex { + let arm_mutex = for_each_expr_without_closures((if_then, if_else), is_mutex_lock); + if let Some(arm_mutex) = arm_mutex + && SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex) + { let diag = |diag: &mut Diag<'_, ()>| { diag.span_label( op_mutex.span, @@ -83,48 +90,6 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex { } } -/// Checks if `Mutex::lock` is called in the `if let` expr. -pub struct OppVisitor<'a, 'tcx> { - found_mutex: Option<&'tcx Expr<'tcx>>, - cx: &'a LateContext<'tcx>, -} - -impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if let Some(mutex) = is_mutex_lock_call(self.cx, expr) { - self.found_mutex = Some(mutex); - return; - } - visit::walk_expr(self, expr); - } -} - -/// Checks if `Mutex::lock` is called in any of the branches. -pub struct ArmVisitor<'a, 'tcx> { - found_mutex: Option<&'tcx Expr<'tcx>>, - cx: &'a LateContext<'tcx>, -} - -impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - if let Some(mutex) = is_mutex_lock_call(self.cx, expr) { - self.found_mutex = Some(mutex); - return; - } - visit::walk_expr(self, expr); - } -} - -impl<'tcx, 'l> ArmVisitor<'tcx, 'l> { - fn found_mutex_if_same_as(&self, op_mutex: &Expr<'_>) -> Option<&Expr<'_>> { - self.found_mutex.and_then(|arm_mutex| { - SpanlessEq::new(self.cx) - .eq_expr(op_mutex, arm_mutex) - .then_some(arm_mutex) - }) - } -} - fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind && path.ident.as_str() == "lock" From b26b820f3ffa1697a9dbd66fcf8f29f373556cdb Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 11 Jun 2024 14:47:29 -0400 Subject: [PATCH 065/734] Refactor `if_not_else`: * Check HIR tree first. * Merge lint calls. --- clippy_lints/src/if_not_else.rs | 63 ++++++++++++++------------------- 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index 4dc1ff837711..2f6daeeb90d9 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -56,44 +56,33 @@ fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool { } impl LateLintPass<'_> for IfNotElse { - fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { - // While loops will be desugared to ExprKind::If. This will cause the lint to fire. - // To fix this, return early if this span comes from a macro or desugaring. - if item.span.from_expansion() { - return; - } - if let ExprKind::If(cond, _, Some(els)) = item.kind { - if let ExprKind::Block(..) = els.kind { - // Disable firing the lint in "else if" expressions. - if is_else_clause(cx.tcx, item) { - return; - } + fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) { + if let ExprKind::If(cond, _, Some(els)) = e.kind + && let ExprKind::DropTemps(cond) = cond.kind + && let ExprKind::Block(..) = els.kind + { + let (msg, help) = match cond.kind { + ExprKind::Unary(UnOp::Not, _) => ( + "unnecessary boolean `not` operation", + "remove the `!` and swap the blocks of the `if`/`else`", + ), + // Don't lint on `… != 0`, as these are likely to be bit tests. + // For example, `if foo & 0x0F00 != 0 { … } else { … }` is already in the "proper" order. + ExprKind::Binary(op, _, rhs) if op.node == BinOpKind::Ne && !is_zero_const(rhs, cx) => ( + "unnecessary `!=` operation", + "change to `==` and swap the blocks of the `if`/`else`", + ), + _ => return, + }; - match cond.peel_drop_temps().kind { - ExprKind::Unary(UnOp::Not, _) => { - span_lint_and_help( - cx, - IF_NOT_ELSE, - item.span, - "unnecessary boolean `not` operation", - None, - "remove the `!` and swap the blocks of the `if`/`else`", - ); - }, - ExprKind::Binary(ref kind, _, lhs) if kind.node == BinOpKind::Ne && !is_zero_const(lhs, cx) => { - // Disable firing the lint on `… != 0`, as these are likely to be bit tests. - // For example, `if foo & 0x0F00 != 0 { … } else { … }` already is in the "proper" order. - span_lint_and_help( - cx, - IF_NOT_ELSE, - item.span, - "unnecessary `!=` operation", - None, - "change to `==` and swap the blocks of the `if`/`else`", - ); - }, - _ => (), - } + // `from_expansion` will also catch `while` loops which appear in the HIR as: + // ```rust + // loop { + // if cond { ... } else { break; } + // } + // ``` + if !e.span.from_expansion() && !is_else_clause(cx.tcx, e) { + span_lint_and_help(cx, IF_NOT_ELSE, e.span, msg, None, help); } } } From 517e1ac225209a8c02e20cd8c148412b64850261 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 11 Jun 2024 14:56:15 -0400 Subject: [PATCH 066/734] `if_then_some_else_none`: Check HIR tree before other checks. --- clippy_lints/src/if_then_some_else_none.rs | 25 +++++----------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 0b2008152198..087bf9e9d056 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -61,26 +61,6 @@ impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]); impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if !self.msrv.meets(msrvs::BOOL_THEN) { - return; - } - - if in_external_macro(cx.sess(), expr.span) { - return; - } - - // We only care about the top-most `if` in the chain - if is_else_clause(cx.tcx, expr) { - return; - } - - // `bool::then()` and `bool::then_some()` are not const - if in_constant(cx, expr.hir_id) { - return; - } - - let ctxt = expr.span.ctxt(); - if let Some(higher::If { cond, then, @@ -89,9 +69,14 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { && let ExprKind::Block(then_block, _) = then.kind && let Some(then_expr) = then_block.expr && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind + && let ctxt = expr.span.ctxt() && then_expr.span.ctxt() == ctxt && is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome) && is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone) + && !is_else_clause(cx.tcx, expr) + && !in_constant(cx, expr.hir_id) + && !in_external_macro(cx.sess(), expr.span) + && self.msrv.meets(msrvs::BOOL_THEN) && !contains_return(then_block.stmts) { let mut app = Applicability::Unspecified; From 3869e934080b145f349dca2b296d750bf9a9f757 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 11 Jun 2024 14:59:36 -0400 Subject: [PATCH 067/734] `ignored_unit_patterns`: Reorder checks. --- clippy_lints/src/ignored_unit_patterns.rs | 31 +++++++++++------------ 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/ignored_unit_patterns.rs b/clippy_lints/src/ignored_unit_patterns.rs index a32201d80793..54b8adbc8ac7 100644 --- a/clippy_lints/src/ignored_unit_patterns.rs +++ b/clippy_lints/src/ignored_unit_patterns.rs @@ -37,22 +37,21 @@ declare_lint_pass!(IgnoredUnitPatterns => [IGNORED_UNIT_PATTERNS]); impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) { - if pat.span.from_expansion() { - return; - } - - match cx.tcx.parent_hir_node(pat.hir_id) { - Node::Param(param) if matches!(cx.tcx.parent_hir_node(param.hir_id), Node::Item(_)) => { - // Ignore function parameters - return; - }, - Node::LetStmt(local) if local.ty.is_some() => { - // Ignore let bindings with explicit type - return; - }, - _ => {}, - } - if matches!(pat.kind, PatKind::Wild) && cx.typeck_results().pat_ty(pat).peel_refs().is_unit() { + if matches!(pat.kind, PatKind::Wild) + && !pat.span.from_expansion() + && cx.typeck_results().pat_ty(pat).peel_refs().is_unit() + { + match cx.tcx.parent_hir_node(pat.hir_id) { + Node::Param(param) if matches!(cx.tcx.parent_hir_node(param.hir_id), Node::Item(_)) => { + // Ignore function parameters + return; + }, + Node::LetStmt(local) if local.ty.is_some() => { + // Ignore let bindings with explicit type + return; + }, + _ => {}, + } span_lint_and_sugg( cx, IGNORED_UNIT_PATTERNS, From b58b491d162bbb4b8f417b8abfcce1c6083208b9 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 11 Jun 2024 15:06:14 -0400 Subject: [PATCH 068/734] `inconsistent_struct_constructor`: Check HIR tree first. --- clippy_lints/src/inconsistent_struct_constructor.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index 1075975f0a21..5b0aadf35c62 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -65,13 +65,13 @@ declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRU impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if !expr.span.from_expansion() - && let ExprKind::Struct(qpath, fields, base) = expr.kind + if let ExprKind::Struct(qpath, fields, base) = expr.kind + && fields.iter().all(|f| f.is_shorthand) + && !expr.span.from_expansion() && let ty = cx.typeck_results().expr_ty(expr) && let Some(adt_def) = ty.ty_adt_def() && adt_def.is_struct() && let Some(variant) = adt_def.variants().iter().next() - && fields.iter().all(|f| f.is_shorthand) { let mut def_order_map = FxHashMap::default(); for (idx, field) in variant.fields.iter().enumerate() { From 06f83b4e2603b9bb702383199e57480b88f2382a Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 11 Jun 2024 15:10:05 -0400 Subject: [PATCH 069/734] `index_refutable_slice`: Check HIR tree first. --- clippy_lints/src/index_refutable_slice.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 128461ce7bcf..4ce2fa32fe56 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -70,8 +70,8 @@ impl_lint_pass!(IndexRefutableSlice => [INDEX_REFUTABLE_SLICE]); impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if (!expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some()) - && let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr) + if let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr) + && (!expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some()) && !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id) && self.msrv.meets(msrvs::SLICE_PATTERNS) && let found_slices = find_slice_values(cx, let_pat) From c73aceb0435ca35e47d0d8361ce49a74ff3ec70b Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 11 Jun 2024 15:11:20 -0400 Subject: [PATCH 070/734] `indexing_slicing`: Check HIR tree first. --- clippy_lints/src/indexing_slicing.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index d54f2af65cde..52073d2ee4cd 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -102,13 +102,8 @@ impl IndexingSlicing { impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if (self.suppress_restriction_lint_in_const && cx.tcx.hir().is_inside_const_context(expr.hir_id)) - || is_from_proc_macro(cx, expr) - { - return; - } - if let ExprKind::Index(array, index, _) = &expr.kind + && (!self.suppress_restriction_lint_in_const || !cx.tcx.hir().is_inside_const_context(expr.hir_id)) && let expr_ty = cx.typeck_results().expr_ty(array) && let mut deref = deref_chain(cx, expr_ty) && deref.any(|l| { @@ -116,6 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { || l.peel_refs().is_array() || ty_has_applicable_get_function(cx, l.peel_refs(), expr_ty, expr) }) + && !is_from_proc_macro(cx, expr) { let note = "the suggestion might not be applicable in constant blocks"; let ty = cx.typeck_results().expr_ty(array).peel_refs(); From f493d71a38f9737e512b133598bcb78981619f58 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 12 Jun 2024 12:59:55 -0400 Subject: [PATCH 071/734] `infinite_iter`: Only lock the symbol table once. --- clippy_lints/src/infinite_iter.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 9ad02735878a..fa7e7f6b76d1 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -226,13 +226,14 @@ const INFINITE_COLLECTORS: &[Symbol] = &[ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { match expr.kind { ExprKind::MethodCall(method, receiver, args, _) => { + let method_str = method.ident.name.as_str(); for &(name, len) in &COMPLETING_METHODS { - if method.ident.name.as_str() == name && args.len() == len { + if method_str == name && args.len() == len { return is_infinite(cx, receiver); } } for &(name, len) in &POSSIBLY_COMPLETING_METHODS { - if method.ident.name.as_str() == name && args.len() == len { + if method_str == name && args.len() == len { return MaybeInfinite.and(is_infinite(cx, receiver)); } } From 4fe8dd05ed844df0509adcad801e8ff32716c2f8 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 6 Jul 2024 11:45:47 +1000 Subject: [PATCH 072/734] Remove the non-assigning form of `unpack!` This kind of unpacking can be expressed as an ordinary method on `BlockAnd<()>`. --- compiler/rustc_mir_build/src/build/block.rs | 4 +-- .../src/build/expr/as_rvalue.rs | 2 +- .../rustc_mir_build/src/build/expr/into.rs | 24 ++++++++------- .../rustc_mir_build/src/build/matches/mod.rs | 30 +++++++++++-------- compiler/rustc_mir_build/src/build/mod.rs | 25 +++++++++------- compiler/rustc_mir_build/src/build/scope.rs | 19 +++++++----- 6 files changed, 60 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index 5ccbd7c59cfb..813fd17606da 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -282,7 +282,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) } else { let scope = (*init_scope, source_info); - unpack!(this.in_scope(scope, *lint_level, |this| { + let _: BlockAnd<()> = this.in_scope(scope, *lint_level, |this| { this.declare_bindings( visibility_scope, remainder_span, @@ -291,7 +291,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, ); block.unit() - })); + }); debug!("ast_block_stmts: pattern={:?}", pattern); this.visit_primary_bindings( diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index c5ee6db5999a..f0725e18b46e 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -486,7 +486,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(Rvalue::Aggregate(result, operands)) } ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { - block = unpack!(this.stmt_expr(block, expr_id, None)); + block = this.stmt_expr(block, expr_id, None).into_block(); block.and(Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span: expr_span, user_ty: None, diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 942c69b5c0a7..0e5337ba4e12 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -82,13 +82,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Lower the condition, and have it branch into `then` and `else` blocks. let (then_block, else_block) = this.in_if_then_scope(condition_scope, then_span, |this| { - let then_blk = unpack!(this.then_else_break( - block, - cond, - Some(condition_scope), // Temp scope - source_info, - DeclareLetBindings::Yes, // Declare `let` bindings normally - )); + let then_blk = this + .then_else_break( + block, + cond, + Some(condition_scope), // Temp scope + source_info, + DeclareLetBindings::Yes, // Declare `let` bindings normally + ) + .into_block(); // Lower the `then` arm into its block. this.expr_into_dest(destination, then_blk, then) @@ -187,7 +189,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { const_: Const::from_bool(this.tcx, constant), }, ); - let mut rhs_block = unpack!(this.expr_into_dest(destination, continuation, rhs)); + let mut rhs_block = + this.expr_into_dest(destination, continuation, rhs).into_block(); // Instrument the lowered RHS's value for condition coverage. // (Does nothing if condition coverage is not enabled.) this.visit_coverage_standalone_condition(rhs, destination, &mut rhs_block); @@ -230,7 +233,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // introduce a unit temporary as the destination for the loop body. let tmp = this.get_unit_temp(); // Execute the body, branching back to the test. - let body_block_end = unpack!(this.expr_into_dest(tmp, body_block, body)); + let body_block_end = this.expr_into_dest(tmp, body_block, body).into_block(); this.cfg.goto(body_block_end, source_info, loop_block); // Loops are only exited by `break` expressions. @@ -462,7 +465,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { targets.push(target); let tmp = this.get_unit_temp(); - let target = unpack!(this.ast_block(tmp, target, block, source_info)); + let target = + this.ast_block(tmp, target, block, source_info).into_block(); this.cfg.terminate( target, source_info, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index e435e2f92883..be1ea0f8ba9a 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -121,8 +121,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match expr.kind { ExprKind::LogicalOp { op: op @ LogicalOp::And, lhs, rhs } => { this.visit_coverage_branch_operation(op, expr_span); - let lhs_then_block = unpack!(this.then_else_break_inner(block, lhs, args)); - let rhs_then_block = unpack!(this.then_else_break_inner(lhs_then_block, rhs, args)); + let lhs_then_block = this.then_else_break_inner(block, lhs, args).into_block(); + let rhs_then_block = + this.then_else_break_inner(lhs_then_block, rhs, args).into_block(); rhs_then_block.unit() } ExprKind::LogicalOp { op: op @ LogicalOp::Or, lhs, rhs } => { @@ -139,14 +140,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, ) }); - let rhs_success_block = unpack!(this.then_else_break_inner( - failure_block, - rhs, - ThenElseArgs { - declare_let_bindings: DeclareLetBindings::LetNotPermitted, - ..args - }, - )); + let rhs_success_block = this + .then_else_break_inner( + failure_block, + rhs, + ThenElseArgs { + declare_let_bindings: DeclareLetBindings::LetNotPermitted, + ..args + }, + ) + .into_block(); // Make the LHS and RHS success arms converge to a common block. // (We can't just make LHS goto RHS, because `rhs_success_block` @@ -451,7 +454,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { outer_source_info: SourceInfo, fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)>, ) -> BlockAnd<()> { - let arm_end_blocks: Vec<_> = arm_candidates + let arm_end_blocks: Vec = arm_candidates .into_iter() .map(|(arm, candidate)| { debug!("lowering arm {:?}\ncandidate = {:?}", arm, candidate); @@ -502,6 +505,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.expr_into_dest(destination, arm_block, arm.body) }) + .into_block() }) .collect(); @@ -512,10 +516,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { outer_source_info.span.with_lo(outer_source_info.span.hi() - BytePos::from_usize(1)), ); for arm_block in arm_end_blocks { - let block = &self.cfg.basic_blocks[arm_block.0]; + let block = &self.cfg.basic_blocks[arm_block]; let last_location = block.statements.last().map(|s| s.source_info); - self.cfg.goto(unpack!(arm_block), last_location.unwrap_or(end_brace), end_block); + self.cfg.goto(arm_block, last_location.unwrap_or(end_brace), end_block); } self.source_scope = outer_source_info.scope; diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 0f9746cb719c..04aaa806d594 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -403,6 +403,15 @@ enum NeedsTemporary { #[must_use = "if you don't use one of these results, you're leaving a dangling edge"] struct BlockAnd(BasicBlock, T); +impl BlockAnd<()> { + /// Unpacks `BlockAnd<()>` into a [`BasicBlock`]. + #[must_use] + fn into_block(self) -> BasicBlock { + let Self(block, ()) = self; + block + } +} + trait BlockAndExtension { fn and(self, v: T) -> BlockAnd; fn unit(self) -> BlockAnd<()>; @@ -426,11 +435,6 @@ macro_rules! unpack { $x = b; v }}; - - ($c:expr) => {{ - let BlockAnd(b, ()) = $c; - b - }}; } /////////////////////////////////////////////////////////////////////////// @@ -516,21 +520,22 @@ fn construct_fn<'tcx>( region::Scope { id: body.id().hir_id.local_id, data: region::ScopeData::Arguments }; let source_info = builder.source_info(span); let call_site_s = (call_site_scope, source_info); - unpack!(builder.in_scope(call_site_s, LintLevel::Inherited, |builder| { + let _: BlockAnd<()> = builder.in_scope(call_site_s, LintLevel::Inherited, |builder| { let arg_scope_s = (arg_scope, source_info); // Attribute epilogue to function's closing brace let fn_end = span_with_body.shrink_to_hi(); - let return_block = - unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| { + let return_block = builder + .in_breakable_scope(None, Place::return_place(), fn_end, |builder| { Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { builder.args_and_body(START_BLOCK, arguments, arg_scope, expr) })) - })); + }) + .into_block(); let source_info = builder.source_info(fn_end); builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); builder.build_drop_trees(); return_block.unit() - })); + }); let mut body = builder.finish(); diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 5b6de39bb2e7..d6be0e7a252e 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -510,12 +510,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let target = self.cfg.start_new_block(); let source_info = self.source_info(span); self.cfg.terminate( - unpack!(normal_block), + normal_block.into_block(), source_info, TerminatorKind::Goto { target }, ); self.cfg.terminate( - unpack!(exit_block), + exit_block.into_block(), source_info, TerminatorKind::Goto { target }, ); @@ -552,14 +552,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let scope = IfThenScope { region_scope, else_drops: DropTree::new() }; let previous_scope = mem::replace(&mut self.scopes.if_then_scope, Some(scope)); - let then_block = unpack!(f(self)); + let then_block = f(self).into_block(); let if_then_scope = mem::replace(&mut self.scopes.if_then_scope, previous_scope).unwrap(); assert!(if_then_scope.region_scope == region_scope); - let else_block = self - .build_exit_tree(if_then_scope.else_drops, region_scope, span, None) - .map_or_else(|| self.cfg.start_new_block(), |else_block_and| unpack!(else_block_and)); + let else_block = + self.build_exit_tree(if_then_scope.else_drops, region_scope, span, None).map_or_else( + || self.cfg.start_new_block(), + |else_block_and| else_block_and.into_block(), + ); (then_block, else_block) } @@ -753,7 +755,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let unwind_to = if needs_cleanup { self.diverge_cleanup() } else { DropIdx::MAX }; let scope = self.scopes.scopes.last().expect("leave_top_scope called with no scopes"); - unpack!(build_scope_drops( + build_scope_drops( &mut self.cfg, &mut self.scopes.unwind_drops, scope, @@ -761,7 +763,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { unwind_to, is_coroutine && needs_cleanup, self.arg_count, - )) + ) + .into_block() } /// Possibly creates a new source scope if `current_root` and `parent_root` From 36a14e3a12c41f8bdf7087d350a454d6fe05e29d Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 13 Jun 2024 18:56:11 -0400 Subject: [PATCH 073/734] `misc`: * Delay macro checks. * Use `span_lint_hir`. --- clippy_lints/src/misc.rs | 43 +++++++++++++++------------------ tests/ui/toplevel_ref_arg.fixed | 2 ++ tests/ui/toplevel_ref_arg.rs | 2 ++ 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 32c8731c5374..a9aafe7ed56c 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_then, span_lint_hir_and_then}; +use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir, span_lint_hir_and_then}; use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::{ @@ -114,40 +114,35 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { k: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, - span: Span, + _: Span, _: LocalDefId, ) { - if let FnKind::Closure = k { - // Does not apply to closures - return; - } - if in_external_macro(cx.tcx.sess, span) { - return; - } - for arg in iter_input_pats(decl, body) { - // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue. - if !is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id) { - return; - } - if let PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..) = arg.pat.kind { - span_lint( - cx, - TOPLEVEL_REF_ARG, - arg.pat.span, - "`ref` directly on a function argument is ignored. \ - Consider using a reference type instead", - ); + if !matches!(k, FnKind::Closure) { + for arg in iter_input_pats(decl, body) { + if let PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..) = arg.pat.kind + && is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id) + && !in_external_macro(cx.tcx.sess, arg.span) + { + span_lint_hir( + cx, + TOPLEVEL_REF_ARG, + arg.hir_id, + arg.pat.span, + "`ref` directly on a function argument is ignored. \ + Consider using a reference type instead", + ); + } } } } fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { - if !in_external_macro(cx.tcx.sess, stmt.span) - && let StmtKind::Let(local) = stmt.kind + if let StmtKind::Let(local) = stmt.kind && let PatKind::Binding(BindingMode(ByRef::Yes(mutabl), _), .., name, None) = local.pat.kind && let Some(init) = local.init // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue. && is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id) + && !in_external_macro(cx.tcx.sess, stmt.span) { let ctxt = local.span.ctxt(); let mut app = Applicability::MachineApplicable; diff --git a/tests/ui/toplevel_ref_arg.fixed b/tests/ui/toplevel_ref_arg.fixed index ff5cd7abbb69..3eb47a5b5fd6 100644 --- a/tests/ui/toplevel_ref_arg.fixed +++ b/tests/ui/toplevel_ref_arg.fixed @@ -36,4 +36,6 @@ fn main() { // do not lint in external macro external!(let ref _y = 42;); + + fn f(#[allow(clippy::toplevel_ref_arg)] ref x: i32) {} } diff --git a/tests/ui/toplevel_ref_arg.rs b/tests/ui/toplevel_ref_arg.rs index ab79b8959605..cd731387de97 100644 --- a/tests/ui/toplevel_ref_arg.rs +++ b/tests/ui/toplevel_ref_arg.rs @@ -36,4 +36,6 @@ fn main() { // do not lint in external macro external!(let ref _y = 42;); + + fn f(#[allow(clippy::toplevel_ref_arg)] ref x: i32) {} } From 1cf4eb2ad258281fcf59ec93f41b43117bb5b824 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 6 Jul 2024 11:55:54 +1000 Subject: [PATCH 074/734] Stop using `unpack!` for `BlockAnd<()>` --- compiler/rustc_mir_build/src/build/block.rs | 22 +++++++++---------- .../src/build/expr/as_rvalue.rs | 10 +++------ .../rustc_mir_build/src/build/expr/as_temp.rs | 2 +- .../rustc_mir_build/src/build/expr/into.rs | 6 ++--- .../rustc_mir_build/src/build/expr/stmt.rs | 3 ++- .../rustc_mir_build/src/build/matches/mod.rs | 4 ++-- compiler/rustc_mir_build/src/build/mod.rs | 4 ++-- compiler/rustc_mir_build/src/build/scope.rs | 4 ++-- 8 files changed, 26 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index 813fd17606da..c608e5c63d84 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -71,11 +71,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { StmtKind::Expr { scope, expr } => { this.block_context.push(BlockFrame::Statement { ignores_expr_result: true }); let si = (*scope, source_info); - unpack!( - block = this.in_scope(si, LintLevel::Inherited, |this| { + block = this + .in_scope(si, LintLevel::Inherited, |this| { this.stmt_expr(block, *expr, Some(*scope)) }) - ); + .into_block(); } StmtKind::Let { remainder_scope, @@ -166,14 +166,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let dummy_place = this.temp(this.tcx.types.never, else_block_span); let failure_entry = this.cfg.start_new_block(); let failure_block; - unpack!( - failure_block = this.ast_block( + failure_block = this + .ast_block( dummy_place, failure_entry, *else_block, this.source_info(else_block_span), ) - ); + .into_block(); this.cfg.terminate( failure_block, this.source_info(else_block_span), @@ -267,8 +267,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let initializer_span = this.thir[init].span; let scope = (*init_scope, source_info); - unpack!( - block = this.in_scope(scope, *lint_level, |this| { + block = this + .in_scope(scope, *lint_level, |this| { this.declare_bindings( visibility_scope, remainder_span, @@ -279,7 +279,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.expr_into_pattern(block, &pattern, init) // irrefutable pattern }) - ) + .into_block(); } else { let scope = (*init_scope, source_info); let _: BlockAnd<()> = this.in_scope(scope, *lint_level, |this| { @@ -333,7 +333,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.block_context .push(BlockFrame::TailExpr { tail_result_is_ignored, span: expr.span }); - unpack!(block = this.expr_into_dest(destination, block, expr_id)); + block = this.expr_into_dest(destination, block, expr_id).into_block(); let popped = this.block_context.pop(); assert!(popped.is_some_and(|bf| bf.is_tail_expr())); @@ -355,7 +355,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Finally, we pop all the let scopes before exiting out from the scope of block // itself. for scope in let_scope_stack.into_iter().rev() { - unpack!(block = this.pop_scope((*scope, source_info), block)); + block = this.pop_scope((*scope, source_info), block).into_block(); } // Restore the original source scope. this.source_scope = outer_source_scope; diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index f0725e18b46e..40cfe563acce 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -185,13 +185,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.cfg.push_assign(block, source_info, Place::from(result), box_); // initialize the box contents: - unpack!( - block = this.expr_into_dest( - this.tcx.mk_place_deref(Place::from(result)), - block, - value, - ) - ); + block = this + .expr_into_dest(this.tcx.mk_place_deref(Place::from(result)), block, value) + .into_block(); block.and(Rvalue::Use(Operand::Move(Place::from(result)))) } ExprKind::Cast { source } => { diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index 607c7c3259c1..82673582e796 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -112,7 +112,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - unpack!(block = this.expr_into_dest(temp_place, block, expr_id)); + block = this.expr_into_dest(temp_place, block, expr_id).into_block(); if let Some(temp_lifetime) = temp_lifetime { this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value); diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 0e5337ba4e12..9cd958a21da4 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -107,7 +107,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // If there is an `else` arm, lower it into `else_blk`. if let Some(else_expr) = else_opt { - unpack!(else_blk = this.expr_into_dest(destination, else_blk, else_expr)); + else_blk = this.expr_into_dest(destination, else_blk, else_expr).into_block(); } else { // There is no `else` arm, so we know both arms have type `()`. // Generate the implicit `else {}` by assigning unit. @@ -506,7 +506,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // These cases don't actually need a destination ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { - unpack!(block = this.stmt_expr(block, expr_id, None)); + block = this.stmt_expr(block, expr_id, None).into_block(); this.cfg.push_assign_unit(block, source_info, destination, this.tcx); block.unit() } @@ -515,7 +515,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Break { .. } | ExprKind::Return { .. } | ExprKind::Become { .. } => { - unpack!(block = this.stmt_expr(block, expr_id, None)); + block = this.stmt_expr(block, expr_id, None).into_block(); // No assign, as these have type `!`. block.unit() } diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index 2bdeb579a02d..088d6631d959 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -42,7 +42,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if lhs_expr.ty.needs_drop(this.tcx, this.param_env) { let rhs = unpack!(block = this.as_local_rvalue(block, rhs)); let lhs = unpack!(block = this.as_place(block, lhs)); - unpack!(block = this.build_drop_and_replace(block, lhs_expr.span, lhs, rhs)); + block = + this.build_drop_and_replace(block, lhs_expr.span, lhs, rhs).into_block(); } else { let rhs = unpack!(block = this.as_local_rvalue(block, rhs)); let lhs = unpack!(block = this.as_place(block, lhs)); diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index be1ea0f8ba9a..bffd325e3118 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -625,7 +625,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { OutsideGuard, ScheduleDrops::Yes, ); - unpack!(block = self.expr_into_dest(place, block, initializer_id)); + block = self.expr_into_dest(place, block, initializer_id).into_block(); // Inject a fake read, see comments on `FakeReadCause::ForLet`. let source_info = self.source_info(irrefutable_pat.span); @@ -664,7 +664,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { OutsideGuard, ScheduleDrops::Yes, ); - unpack!(block = self.expr_into_dest(place, block, initializer_id)); + block = self.expr_into_dest(place, block, initializer_id).into_block(); // Inject a fake read, see comments on `FakeReadCause::ForLet`. let pattern_source_info = self.source_info(irrefutable_pat.span); diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 04aaa806d594..2793a7d87362 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -584,7 +584,7 @@ fn construct_const<'a, 'tcx>( Builder::new(thir, infcx, def, hir_id, span, 0, const_ty, const_ty_span, None); let mut block = START_BLOCK; - unpack!(block = builder.expr_into_dest(Place::return_place(), block, expr)); + block = builder.expr_into_dest(Place::return_place(), block, expr).into_block(); let source_info = builder.source_info(span); builder.cfg.terminate(block, source_info, TerminatorKind::Return); @@ -966,7 +966,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some((Some(&place), span)), ); let place_builder = PlaceBuilder::from(local); - unpack!(block = self.place_into_pattern(block, pat, place_builder, false)); + block = self.place_into_pattern(block, pat, place_builder, false).into_block(); } } self.source_scope = original_source_scope; diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index d6be0e7a252e..a2424b0fef12 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -587,7 +587,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.push_scope(region_scope); let mut block; let rv = unpack!(block = f(self)); - unpack!(block = self.pop_scope(region_scope, block)); + block = self.pop_scope(region_scope, block).into_block(); self.source_scope = source_scope; debug!(?block); block.and(rv) @@ -659,7 +659,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (Some(destination), Some(value)) => { debug!("stmt_expr Break val block_context.push(SubExpr)"); self.block_context.push(BlockFrame::SubExpr); - unpack!(block = self.expr_into_dest(destination, block, value)); + block = self.expr_into_dest(destination, block, value).into_block(); self.block_context.pop(); } (Some(destination), None) => { From 58aa804ada9c13e8e5e89e6f25594d52ba835816 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 13 Jun 2024 19:00:18 -0400 Subject: [PATCH 075/734] `mismatching_type_param_order`: Delay macro check. --- clippy_lints/src/mismatching_type_param_order.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs index 934b9f490add..748289454bea 100644 --- a/clippy_lints/src/mismatching_type_param_order.rs +++ b/clippy_lints/src/mismatching_type_param_order.rs @@ -49,12 +49,12 @@ declare_lint_pass!(TypeParamMismatch => [MISMATCHING_TYPE_PARAM_ORDER]); impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if !item.span.from_expansion() - && let ItemKind::Impl(imp) = &item.kind + if let ItemKind::Impl(imp) = &item.kind && let TyKind::Path(QPath::Resolved(_, path)) = &imp.self_ty.kind - && let Some(segment) = path.segments.iter().next() + && let [segment, ..] = path.segments && let Some(generic_args) = segment.args && !generic_args.args.is_empty() + && !item.span.from_expansion() { // get the name and span of the generic parameters in the Impl let mut impl_params = Vec::new(); From c22608823f5831f068f027deec09899d6971489a Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 13 Jun 2024 19:20:21 -0400 Subject: [PATCH 076/734] `needless_borrowed_ref`: Check HIR tree first. --- clippy_lints/src/needless_borrowed_ref.rs | 142 ++++++++++------------ 1 file changed, 67 insertions(+), 75 deletions(-) diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index fb02f24c9dc6..098098718af3 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -37,83 +37,75 @@ declare_lint_pass!(NeedlessBorrowedRef => [NEEDLESS_BORROWED_REFERENCE]); impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef { fn check_pat(&mut self, cx: &LateContext<'tcx>, ref_pat: &'tcx Pat<'_>) { - if ref_pat.span.from_expansion() { - // OK, simple enough, lints doesn't check in macro. - return; - } - - // Do not lint patterns that are part of an OR `|` pattern, the binding mode must match in all arms - for (_, node) in cx.tcx.hir().parent_iter(ref_pat.hir_id) { - let Node::Pat(pat) = node else { break }; - - if matches!(pat.kind, PatKind::Or(_)) { - return; + if let PatKind::Ref(pat, Mutability::Not) = ref_pat.kind + && !ref_pat.span.from_expansion() + && cx + .tcx + .hir() + .parent_iter(ref_pat.hir_id) + .map_while(|(_, parent)| if let Node::Pat(pat) = parent { Some(pat) } else { None }) + // Do not lint patterns that are part of an OR `|` pattern, the binding mode must match in all arms + .all(|pat| !matches!(pat.kind, PatKind::Or(_))) + { + match pat.kind { + // Check sub_pat got a `ref` keyword (excluding `ref mut`). + PatKind::Binding(BindingMode::REF, _, ident, None) => { + span_lint_and_then( + cx, + NEEDLESS_BORROWED_REFERENCE, + ref_pat.span, + "this pattern takes a reference on something that is being dereferenced", + |diag| { + // `&ref ident` + // ^^^^^ + let span = ref_pat.span.until(ident.span); + diag.span_suggestion_verbose( + span, + "try removing the `&ref` part", + String::new(), + Applicability::MachineApplicable, + ); + }, + ); + }, + // Slices where each element is `ref`: `&[ref a, ref b, ..., ref z]` + PatKind::Slice( + before, + None + | Some(Pat { + kind: PatKind::Wild, .. + }), + after, + ) => { + check_subpatterns( + cx, + "dereferencing a slice pattern where every element takes a reference", + ref_pat, + pat, + itertools::chain(before, after), + ); + }, + PatKind::Tuple(subpatterns, _) | PatKind::TupleStruct(_, subpatterns, _) => { + check_subpatterns( + cx, + "dereferencing a tuple pattern where every element takes a reference", + ref_pat, + pat, + subpatterns, + ); + }, + PatKind::Struct(_, fields, _) => { + check_subpatterns( + cx, + "dereferencing a struct pattern where every field's pattern takes a reference", + ref_pat, + pat, + fields.iter().map(|field| field.pat), + ); + }, + _ => {}, } } - - // Only lint immutable refs, because `&mut ref T` may be useful. - let PatKind::Ref(pat, Mutability::Not) = ref_pat.kind else { - return; - }; - - match pat.kind { - // Check sub_pat got a `ref` keyword (excluding `ref mut`). - PatKind::Binding(BindingMode::REF, _, ident, None) => { - span_lint_and_then( - cx, - NEEDLESS_BORROWED_REFERENCE, - ref_pat.span, - "this pattern takes a reference on something that is being dereferenced", - |diag| { - // `&ref ident` - // ^^^^^ - let span = ref_pat.span.until(ident.span); - diag.span_suggestion_verbose( - span, - "try removing the `&ref` part", - String::new(), - Applicability::MachineApplicable, - ); - }, - ); - }, - // Slices where each element is `ref`: `&[ref a, ref b, ..., ref z]` - PatKind::Slice( - before, - None - | Some(Pat { - kind: PatKind::Wild, .. - }), - after, - ) => { - check_subpatterns( - cx, - "dereferencing a slice pattern where every element takes a reference", - ref_pat, - pat, - itertools::chain(before, after), - ); - }, - PatKind::Tuple(subpatterns, _) | PatKind::TupleStruct(_, subpatterns, _) => { - check_subpatterns( - cx, - "dereferencing a tuple pattern where every element takes a reference", - ref_pat, - pat, - subpatterns, - ); - }, - PatKind::Struct(_, fields, _) => { - check_subpatterns( - cx, - "dereferencing a struct pattern where every field's pattern takes a reference", - ref_pat, - pat, - fields.iter().map(|field| field.pat), - ); - }, - _ => {}, - } } } From 139dad88497f88f1041d6240aee406ce3afd45c8 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 13 Jun 2024 19:12:10 -0400 Subject: [PATCH 077/734] `mut_mut`: Delay macro check --- clippy_lints/src/mut_mut.rs | 37 +++++++++++-------------------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index bc7b2c6b7c1b..60372121a7a4 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -35,33 +35,18 @@ impl<'tcx> LateLintPass<'tcx> for MutMut { } fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'_>) { - if in_external_macro(cx.sess(), ty.span) { - return; - } - - if let hir::TyKind::Ref( - _, - hir::MutTy { - ty: pty, - mutbl: hir::Mutability::Mut, - }, - ) = ty.kind + if let hir::TyKind::Ref(_, mty) = ty.kind + && mty.mutbl == hir::Mutability::Mut + && let hir::TyKind::Ref(_, mty) = mty.ty.kind + && mty.mutbl == hir::Mutability::Mut + && !in_external_macro(cx.sess(), ty.span) { - if let hir::TyKind::Ref( - _, - hir::MutTy { - mutbl: hir::Mutability::Mut, - .. - }, - ) = pty.kind - { - span_lint( - cx, - MUT_MUT, - ty.span, - "generally you want to avoid `&mut &mut _` if possible", - ); - } + span_lint( + cx, + MUT_MUT, + ty.span, + "generally you want to avoid `&mut &mut _` if possible", + ); } } } From 7c17dd331bb5708152ef2c2dd91c67287f9d821d Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 15 Jun 2024 02:13:32 -0400 Subject: [PATCH 078/734] `needless_for_each`: Check HIR tree first. --- clippy_lints/src/needless_for_each.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 143acc2b1cb7..6390e51f916b 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -3,7 +3,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{sym, Span}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_trait_method; @@ -55,16 +55,8 @@ declare_lint_pass!(NeedlessForEach => [NEEDLESS_FOR_EACH]); impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { - let (StmtKind::Expr(expr) | StmtKind::Semi(expr)) = stmt.kind else { - return; - }; - - if let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind - // Check the method name is `for_each`. - && method_name.ident.name == Symbol::intern("for_each") - // Check `for_each` is an associated function of `Iterator`. - && is_trait_method(cx, expr, sym::Iterator) - // Checks the receiver of `for_each` is also a method call. + if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind + && let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind && let ExprKind::MethodCall(_, iter_recv, [], _) = for_each_recv.kind // Skip the lint if the call chain is too long. e.g. `v.field.iter().for_each()` or // `v.foo().iter().for_each()` must be skipped. @@ -72,6 +64,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { iter_recv.kind, ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::Path(..) ) + && method_name.ident.name.as_str() == "for_each" + && is_trait_method(cx, expr, sym::Iterator) // Checks the type of the `iter` method receiver is NOT a user defined type. && has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some() // Skip the lint if the body is not block because this is simpler than `for` loop. From ff28de20b4c9522cce639a8e5dbff433501ae265 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 15 Jun 2024 11:16:20 -0400 Subject: [PATCH 079/734] `neg_cmp_op_on_partial_ord`: Delay macro check --- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index f7621822b66c..fa90ee606121 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -45,10 +45,10 @@ declare_lint_pass!(NoNegCompOpForPartialOrd => [NEG_CMP_OP_ON_PARTIAL_ORD]); impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !in_external_macro(cx.sess(), expr.span) - && let ExprKind::Unary(UnOp::Not, inner) = expr.kind + if let ExprKind::Unary(UnOp::Not, inner) = expr.kind && let ExprKind::Binary(ref op, left, _) = inner.kind && let BinOpKind::Le | BinOpKind::Ge | BinOpKind::Lt | BinOpKind::Gt = op.node + && !in_external_macro(cx.sess(), expr.span) { let ty = cx.typeck_results().expr_ty(left); From 15eac5abd684a38df7643183ef2874432d960d9c Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 15 Jun 2024 17:32:04 -0400 Subject: [PATCH 080/734] Simplify `option_env_unwrap`. --- clippy_lints/src/option_env_unwrap.rs | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/clippy_lints/src/option_env_unwrap.rs b/clippy_lints/src/option_env_unwrap.rs index 4bfb26209d21..d16f5f8e112c 100644 --- a/clippy_lints/src/option_env_unwrap.rs +++ b/clippy_lints/src/option_env_unwrap.rs @@ -3,7 +3,7 @@ use clippy_utils::is_direct_expn_of; use rustc_ast::ast::{Expr, ExprKind, MethodCall}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -35,30 +35,18 @@ declare_lint_pass!(OptionEnvUnwrap => [OPTION_ENV_UNWRAP]); impl EarlyLintPass for OptionEnvUnwrap { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - fn lint(cx: &EarlyContext<'_>, span: Span) { + if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind + && matches!(seg.ident.name, sym::expect | sym::unwrap) + && is_direct_expn_of(receiver.span, "option_env").is_some() + { span_lint_and_help( cx, OPTION_ENV_UNWRAP, - span, + expr.span, "this will panic at run-time if the environment variable doesn't exist at compile-time", None, "consider using the `env!` macro instead", ); } - - if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind - && matches!(seg.ident.name, sym::expect | sym::unwrap) - { - if let ExprKind::Call(caller, _) = &receiver.kind && - // If it exists, it will be ::core::option::Option::Some("").unwrap() (A method call in the HIR) - is_direct_expn_of(caller.span, "option_env").is_some() - { - lint(cx, expr.span); - } else if let ExprKind::Path(_, caller) = &receiver.kind && // If it doesn't exist, it will be ::core::option::Option::None::<&'static str>.unwrap() (A path in the HIR) - is_direct_expn_of(caller.span, "option_env").is_some() - { - lint(cx, expr.span); - } - } } } From e12ff630fde5fb331b32cb2831fd164497df8f27 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 16 Jun 2024 01:41:56 -0400 Subject: [PATCH 081/734] `permissions_set_readonly_false`: Check HIR tree first. --- clippy_lints/src/permissions_set_readonly_false.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/permissions_set_readonly_false.rs b/clippy_lints/src/permissions_set_readonly_false.rs index 704acdc103e8..dc142b6e1577 100644 --- a/clippy_lints/src/permissions_set_readonly_false.rs +++ b/clippy_lints/src/permissions_set_readonly_false.rs @@ -31,10 +31,10 @@ declare_lint_pass!(PermissionsSetReadonlyFalse => [PERMISSIONS_SET_READONLY_FALS impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind - && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::FsPermissions) - && path.ident.name == sym!(set_readonly) && let ExprKind::Lit(lit) = &arg.kind && LitKind::Bool(false) == lit.node + && path.ident.name.as_str() == "set_readonly" + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::FsPermissions) { span_lint_and_then( cx, From 0c72a99cac2b8f53a77fe1acc1efef8559f19940 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 16 Jun 2024 15:42:28 -0400 Subject: [PATCH 082/734] `raw_strings` Check HIR tree first. --- clippy_lints/src/raw_strings.rs | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs index 3a0042454592..e66e2ee47cd0 100644 --- a/clippy_lints/src/raw_strings.rs +++ b/clippy_lints/src/raw_strings.rs @@ -2,7 +2,7 @@ use std::iter::once; use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet; +use clippy_utils::source::SpanRangeExt; use rustc_ast::ast::{Expr, ExprKind}; use rustc_ast::token::LitKind; use rustc_errors::Applicability; @@ -63,20 +63,17 @@ pub struct RawStrings { impl EarlyLintPass for RawStrings { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if !in_external_macro(cx.sess(), expr.span) - && let ExprKind::Lit(lit) = expr.kind - && let LitKind::StrRaw(max) | LitKind::ByteStrRaw(max) | LitKind::CStrRaw(max) = lit.kind + if let ExprKind::Lit(lit) = expr.kind + && let (prefix, max) = match lit.kind { + LitKind::StrRaw(max) => ("r", max), + LitKind::ByteStrRaw(max) => ("br", max), + LitKind::CStrRaw(max) => ("cr", max), + _ => return, + } + && !in_external_macro(cx.sess(), expr.span) + && expr.span.check_source_text(cx, |src| src.starts_with(prefix)) { let str = lit.symbol.as_str(); - let prefix = match lit.kind { - LitKind::StrRaw(..) => "r", - LitKind::ByteStrRaw(..) => "br", - LitKind::CStrRaw(..) => "cr", - _ => unreachable!(), - }; - if !snippet(cx, expr.span, prefix).trim().starts_with(prefix) { - return; - } let descr = lit.kind.descr(); if !str.contains(['\\', '"']) { @@ -86,7 +83,7 @@ impl EarlyLintPass for RawStrings { expr.span, "unnecessary raw string literal", |diag| { - let (start, end) = hash_spans(expr.span, prefix, 0, max); + let (start, end) = hash_spans(expr.span, prefix.len(), 0, max); // BytePos: skip over the `b` in `br`, we checked the prefix appears in the source text let r_pos = expr.span.lo() + BytePos::from_usize(prefix.len() - 1); @@ -148,7 +145,7 @@ impl EarlyLintPass for RawStrings { expr.span, "unnecessary hashes around raw string literal", |diag| { - let (start, end) = hash_spans(expr.span, prefix, req, max); + let (start, end) = hash_spans(expr.span, prefix.len(), req, max); let message = match max - req { _ if req == 0 => format!("remove all the hashes around the {descr} literal"), @@ -174,11 +171,11 @@ impl EarlyLintPass for RawStrings { /// r###".."### /// ^^ ^^ /// ``` -fn hash_spans(literal_span: Span, prefix: &str, req: u8, max: u8) -> (Span, Span) { +fn hash_spans(literal_span: Span, prefix_len: usize, req: u8, max: u8) -> (Span, Span) { let literal_span = literal_span.data(); // BytePos: we checked prefix appears literally in the source text - let hash_start = literal_span.lo + BytePos::from_usize(prefix.len()); + let hash_start = literal_span.lo + BytePos::from_usize(prefix_len); let hash_end = literal_span.hi; // BytePos: req/max are counts of the ASCII character # From 6519c143a7ae1494b38920cfb08a55793fbfe07d Mon Sep 17 00:00:00 2001 From: B I Mohammed Abbas Date: Mon, 8 Jul 2024 10:56:13 +0530 Subject: [PATCH 083/734] Reset sigpipe not supported for vxworks --- library/std/src/sys/pal/unix/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 16fc2011d708..d016e5e32d40 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -164,6 +164,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { target_os = "emscripten", target_os = "fuchsia", target_os = "horizon", + target_os = "vxworks", // Unikraft's `signal` implementation is currently broken: // https://github.com/unikraft/lib-musl/issues/57 target_vendor = "unikraft", From cf9e7a975d4a64ad60669a9764e64400710c7e67 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 14 Jun 2024 11:10:29 -0400 Subject: [PATCH 084/734] rewrite std-core-cycle to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/std-core-cycle/Makefile | 17 ----------- tests/run-make/std-core-cycle/rmake.rs | 28 +++++++++++++++++++ 3 files changed, 28 insertions(+), 18 deletions(-) delete mode 100644 tests/run-make/std-core-cycle/Makefile create mode 100644 tests/run-make/std-core-cycle/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 31cb32d349ac..c527161aa9a0 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -142,7 +142,6 @@ run-make/static-dylib-by-default/Makefile run-make/static-extern-type/Makefile run-make/staticlib-blank-lib/Makefile run-make/staticlib-dylib-linkage/Makefile -run-make/std-core-cycle/Makefile run-make/symbol-mangling-hashed/Makefile run-make/symbol-visibility/Makefile run-make/symbols-include-type-name/Makefile diff --git a/tests/run-make/std-core-cycle/Makefile b/tests/run-make/std-core-cycle/Makefile deleted file mode 100644 index 5ed6be905dff..000000000000 --- a/tests/run-make/std-core-cycle/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -ifeq ($(UNAME),Darwin) -FLAGS := -else -ifdef IS_WINDOWS -FLAGS := -else -FLAGS := -C link-args=-Wl,--no-undefined -endif -endif - -all: - $(RUSTC) bar.rs - $(RUSTC) foo.rs $(FLAGS) - $(RUSTC) foo.rs $(FLAGS) -C panic=abort diff --git a/tests/run-make/std-core-cycle/rmake.rs b/tests/run-make/std-core-cycle/rmake.rs new file mode 100644 index 000000000000..0f63c3f7ce47 --- /dev/null +++ b/tests/run-make/std-core-cycle/rmake.rs @@ -0,0 +1,28 @@ +// In some cases, linking libraries with GNU used to fail due to how +// `std` and `core` possess a circular dependency with one another, and +// how the linker could not go back through its symbol processing to resolve +// the circular link. #49316 fixed this, and this test reproduces a minimal +// version of one such linking attempt which used to fail. +// See https://github.com/rust-lang/rust/issues/18807 + +//@ ignore-cross-compile + +use run_make_support::{is_darwin, is_windows, rustc}; + +fn main() { + rustc().input("bar.rs").run(); + + let mut rustc_foo = rustc(); + rustc_foo.input("foo.rs"); + let mut rustc_foo_panic = rustc(); + rustc_foo_panic.input("foo.rs").panic("abort"); + + if !is_darwin() && !is_windows() { + rustc_foo.arg("-Clink-args=-Wl,--no-undefined"); + rustc_foo_panic.arg("-Clink-args=-Wl,--no-undefined"); + } + + rustc_foo.run(); + rustc_foo_panic.run(); +} + From 2c7afc114d7ccc9bbc1dce29f1be1dca343e722f Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 14 Jun 2024 11:41:54 -0400 Subject: [PATCH 085/734] rewrite obey-crate-type-flag to rmake --- src/tools/run-make-support/src/lib.rs | 37 +++++++++++++++++++ .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/obey-crate-type-flag/Makefile | 14 ------- tests/run-make/obey-crate-type-flag/rmake.rs | 16 ++++++++ 4 files changed, 53 insertions(+), 15 deletions(-) delete mode 100644 tests/run-make/obey-crate-type-flag/Makefile create mode 100644 tests/run-make/obey-crate-type-flag/rmake.rs diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index f464a109e771..721200f77f3a 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -23,6 +23,7 @@ use std::path::{Path, PathBuf}; pub use bstr; pub use gimli; +pub use glob; pub use object; pub use regex; pub use wasmparser; @@ -223,6 +224,42 @@ pub fn bin_name(name: &str) -> String { if is_windows() { format!("{name}.exe") } else { name.to_string() } } +/// Remove all dynamic libraries possessing a name starting with `paths`. +#[track_caller] +pub fn remove_dylibs(paths: &str) { + let paths = format!(r"{paths}*"); + remove_glob(dynamic_lib_name(&paths).as_str()); +} + +/// Remove all rust libraries possessing a name starting with `paths`. +#[track_caller] +pub fn remove_rlibs(paths: &str) { + let paths = format!(r"{paths}*"); + remove_glob(rust_lib_name(&paths).as_str()); +} + +#[track_caller] +fn remove_glob(paths: &str) { + let paths = glob::glob(paths).expect(format!("Glob expression {paths} is not valid.").as_str()); + paths + .filter_map(|entry| entry.ok()) + .filter(|entry| entry.as_path().is_file()) + .for_each(|file| fs_wrapper::remove_file(&file)); +} + +#[track_caller] +fn count_glob(paths: &str) -> usize { + let paths = glob::glob(paths).expect(format!("Glob expression {paths} is not valid.").as_str()); + paths.filter_map(|entry| entry.ok()).filter(|entry| entry.as_path().is_file()).count() +} + +/// Count the number of rust libraries possessing a name starting with `paths`. +#[track_caller] +pub fn count_rlibs(paths: &str) -> usize { + let paths = format!(r"{paths}*"); + count_glob(rust_lib_name(&paths).as_str()) +} + /// Return the current working directory. #[must_use] pub fn cwd() -> PathBuf { diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index c527161aa9a0..8dc48d42f67f 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -97,7 +97,6 @@ run-make/native-link-modifier-whole-archive/Makefile run-make/no-alloc-shim/Makefile run-make/no-builtins-attribute/Makefile run-make/no-duplicate-libs/Makefile -run-make/obey-crate-type-flag/Makefile run-make/panic-abort-eh_frame/Makefile run-make/pass-linker-flags-flavor/Makefile run-make/pass-linker-flags-from-dep/Makefile diff --git a/tests/run-make/obey-crate-type-flag/Makefile b/tests/run-make/obey-crate-type-flag/Makefile deleted file mode 100644 index ecbb2e620ed3..000000000000 --- a/tests/run-make/obey-crate-type-flag/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# check that rustc builds all crate_type attributes -# delete rlib -# delete whatever dylib is made for this system -# check that rustc only builds --crate-type flags, ignoring attributes -# fail if an rlib was built -all: - $(RUSTC) test.rs - $(call REMOVE_RLIBS,test) - $(call REMOVE_DYLIBS,test) - $(RUSTC) --crate-type dylib test.rs - $(call REMOVE_RLIBS,test) && exit 1 || exit 0 diff --git a/tests/run-make/obey-crate-type-flag/rmake.rs b/tests/run-make/obey-crate-type-flag/rmake.rs new file mode 100644 index 000000000000..4ae4b6e4eec0 --- /dev/null +++ b/tests/run-make/obey-crate-type-flag/rmake.rs @@ -0,0 +1,16 @@ +// test.rs should produce both an rlib and a dylib +// by default. When the crate_type flag is passed and +// forced to dylib, no rlibs should be produced. +// See https://github.com/rust-lang/rust/issues/11573 + +//@ ignore-cross-compile + +use run_make_support::{count_rlibs, remove_dylibs, remove_rlibs, rustc}; + +fn main() { + rustc().input("test.rs").run(); + remove_rlibs("test"); + remove_dylibs("test"); + rustc().crate_type("dylib").input("test.rs").run(); + assert_eq!(count_rlibs("test"), 0); +} From d9162fd97f1655a145b7975b8e7af7e37f4de84d Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 14 Jun 2024 12:08:43 -0400 Subject: [PATCH 086/734] rewrite and rename issue-18943 to rmake --- src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/issue-18943/Makefile | 7 ------- .../foo.rs | 0 tests/run-make/lib-trait-for-trait-no-ice/rmake.rs | 13 +++++++++++++ tests/run-make/std-core-cycle/rmake.rs | 1 - 5 files changed, 13 insertions(+), 9 deletions(-) delete mode 100644 tests/run-make/issue-18943/Makefile rename tests/run-make/{issue-18943 => lib-trait-for-trait-no-ice}/foo.rs (100%) create mode 100644 tests/run-make/lib-trait-for-trait-no-ice/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 8dc48d42f67f..23b3b91604dc 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -52,7 +52,6 @@ run-make/issue-107094/Makefile run-make/issue-109934-lto-debuginfo/Makefile run-make/issue-14698/Makefile run-make/issue-15460/Makefile -run-make/issue-18943/Makefile run-make/issue-22131/Makefile run-make/issue-25581/Makefile run-make/issue-26006/Makefile diff --git a/tests/run-make/issue-18943/Makefile b/tests/run-make/issue-18943/Makefile deleted file mode 100644 index fc40d756d6f2..000000000000 --- a/tests/run-make/issue-18943/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -# Regression test for ICE #18943 when compiling as lib - -all: - $(RUSTC) foo.rs --crate-type lib - $(call REMOVE_RLIBS,foo) && exit 0 || exit 1 diff --git a/tests/run-make/issue-18943/foo.rs b/tests/run-make/lib-trait-for-trait-no-ice/foo.rs similarity index 100% rename from tests/run-make/issue-18943/foo.rs rename to tests/run-make/lib-trait-for-trait-no-ice/foo.rs diff --git a/tests/run-make/lib-trait-for-trait-no-ice/rmake.rs b/tests/run-make/lib-trait-for-trait-no-ice/rmake.rs new file mode 100644 index 000000000000..5f8c998874b6 --- /dev/null +++ b/tests/run-make/lib-trait-for-trait-no-ice/rmake.rs @@ -0,0 +1,13 @@ +// Inside a library, implementing a trait for another trait +// with a lifetime used to cause an internal compiler error (ICE). +// This test checks that this bug does not make a resurgence - +// first by ensuring successful compilation, then verifying that +// the lib crate-type flag was actually followed. +// See https://github.com/rust-lang/rust/issues/18943 + +use run_make_support::{count_rlibs, rustc}; + +fn main() { + rustc().input("foo.rs").crate_type("lib").run(); + assert_eq!(count_rlibs("foo"), 1); +} diff --git a/tests/run-make/std-core-cycle/rmake.rs b/tests/run-make/std-core-cycle/rmake.rs index 0f63c3f7ce47..162b783aeb98 100644 --- a/tests/run-make/std-core-cycle/rmake.rs +++ b/tests/run-make/std-core-cycle/rmake.rs @@ -25,4 +25,3 @@ fn main() { rustc_foo.run(); rustc_foo_panic.run(); } - From ece7d98c0ea5b639c59331ef6b2c890c637ef862 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 14 Jun 2024 13:22:51 -0400 Subject: [PATCH 087/734] rewrite mixing-libs to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/mixing-libs/Makefile | 8 ------- tests/run-make/mixing-libs/rmake.rs | 21 +++++++++++++++++++ 3 files changed, 21 insertions(+), 9 deletions(-) delete mode 100644 tests/run-make/mixing-libs/Makefile create mode 100644 tests/run-make/mixing-libs/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 23b3b91604dc..6c67155b55cf 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -90,7 +90,6 @@ run-make/manual-link/Makefile run-make/metadata-dep-info/Makefile run-make/min-global-align/Makefile run-make/missing-crate-dependency/Makefile -run-make/mixing-libs/Makefile run-make/native-link-modifier-bundle/Makefile run-make/native-link-modifier-whole-archive/Makefile run-make/no-alloc-shim/Makefile diff --git a/tests/run-make/mixing-libs/Makefile b/tests/run-make/mixing-libs/Makefile deleted file mode 100644 index 459db0dfdb2f..000000000000 --- a/tests/run-make/mixing-libs/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) rlib.rs --crate-type=rlib --crate-type=dylib - $(RUSTC) dylib.rs # no -Cprefer-dynamic so statically linking librlib.rlib - $(call REMOVE_DYLIBS,rlib) # remove librlib.so to test that prog.rs doesn't get confused about the removed dylib version of librlib - $(RUSTC) prog.rs && exit 1 || exit 0 diff --git a/tests/run-make/mixing-libs/rmake.rs b/tests/run-make/mixing-libs/rmake.rs new file mode 100644 index 000000000000..d46a2403c25b --- /dev/null +++ b/tests/run-make/mixing-libs/rmake.rs @@ -0,0 +1,21 @@ +// Having multiple upstream crates available in different formats +// should result in failed compilation. This test causes multiple +// libraries to exist simultaneously as rust libs and dynamic libs, +// causing prog.rs to fail compilation. +// See https://github.com/rust-lang/rust/issues/10434 + +//@ ignore-cross-compile + +use run_make_support::{remove_dylibs, rustc}; + +fn main() { + rustc().input("rlib.rs").crate_type("rlib").crate_type("dylib").run(); + + // Not putting `-C prefer-dynamic` here allows for static linking of librlib.rlib. + rustc().input("dylib.rs").run(); + + // librlib's dynamic version needs to be removed here to prevent prog.rs from fetching + // the wrong one. + remove_dylibs("rlib"); + rustc().input("prog.rs").run_fail(); +} From cbc62cb38fb0982ba1db9f91149a241792002024 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Mon, 17 Jun 2024 13:23:53 -0400 Subject: [PATCH 088/734] shallow_find_files function for run_make_support --- src/tools/run-make-support/src/lib.rs | 37 ------------------- .../lib-trait-for-trait-no-ice/rmake.rs | 5 ++- tests/run-make/mixing-libs/rmake.rs | 4 +- tests/run-make/obey-crate-type-flag/rmake.rs | 13 +++++-- 4 files changed, 14 insertions(+), 45 deletions(-) diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 721200f77f3a..f464a109e771 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -23,7 +23,6 @@ use std::path::{Path, PathBuf}; pub use bstr; pub use gimli; -pub use glob; pub use object; pub use regex; pub use wasmparser; @@ -224,42 +223,6 @@ pub fn bin_name(name: &str) -> String { if is_windows() { format!("{name}.exe") } else { name.to_string() } } -/// Remove all dynamic libraries possessing a name starting with `paths`. -#[track_caller] -pub fn remove_dylibs(paths: &str) { - let paths = format!(r"{paths}*"); - remove_glob(dynamic_lib_name(&paths).as_str()); -} - -/// Remove all rust libraries possessing a name starting with `paths`. -#[track_caller] -pub fn remove_rlibs(paths: &str) { - let paths = format!(r"{paths}*"); - remove_glob(rust_lib_name(&paths).as_str()); -} - -#[track_caller] -fn remove_glob(paths: &str) { - let paths = glob::glob(paths).expect(format!("Glob expression {paths} is not valid.").as_str()); - paths - .filter_map(|entry| entry.ok()) - .filter(|entry| entry.as_path().is_file()) - .for_each(|file| fs_wrapper::remove_file(&file)); -} - -#[track_caller] -fn count_glob(paths: &str) -> usize { - let paths = glob::glob(paths).expect(format!("Glob expression {paths} is not valid.").as_str()); - paths.filter_map(|entry| entry.ok()).filter(|entry| entry.as_path().is_file()).count() -} - -/// Count the number of rust libraries possessing a name starting with `paths`. -#[track_caller] -pub fn count_rlibs(paths: &str) -> usize { - let paths = format!(r"{paths}*"); - count_glob(rust_lib_name(&paths).as_str()) -} - /// Return the current working directory. #[must_use] pub fn cwd() -> PathBuf { diff --git a/tests/run-make/lib-trait-for-trait-no-ice/rmake.rs b/tests/run-make/lib-trait-for-trait-no-ice/rmake.rs index 5f8c998874b6..766acfc00da5 100644 --- a/tests/run-make/lib-trait-for-trait-no-ice/rmake.rs +++ b/tests/run-make/lib-trait-for-trait-no-ice/rmake.rs @@ -5,9 +5,10 @@ // the lib crate-type flag was actually followed. // See https://github.com/rust-lang/rust/issues/18943 -use run_make_support::{count_rlibs, rustc}; +use run_make_support::{rust_lib_name, rustc}; +use std::path::Path; fn main() { rustc().input("foo.rs").crate_type("lib").run(); - assert_eq!(count_rlibs("foo"), 1); + assert!(Path::new(&rust_lib_name("foo")).exists()); } diff --git a/tests/run-make/mixing-libs/rmake.rs b/tests/run-make/mixing-libs/rmake.rs index d46a2403c25b..06ef6ab00f5f 100644 --- a/tests/run-make/mixing-libs/rmake.rs +++ b/tests/run-make/mixing-libs/rmake.rs @@ -6,7 +6,7 @@ //@ ignore-cross-compile -use run_make_support::{remove_dylibs, rustc}; +use run_make_support::{dynamic_lib_name, fs_wrapper, rustc}; fn main() { rustc().input("rlib.rs").crate_type("rlib").crate_type("dylib").run(); @@ -16,6 +16,6 @@ fn main() { // librlib's dynamic version needs to be removed here to prevent prog.rs from fetching // the wrong one. - remove_dylibs("rlib"); + fs_wrapper::remove_file(dynamic_lib_name("rlib")); rustc().input("prog.rs").run_fail(); } diff --git a/tests/run-make/obey-crate-type-flag/rmake.rs b/tests/run-make/obey-crate-type-flag/rmake.rs index 4ae4b6e4eec0..8aa78cccbb23 100644 --- a/tests/run-make/obey-crate-type-flag/rmake.rs +++ b/tests/run-make/obey-crate-type-flag/rmake.rs @@ -5,12 +5,17 @@ //@ ignore-cross-compile -use run_make_support::{count_rlibs, remove_dylibs, remove_rlibs, rustc}; +use run_make_support::{ + cwd, dynamic_lib_name, fs_wrapper, has_extension, rust_lib_name, rustc, shallow_find_files, +}; +use std::path::Path; fn main() { rustc().input("test.rs").run(); - remove_rlibs("test"); - remove_dylibs("test"); + assert!(Path::new(&dynamic_lib_name("test")).exists()); + assert!(Path::new(&rust_lib_name("test")).exists()); + + fs_wrapper::remove_file(rust_lib_name("test")); rustc().crate_type("dylib").input("test.rs").run(); - assert_eq!(count_rlibs("test"), 0); + assert!(shallow_find_files(cwd(), |path| { has_extension(path, "rlib") }).is_empty()); } From 5e2cc5793a9cf7cdbb4758ce18470dbdefd8491c Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Tue, 9 Jul 2024 10:40:26 +0100 Subject: [PATCH 089/734] Terminate `--print link-args` output with newline --- compiler/rustc_codegen_ssa/src/back/link.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 1f627353d54e..8e07d128dbd6 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -750,7 +750,7 @@ fn link_natively( for print in &sess.opts.prints { if print.kind == PrintKind::LinkArgs { - let content = format!("{cmd:?}"); + let content = format!("{cmd:?}\n"); print.out.overwrite(&content, sess); } } From 296dcf09fb7e744c8f7b118e2e328dbc1fd6a7a5 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 19 Apr 2024 09:26:52 +0100 Subject: [PATCH 090/734] unnecessary_struct_initialization: extend to assignments moving all fields This lint makes Clippy warn about situations where an owned struct is essentially recreated by moving all its fields into a new instance of the struct. Until now this lint only triggered for structs recreated from a base struct. NB: The new functionality too will cause false positives for the situation where a non-copy struct consisting of all copy members is touched again in subsequent code. --- .../src/unnecessary_struct_initialization.rs | 189 ++++++++++++++---- .../unnecessary_struct_initialization.fixed | 70 +++++++ tests/ui/unnecessary_struct_initialization.rs | 70 +++++++ .../unnecessary_struct_initialization.stderr | 44 +++- 4 files changed, 329 insertions(+), 44 deletions(-) diff --git a/clippy_lints/src/unnecessary_struct_initialization.rs b/clippy_lints/src/unnecessary_struct_initialization.rs index 2da753343448..afdd3505cdd1 100644 --- a/clippy_lints/src/unnecessary_struct_initialization.rs +++ b/clippy_lints/src/unnecessary_struct_initialization.rs @@ -2,14 +2,15 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_copy; use clippy_utils::{get_parent_expr, path_to_local}; -use rustc_hir::{BindingMode, Expr, ExprKind, Node, PatKind, UnOp}; +use rustc_hir::{BindingMode, Expr, ExprField, ExprKind, Node, PatKind, Path, QPath, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks for initialization of a `struct` by copying a base without setting - /// any field. + /// Checks for initialization of an identical `struct` from another instance + /// of the type, either by copying a base without setting any field or by + /// moving all fields individually. /// /// ### Why is this bad? /// Readability suffers from unnecessary struct building. @@ -29,9 +30,14 @@ declare_clippy_lint! { /// let b = a; /// ``` /// + /// The struct literal ``S { ..a }`` in the assignment to ``b`` could be replaced + /// with just ``a``. + /// /// ### Known Problems /// Has false positives when the base is a place expression that cannot be /// moved out of, see [#10547](https://github.com/rust-lang/rust-clippy/issues/10547). + /// + /// Empty structs are ignored by the lint. #[clippy::version = "1.70.0"] pub UNNECESSARY_STRUCT_INITIALIZATION, nursery, @@ -41,42 +47,111 @@ declare_lint_pass!(UnnecessaryStruct => [UNNECESSARY_STRUCT_INITIALIZATION]); impl LateLintPass<'_> for UnnecessaryStruct { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::Struct(_, &[], Some(base)) = expr.kind { - if let Some(parent) = get_parent_expr(cx, expr) - && let parent_ty = cx.typeck_results().expr_ty_adjusted(parent) - && parent_ty.is_any_ptr() - { - if is_copy(cx, cx.typeck_results().expr_ty(expr)) && path_to_local(base).is_some() { - // When the type implements `Copy`, a reference to the new struct works on the - // copy. Using the original would borrow it. - return; - } + let ExprKind::Struct(_, fields, base) = expr.kind else { + return; + }; - if parent_ty.is_mutable_ptr() && !is_mutable(cx, base) { - // The original can be used in a mutable reference context only if it is mutable. - return; - } - } - - // TODO: do not propose to replace *XX if XX is not Copy - if let ExprKind::Unary(UnOp::Deref, target) = base.kind - && matches!(target.kind, ExprKind::Path(..)) - && !is_copy(cx, cx.typeck_results().expr_ty(expr)) - { - // `*base` cannot be used instead of the struct in the general case if it is not Copy. - return; - } - - span_lint_and_sugg( - cx, - UNNECESSARY_STRUCT_INITIALIZATION, - expr.span, - "unnecessary struct building", - "replace with", - snippet(cx, base.span, "..").into_owned(), - rustc_errors::Applicability::MachineApplicable, - ); + if expr.span.from_expansion() { + // Prevent lint from hitting inside macro code + return; } + + let field_path = same_path_in_all_fields(cx, expr, fields); + + let sugg = match (field_path, base) { + (Some(&path), None) => { + // all fields match, no base given + path.span + }, + (Some(path), Some(base)) if base_is_suitable(cx, expr, base) && path_matches_base(path, base) => { + // all fields match, has base: ensure that the path of the base matches + base.span + }, + (None, Some(base)) if fields.is_empty() && base_is_suitable(cx, expr, base) => { + // just the base, no explicit fields + base.span + }, + _ => return, + }; + + span_lint_and_sugg( + cx, + UNNECESSARY_STRUCT_INITIALIZATION, + expr.span, + "unnecessary struct building", + "replace with", + snippet(cx, sugg, "..").into_owned(), + rustc_errors::Applicability::MachineApplicable, + ); + } +} + +fn base_is_suitable(cx: &LateContext<'_>, expr: &Expr<'_>, base: &Expr<'_>) -> bool { + if !check_references(cx, expr, base) { + return false; + } + + // TODO: do not propose to replace *XX if XX is not Copy + if let ExprKind::Unary(UnOp::Deref, target) = base.kind + && matches!(target.kind, ExprKind::Path(..)) + && !is_copy(cx, cx.typeck_results().expr_ty(expr)) + { + // `*base` cannot be used instead of the struct in the general case if it is not Copy. + return false; + } + true +} + +/// Check whether all fields of a struct assignment match. +/// Returns a [Path] item that one can obtain a span from for the lint suggestion. +/// +/// Conditions that must be satisfied to trigger this variant of the lint: +/// +/// - source struct of the assignment must be of same type as the destination +/// - names of destination struct fields must match the field names of the source +/// +/// We don’t check here if all struct fields are assigned as the remainder may +/// be filled in from a base struct. +fn same_path_in_all_fields<'tcx>( + cx: &LateContext<'_>, + expr: &Expr<'_>, + fields: &[ExprField<'tcx>], +) -> Option<&'tcx Path<'tcx>> { + let ty = cx.typeck_results().expr_ty(expr); + + let mut found = None; + + for f in fields { + // fields are assigned from expression + if let ExprKind::Field(src_expr, ident) = f.expr.kind + // expression type matches + && ty == cx.typeck_results().expr_ty(src_expr) + // field name matches + && f.ident == ident + // assigned from a path expression + && let ExprKind::Path(QPath::Resolved(None, src_path)) = src_expr.kind + { + let Some((_, p)) = found else { + // this is the first field assignment in the list + found = Some((src_expr, src_path)); + continue; + }; + + if p.res == src_path.res { + // subsequent field assignment with same origin struct as before + continue; + } + } + // source of field assignment doesn’t qualify + return None; + } + + if let Some((src_expr, src_path)) = found + && check_references(cx, expr, src_expr) + { + Some(src_path) + } else { + None } } @@ -89,3 +164,43 @@ fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { true } } + +fn check_references(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool { + if let Some(parent) = get_parent_expr(cx, expr_a) + && let parent_ty = cx.typeck_results().expr_ty_adjusted(parent) + && parent_ty.is_any_ptr() + { + if is_copy(cx, cx.typeck_results().expr_ty(expr_a)) && path_to_local(expr_b).is_some() { + // When the type implements `Copy`, a reference to the new struct works on the + // copy. Using the original would borrow it. + return false; + } + + if parent_ty.is_mutable_ptr() && !is_mutable(cx, expr_b) { + // The original can be used in a mutable reference context only if it is mutable. + return false; + } + } + + true +} + +/// When some fields are assigned from a base struct and others individually +/// the lint applies only if the source of the field is the same as the base. +/// This is enforced here by comparing the path of the base expression; +/// needless to say the lint only applies if it (or whatever expression it is +/// a reference of) actually has a path. +fn path_matches_base(path: &Path<'_>, base: &Expr<'_>) -> bool { + let base_path = match base.kind { + ExprKind::Unary(UnOp::Deref, base_expr) => { + if let ExprKind::Path(QPath::Resolved(_, base_path)) = base_expr.kind { + base_path + } else { + return false; + } + }, + ExprKind::Path(QPath::Resolved(_, base_path)) => base_path, + _ => return false, + }; + path.res == base_path.res +} diff --git a/tests/ui/unnecessary_struct_initialization.fixed b/tests/ui/unnecessary_struct_initialization.fixed index f3cf65da2d6a..b0e8f4546353 100644 --- a/tests/ui/unnecessary_struct_initialization.fixed +++ b/tests/ui/unnecessary_struct_initialization.fixed @@ -26,6 +26,11 @@ struct V { f: u32, } +struct W { + f1: u32, + f2: u32, +} + impl Clone for V { fn clone(&self) -> Self { // Lint: `Self` implements `Copy` @@ -68,4 +73,69 @@ fn main() { // Should lint: the result of an expression is mutable and temporary let p = &mut *Box::new(T { f: 5 }); + + // Should lint: all fields of `q` would be consumed anyway + let q = W { f1: 42, f2: 1337 }; + let r = q; + + // Should not lint: not all fields of `t` from same source + let s = W { f1: 1337, f2: 42 }; + let t = W { f1: s.f1, f2: r.f2 }; + + // Should not lint: different fields of `s` assigned + let u = W { f1: s.f2, f2: s.f1 }; + + // Should lint: all fields of `v` would be consumed anyway + let v = W { f1: 42, f2: 1337 }; + let w = v; + + // Should not lint: source differs between fields and base + let x = W { f1: 42, f2: 1337 }; + let y = W { f1: w.f1, ..x }; + + // Should lint: range desugars to struct + let r1 = 0..5; + let r2 = r1; + + references(); + shorthand(); +} + +fn references() { + // Should not lint as `a` is not mutable + let a = W { f1: 42, f2: 1337 }; + let b = &mut W { f1: a.f1, f2: a.f2 }; + + // Should lint as `d` is a shared reference + let c = W { f1: 42, f2: 1337 }; + let d = &c; + + // Should not lint as `e` is not mutable + let e = W { f1: 42, f2: 1337 }; + let f = &mut W { f1: e.f1, ..e }; + + // Should lint as `h` is a shared reference + let g = W { f1: 42, f2: 1337 }; + let h = &g; + + // Should not lint as `j` is copy + let i = V { f: 0x1701d }; + let j = &V { ..i }; + + // Should not lint as `k` is copy + let k = V { f: 0x1701d }; + let l = &V { f: k.f }; +} + +fn shorthand() { + struct S1 { + a: i32, + b: i32, + } + + let a = 42; + let s = S1 { a: 3, b: 4 }; + + // Should not lint: `a` is not from `s` + let s = S1 { a, b: s.b }; } diff --git a/tests/ui/unnecessary_struct_initialization.rs b/tests/ui/unnecessary_struct_initialization.rs index bd5302f9d85d..b0db71af4d4c 100644 --- a/tests/ui/unnecessary_struct_initialization.rs +++ b/tests/ui/unnecessary_struct_initialization.rs @@ -26,6 +26,11 @@ struct V { f: u32, } +struct W { + f1: u32, + f2: u32, +} + impl Clone for V { fn clone(&self) -> Self { // Lint: `Self` implements `Copy` @@ -72,4 +77,69 @@ fn main() { let p = &mut T { ..*Box::new(T { f: 5 }) }; + + // Should lint: all fields of `q` would be consumed anyway + let q = W { f1: 42, f2: 1337 }; + let r = W { f1: q.f1, f2: q.f2 }; + + // Should not lint: not all fields of `t` from same source + let s = W { f1: 1337, f2: 42 }; + let t = W { f1: s.f1, f2: r.f2 }; + + // Should not lint: different fields of `s` assigned + let u = W { f1: s.f2, f2: s.f1 }; + + // Should lint: all fields of `v` would be consumed anyway + let v = W { f1: 42, f2: 1337 }; + let w = W { f1: v.f1, ..v }; + + // Should not lint: source differs between fields and base + let x = W { f1: 42, f2: 1337 }; + let y = W { f1: w.f1, ..x }; + + // Should lint: range desugars to struct + let r1 = 0..5; + let r2 = r1.start..r1.end; + + references(); + shorthand(); +} + +fn references() { + // Should not lint as `a` is not mutable + let a = W { f1: 42, f2: 1337 }; + let b = &mut W { f1: a.f1, f2: a.f2 }; + + // Should lint as `d` is a shared reference + let c = W { f1: 42, f2: 1337 }; + let d = &W { f1: c.f1, f2: c.f2 }; + + // Should not lint as `e` is not mutable + let e = W { f1: 42, f2: 1337 }; + let f = &mut W { f1: e.f1, ..e }; + + // Should lint as `h` is a shared reference + let g = W { f1: 42, f2: 1337 }; + let h = &W { f1: g.f1, ..g }; + + // Should not lint as `j` is copy + let i = V { f: 0x1701d }; + let j = &V { ..i }; + + // Should not lint as `k` is copy + let k = V { f: 0x1701d }; + let l = &V { f: k.f }; +} + +fn shorthand() { + struct S1 { + a: i32, + b: i32, + } + + let a = 42; + let s = S1 { a: 3, b: 4 }; + + // Should not lint: `a` is not from `s` + let s = S1 { a, b: s.b }; } diff --git a/tests/ui/unnecessary_struct_initialization.stderr b/tests/ui/unnecessary_struct_initialization.stderr index 8bc308c7567b..56982cc0a39f 100644 --- a/tests/ui/unnecessary_struct_initialization.stderr +++ b/tests/ui/unnecessary_struct_initialization.stderr @@ -1,5 +1,5 @@ error: unnecessary struct building - --> tests/ui/unnecessary_struct_initialization.rs:32:9 + --> tests/ui/unnecessary_struct_initialization.rs:37:9 | LL | Self { ..*self } | ^^^^^^^^^^^^^^^^ help: replace with: `*self` @@ -8,25 +8,25 @@ LL | Self { ..*self } = help: to override `-D warnings` add `#[allow(clippy::unnecessary_struct_initialization)]` error: unnecessary struct building - --> tests/ui/unnecessary_struct_initialization.rs:39:17 + --> tests/ui/unnecessary_struct_initialization.rs:44:17 | LL | let mut b = S { ..a }; | ^^^^^^^^^ help: replace with: `a` error: unnecessary struct building - --> tests/ui/unnecessary_struct_initialization.rs:42:18 + --> tests/ui/unnecessary_struct_initialization.rs:47:18 | LL | let c = &mut S { ..b }; | ^^^^^^^^^ help: replace with: `b` error: unnecessary struct building - --> tests/ui/unnecessary_struct_initialization.rs:50:14 + --> tests/ui/unnecessary_struct_initialization.rs:55:14 | LL | let g = &S { ..f }; | ^^^^^^^^^ help: replace with: `f` error: unnecessary struct building - --> tests/ui/unnecessary_struct_initialization.rs:53:18 + --> tests/ui/unnecessary_struct_initialization.rs:58:18 | LL | let h = &mut S { | __________________^ @@ -35,7 +35,7 @@ LL | | }; | |_____^ help: replace with: `*Box::new(S { f: String::from("foo") })` error: unnecessary struct building - --> tests/ui/unnecessary_struct_initialization.rs:72:18 + --> tests/ui/unnecessary_struct_initialization.rs:77:18 | LL | let p = &mut T { | __________________^ @@ -43,5 +43,35 @@ LL | | ..*Box::new(T { f: 5 }) LL | | }; | |_____^ help: replace with: `*Box::new(T { f: 5 })` -error: aborting due to 6 previous errors +error: unnecessary struct building + --> tests/ui/unnecessary_struct_initialization.rs:83:13 + | +LL | let r = W { f1: q.f1, f2: q.f2 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `q` + +error: unnecessary struct building + --> tests/ui/unnecessary_struct_initialization.rs:94:13 + | +LL | let w = W { f1: v.f1, ..v }; + | ^^^^^^^^^^^^^^^^^^^ help: replace with: `v` + +error: unnecessary struct building + --> tests/ui/unnecessary_struct_initialization.rs:102:14 + | +LL | let r2 = r1.start..r1.end; + | ^^^^^^^^^^^^^^^^ help: replace with: `r1` + +error: unnecessary struct building + --> tests/ui/unnecessary_struct_initialization.rs:115:14 + | +LL | let d = &W { f1: c.f1, f2: c.f2 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `c` + +error: unnecessary struct building + --> tests/ui/unnecessary_struct_initialization.rs:123:14 + | +LL | let h = &W { f1: g.f1, ..g }; + | ^^^^^^^^^^^^^^^^^^^ help: replace with: `g` + +error: aborting due to 11 previous errors From 2a3e22bf04b41c6116cb1e29ab7d8daeed8e63db Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 24 Jun 2024 12:30:44 -0700 Subject: [PATCH 091/734] Promote the `wasm32-wasip2` target to Tier 2 This commit promotes the `wasm32-wasip2` Rust target to tier 2 as proposed in rust-lang/compiler-team#760. There are two major changes in this PR: 1. The `dist-various-2` container, which already produces the other WASI targets, now has an extra target added for `wasm32-wasip2`. 2. A new `wasm-component-ld` binary is added to all host toolchains when LLD is enabled. This is the linker used for the `wasm32-wasip2` target. This new linker is added for all host toolchains to ensure that all host toolchains can produce the `wasm32-wasip2` target. This is similar to how `rust-lld` was originally included for all host toolchains to be able to produce WebAssembly output when the targets were first added. The new linker is developed [here][wasm-component-ld] and is pulled in via a crates.io-based dependency to the tree here. [wasm-component-ld]: https://github.com/bytecodealliance/wasm-component-ld --- Cargo.lock | 157 +++++++++++++++++- Cargo.toml | 4 + src/bootstrap/src/core/build_steps/compile.rs | 15 ++ src/bootstrap/src/core/build_steps/tool.rs | 28 ++++ .../host-x86_64/dist-various-2/Dockerfile | 1 + src/tools/tidy/src/deps.rs | 5 + src/tools/wasm-component-ld/Cargo.toml | 13 ++ src/tools/wasm-component-ld/README.md | 62 +++++++ src/tools/wasm-component-ld/src/main.rs | 9 + 9 files changed, 291 insertions(+), 3 deletions(-) create mode 100644 src/tools/wasm-component-ld/Cargo.toml create mode 100644 src/tools/wasm-component-ld/README.md create mode 100644 src/tools/wasm-component-ld/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index afeb9faec097..f426c0e37040 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1671,6 +1671,7 @@ dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", + "serde", ] [[package]] @@ -1880,6 +1881,12 @@ dependencies = [ "syn 2.0.67", ] +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + [[package]] name = "ident_case" version = "1.0.1" @@ -2109,6 +2116,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" +[[package]] +name = "lexopt" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baff4b617f7df3d896f97fe922b64817f6cd9a756bb81d40f8883f2f66dcb401" + [[package]] name = "libc" version = "0.2.155" @@ -2623,7 +2636,7 @@ dependencies = [ "indexmap", "memchr", "ruzstd 0.5.0", - "wasmparser", + "wasmparser 0.118.2", ] [[package]] @@ -3424,7 +3437,7 @@ dependencies = [ "object 0.34.0", "regex", "similar", - "wasmparser", + "wasmparser 0.118.2", ] [[package]] @@ -3805,7 +3818,7 @@ dependencies = [ "thin-vec", "thorin-dwp", "tracing", - "wasm-encoder", + "wasm-encoder 0.200.0", "windows", ] @@ -5248,6 +5261,15 @@ dependencies = [ "color-eyre", ] +[[package]] +name = "spdx" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47317bbaf63785b53861e1ae2d11b80d6b624211d42cb20efcd210ee6f8a14bc" +dependencies = [ + "smallvec", +] + [[package]] name = "spdx-expression" version = "0.5.2" @@ -6296,6 +6318,28 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +[[package]] +name = "wasm-component-ld" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "314d932d5e84c9678751b85498b1482b2f32f185744e449d3ce0b1d400376dad" +dependencies = [ + "anyhow", + "clap", + "lexopt", + "tempfile", + "wasmparser 0.210.0", + "wat", + "wit-component", +] + +[[package]] +name = "wasm-component-ld-wrapper" +version = "0.1.0" +dependencies = [ + "wasm-component-ld", +] + [[package]] name = "wasm-encoder" version = "0.200.0" @@ -6305,6 +6349,40 @@ dependencies = [ "leb128", ] +[[package]] +name = "wasm-encoder" +version = "0.210.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e3764d9d6edabd8c9e16195e177be0d20f6ab942ad18af52860f12f82bc59a" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasm-encoder" +version = "0.211.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e7d931a1120ef357f32b74547646b6fa68ea25e377772b72874b131a9ed70d4" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasm-metadata" +version = "0.210.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "012729d1294907fcb0866f08460ab95426a6d0b176a599619b84cac7653452b4" +dependencies = [ + "anyhow", + "indexmap", + "serde", + "serde_derive", + "serde_json", + "spdx", + "wasm-encoder 0.210.0", + "wasmparser 0.210.0", +] + [[package]] name = "wasmparser" version = "0.118.2" @@ -6315,6 +6393,42 @@ dependencies = [ "semver", ] +[[package]] +name = "wasmparser" +version = "0.210.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7bbcd21e7581619d9f6ca00f8c4f08f1cacfe58bf63f83af57cd0476f1026f5" +dependencies = [ + "ahash", + "bitflags 2.5.0", + "hashbrown", + "indexmap", + "semver", + "serde", +] + +[[package]] +name = "wast" +version = "211.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b25506dd82d00da6b14a87436b3d52b1d264083fa79cdb72a0d1b04a8595ccaa" +dependencies = [ + "bumpalo", + "leb128", + "memchr", + "unicode-width", + "wasm-encoder 0.211.1", +] + +[[package]] +name = "wat" +version = "1.211.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb716ca6c86eecac2d82541ffc39860118fc0af9309c4f2670637bea2e1bdd7d" +dependencies = [ + "wast", +] + [[package]] name = "winapi" version = "0.3.9" @@ -6542,6 +6656,43 @@ dependencies = [ "memchr", ] +[[package]] +name = "wit-component" +version = "0.210.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a450bdb5d032acf1fa0865451fa0c6f50e62f2d31eaa8dba967c2e2d068694a4" +dependencies = [ + "anyhow", + "bitflags 2.5.0", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder 0.210.0", + "wasm-metadata", + "wasmparser 0.210.0", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.210.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a965cbd439af19a4b44a54a97ab8957d86f02d01320efc9e31c1d3605c6710" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser 0.210.0", +] + [[package]] name = "writeable" version = "0.5.5" diff --git a/Cargo.toml b/Cargo.toml index 93c520b0d689..ce87a8c20b77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,7 @@ members = [ "src/tools/opt-dist", "src/tools/coverage-dump", "src/tools/rustc-perf-wrapper", + "src/tools/wasm-component-ld", ] exclude = [ @@ -104,6 +105,9 @@ rustc-demangle.debug = 0 [profile.release.package.lld-wrapper] debug = 0 strip = true +[profile.release.package.wasm-component-ld-wrapper] +debug = 0 +strip = true [patch.crates-io] # See comments in `library/rustc-std-workspace-core/README.md` for what's going on diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 11a7a4045351..175ef52b33fc 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1829,6 +1829,21 @@ impl Step for Assemble { &self_contained_lld_dir.join(exe(name, target_compiler.host)), ); } + + // In addition to `rust-lld` also install `wasm-component-ld` when + // LLD is enabled. This is a relatively small binary that primarily + // delegates to the `rust-lld` binary for linking and then runs + // logic to create the final binary. This is used by the + // `wasm32-wasip2` target of Rust. + let wasm_component_ld_exe = + builder.ensure(crate::core::build_steps::tool::WasmComponentLd { + compiler: build_compiler, + target: target_compiler.host, + }); + builder.copy_link( + &wasm_component_ld_exe, + &libdir_bin.join(wasm_component_ld_exe.file_name().unwrap()), + ); } if builder.config.llvm_enabled(target_compiler.host) { diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index ad92a01bce7f..e19a05371a7f 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -701,6 +701,34 @@ impl Step for LldWrapper { } } +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct WasmComponentLd { + pub compiler: Compiler, + pub target: TargetSelection, +} + +impl Step for WasmComponentLd { + type Output = PathBuf; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.never() + } + + fn run(self, builder: &Builder<'_>) -> PathBuf { + builder.ensure(ToolBuild { + compiler: self.compiler, + target: self.target, + tool: "wasm-component-ld", + mode: Mode::ToolStd, + path: "src/tools/wasm-component-ld", + source_type: SourceType::InTree, + extra_features: Vec::new(), + allow_features: "", + cargo_args: Vec::new(), + }) + } +} + #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustAnalyzer { pub compiler: Compiler, diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index e3cb396b7829..962484593b4b 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -112,6 +112,7 @@ ENV TARGETS=$TARGETS,wasm32-unknown-unknown ENV TARGETS=$TARGETS,wasm32-wasi ENV TARGETS=$TARGETS,wasm32-wasip1 ENV TARGETS=$TARGETS,wasm32-wasip1-threads +ENV TARGETS=$TARGETS,wasm32-wasip2 ENV TARGETS=$TARGETS,sparcv9-sun-solaris ENV TARGETS=$TARGETS,x86_64-pc-solaris ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32 diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 82fa43f581fd..871855df7beb 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -95,7 +95,12 @@ const EXCEPTIONS: ExceptionList = &[ ("self_cell", "Apache-2.0"), // rustc (fluent translations) ("snap", "BSD-3-Clause"), // rustc ("wasm-encoder", "Apache-2.0 WITH LLVM-exception"), // rustc + ("wasm-metadata", "Apache-2.0 WITH LLVM-exception"), // rustc ("wasmparser", "Apache-2.0 WITH LLVM-exception"), // rustc + ("wast", "Apache-2.0 WITH LLVM-exception"), // rustc + ("wat", "Apache-2.0 WITH LLVM-exception"), // rustc + ("wit-component", "Apache-2.0 WITH LLVM-exception"), // rustc + ("wit-parser", "Apache-2.0 WITH LLVM-exception"), // rustc // tidy-alphabetical-end ]; diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml new file mode 100644 index 000000000000..91ff19ad9fcb --- /dev/null +++ b/src/tools/wasm-component-ld/Cargo.toml @@ -0,0 +1,13 @@ +# See the `README.md` in this directory for what this tool is. + +[package] +name = "wasm-component-ld-wrapper" +version = "0.1.0" +edition = "2021" + +[[bin]] +name = "wasm-component-ld" +path = "src/main.rs" + +[dependencies] +wasm-component-ld = "0.5.4" diff --git a/src/tools/wasm-component-ld/README.md b/src/tools/wasm-component-ld/README.md new file mode 100644 index 000000000000..54608a2dea1d --- /dev/null +++ b/src/tools/wasm-component-ld/README.md @@ -0,0 +1,62 @@ +# `wasm-component-ld` + +This wrapper is a wrapper around the [`wasm-component-ld`] crates.io crate. That +crate. That crate is itself a thin wrapper around two pieces: + +* `wasm-ld` - the LLVM-based linker distributed as part of LLD and packaged in + Rust as `rust-lld`. +* [`wit-component`] - a Rust crate for creating a [WebAssembly Component] from a + core wasm module. + +This linker is used for Rust's `wasm32-wasip2` target to natively output a +component instead of a core WebAssembly module, unlike other WebAssembly +targets. If you're confused about any of this here's an FAQ-style explanation of +what's going on here: + +* **What's a component?** - It's a proposal to the WebAssembly standard + primarily developed at this time by out-of-browser use cases of WebAssembly. + You can find high-level documentation [here][component docs]. + +* **What's WASIp2?** - Not to be confused with WASIp1, WASIp0, + `wasi_snapshot_preview1`, or `wasi_unstable`, it's a version of WASI. Released + in January 2024 it's the first version of WASI defined in terms of the + component model. + +* **Why does this need its own linker?** - like any target that Rust has the + `wasm32-wasip2` target needs a linker. What makes this different from other + WebAssembly targets is that WASIp2 is defined at the component level, not core + WebAssembly level. This means that filesystem functions take a `string` + instead of `i32 i32`, for example. This means that the raw output of LLVM and + `wasm-ld`, a core WebAssembly module, is not suitable. + +* **Isn't writing a linker really hard?** - Generally, yes, but this linker + works by first asking `wasm-ld` to do all the hard work. It invokes `wasm-ld` + and then uses the output core WebAssembly module to create a component. + +* **How do you create a component from a core module?** - this is the purpose of + the [`wit-component`] crate, notably the `ComponentEncoder` type. This uses + component type information embedded in the core module and a general set of + conventions/guidelines with what the core module imports/exports. A component + is then hooked up to codify all of these conventions in a component itself. + +* **Why not require users to run `wit-component` themselves?** - while possible + it adds friction to the usage `wasm32-wasip2` target. More importantly though + the "module only" output of the `wasm32-wasip2` target is not ready right now. + The standard library still imports from `wasi_snapshot_preview1` and it will + take time to migrate all usage to WASIp2. + +* **What exactly does this linker do?** - the `wasm-component-ld` has the same + CLI interface and flags as `wasm-ld`, plus some more that are + component-specific. These flags are used to forward most flags to `wasm-ld` to + produce a core wasm module. After the core wasm module is produced the + `wit-component` crate will read custom sections in the final binary which + contain component type information. After merging all this type information + together a component is produced which wraps the core module. + +If you've got any other questions about this linker or its operation don't +hesitate to reach out to the maintainers of the `wasm32-wasip2` target. + +[`wasm-component-ld`]: https://crates.io/crates/wasm-component-ld +[`wit-component`]: https://crates.io/crates/wit-component +[WebAssembly Component]: https://github.com/webassembly/component-model +[component docs]: https://component-model.bytecodealliance.org/ diff --git a/src/tools/wasm-component-ld/src/main.rs b/src/tools/wasm-component-ld/src/main.rs new file mode 100644 index 000000000000..caaac651c4c7 --- /dev/null +++ b/src/tools/wasm-component-ld/src/main.rs @@ -0,0 +1,9 @@ +// See the `README.md` in this directory for what this tool is. + +// The source for this crate lives at +// https://github.com/bytecodealliance/wasm-component-ld and the binary is +// independently used in other projects such as `wasi-sdk` so the `main` +// function is just reexported here to delegate. A Cargo dependency is used to +// facilitate version management in the Rust repository and work well with +// vendored/offline builds. +use wasm_component_ld::main; From 1afdd45881d39f6af434fba77ae07e68e1b62bce Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 9 Jul 2024 10:26:33 -0700 Subject: [PATCH 092/734] Update how wasm-component-ld is built Reuse preexisting macro and switch it to a "bootstrap tool" to try to resolve build issues. --- src/bootstrap/src/core/build_steps/tool.rs | 29 +--------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index e19a05371a7f..d62166d8f047 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -337,6 +337,7 @@ bootstrap_tool!( RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = "test"; CoverageDump, "src/tools/coverage-dump", "coverage-dump"; RustcPerfWrapper, "src/tools/rustc-perf-wrapper", "rustc-perf-wrapper"; + WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld"; ); #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -701,34 +702,6 @@ impl Step for LldWrapper { } } -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub struct WasmComponentLd { - pub compiler: Compiler, - pub target: TargetSelection, -} - -impl Step for WasmComponentLd { - type Output = PathBuf; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.never() - } - - fn run(self, builder: &Builder<'_>) -> PathBuf { - builder.ensure(ToolBuild { - compiler: self.compiler, - target: self.target, - tool: "wasm-component-ld", - mode: Mode::ToolStd, - path: "src/tools/wasm-component-ld", - source_type: SourceType::InTree, - extra_features: Vec::new(), - allow_features: "", - cargo_args: Vec::new(), - }) - } -} - #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustAnalyzer { pub compiler: Compiler, From 4cd6eee894ec87de26b8dc212363c23f1db70c62 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 9 Jul 2024 13:02:51 -0700 Subject: [PATCH 093/734] Unconditionally use stage0 build compiler --- src/bootstrap/src/core/build_steps/compile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 175ef52b33fc..5650fea1b812 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1837,7 +1837,7 @@ impl Step for Assemble { // `wasm32-wasip2` target of Rust. let wasm_component_ld_exe = builder.ensure(crate::core::build_steps::tool::WasmComponentLd { - compiler: build_compiler, + compiler: build_compiler.with_stage(0), target: target_compiler.host, }); builder.copy_link( From f96f68f2ec4b512a91b27d1b14d3dae66305cc6e Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Tue, 9 Jul 2024 23:07:38 +0100 Subject: [PATCH 094/734] Test that `--print link-args` ends in newline --- tests/run-make/link-arg/rmake.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-make/link-arg/rmake.rs b/tests/run-make/link-arg/rmake.rs index a6d68800792f..c0bf8d972af7 100644 --- a/tests/run-make/link-arg/rmake.rs +++ b/tests/run-make/link-arg/rmake.rs @@ -17,4 +17,5 @@ fn main() { .run_unchecked(); out.assert_stdout_contains("lfoo"); out.assert_stdout_contains("lbar"); + assert!(out.stdout_utf8().ends_with('\n')); } From 601a61fe276a92bbde6e74d60fc493e064677d9d Mon Sep 17 00:00:00 2001 From: xFrednet Date: Tue, 9 Jul 2024 23:51:31 +0200 Subject: [PATCH 095/734] Lintcheck: Refactor `CrateSource` --- lintcheck/src/input.rs | 65 ++++++++++++++++++++---------------------- lintcheck/src/main.rs | 10 ++----- 2 files changed, 33 insertions(+), 42 deletions(-) diff --git a/lintcheck/src/input.rs b/lintcheck/src/input.rs index 3d034391c280..8e048615f43e 100644 --- a/lintcheck/src/input.rs +++ b/lintcheck/src/input.rs @@ -37,28 +37,22 @@ struct TomlCrate { /// Represents an archive we download from crates.io, or a git repo, or a local repo/folder /// Once processed (downloaded/extracted/cloned/copied...), this will be translated into a `Crate` +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)] +pub struct CrateWithSource { + pub name: String, + pub source: CrateSource, + pub options: Option>, +} + #[derive(Debug, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)] pub enum CrateSource { - CratesIo { - name: String, - version: String, - options: Option>, - }, - Git { - name: String, - url: String, - commit: String, - options: Option>, - }, - Path { - name: String, - path: PathBuf, - options: Option>, - }, + CratesIo { version: String }, + Git { url: String, commit: String }, + Path { path: PathBuf }, } /// Read a `lintcheck_crates.toml` file -pub fn read_crates(toml_path: &Path) -> (Vec, RecursiveOptions) { +pub fn read_crates(toml_path: &Path) -> (Vec, RecursiveOptions) { let toml_content: String = fs::read_to_string(toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display())); let crate_list: SourceList = @@ -71,23 +65,29 @@ pub fn read_crates(toml_path: &Path) -> (Vec, RecursiveOptions) { let mut crate_sources = Vec::new(); for tk in tomlcrates { if let Some(ref path) = tk.path { - crate_sources.push(CrateSource::Path { + crate_sources.push(CrateWithSource { name: tk.name.clone(), - path: PathBuf::from(path), + source: CrateSource::Path { + path: PathBuf::from(path), + }, options: tk.options.clone(), }); } else if let Some(ref version) = tk.version { - crate_sources.push(CrateSource::CratesIo { + crate_sources.push(CrateWithSource { name: tk.name.clone(), - version: version.to_string(), + source: CrateSource::CratesIo { + version: version.to_string(), + }, options: tk.options.clone(), }); } else if tk.git_url.is_some() && tk.git_hash.is_some() { // otherwise, we should have a git source - crate_sources.push(CrateSource::Git { + crate_sources.push(CrateWithSource { name: tk.name.clone(), - url: tk.git_url.clone().unwrap(), - commit: tk.git_hash.clone().unwrap(), + source: CrateSource::Git { + url: tk.git_url.clone().unwrap(), + commit: tk.git_hash.clone().unwrap(), + }, options: tk.options.clone(), }); } else { @@ -117,7 +117,7 @@ pub fn read_crates(toml_path: &Path) -> (Vec, RecursiveOptions) { (crate_sources, crate_list.recursive) } -impl CrateSource { +impl CrateWithSource { /// Makes the sources available on the disk for clippy to check. /// Clones a git repo and checks out the specified commit or downloads a crate from crates.io or /// copies a local folder @@ -139,8 +139,10 @@ impl CrateSource { retries += 1; } } - match self { - CrateSource::CratesIo { name, version, options } => { + let name = &self.name; + let options = &self.options; + match &self.source { + CrateSource::CratesIo { version } => { let extract_dir = PathBuf::from(LINTCHECK_SOURCES); let krate_download_dir = PathBuf::from(LINTCHECK_DOWNLOADS); @@ -173,12 +175,7 @@ impl CrateSource { options: options.clone(), } }, - CrateSource::Git { - name, - url, - commit, - options, - } => { + CrateSource::Git { url, commit } => { let repo_path = { let mut repo_path = PathBuf::from(LINTCHECK_SOURCES); // add a -git suffix in case we have the same crate from crates.io and a git repo @@ -219,7 +216,7 @@ impl CrateSource { options: options.clone(), } }, - CrateSource::Path { name, path, options } => { + CrateSource::Path { path } => { fn is_cache_dir(entry: &DirEntry) -> bool { fs::read(entry.path().join("CACHEDIR.TAG")) .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55")) diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index e37ffab13ac8..e85d70f11ed6 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -38,7 +38,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::{env, fs}; use cargo_metadata::Message; -use input::{read_crates, CrateSource}; +use input::read_crates; use output::{ClippyCheckOutput, ClippyWarning, RustcIce}; use rayon::prelude::*; @@ -292,13 +292,7 @@ fn lintcheck(config: LintcheckConfig) { .into_iter() .filter(|krate| { if let Some(only_one_crate) = &config.only { - let name = match krate { - CrateSource::CratesIo { name, .. } - | CrateSource::Git { name, .. } - | CrateSource::Path { name, .. } => name, - }; - - name == only_one_crate + krate.name == *only_one_crate } else { true } From 83e1efb254d3de48c4c00eed67698a4d10173407 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 10 Jul 2024 16:15:23 +1000 Subject: [PATCH 096/734] Replace a long inline "autoref" comment with method docs This comment has two problems: - It is very long, making the flow of the enclosing method hard to follow. - It starts by talking about an `autoref` flag that hasn't existed since #59114. This PR therefore replaces the long inline comment with a revised doc comment on `bind_matched_candidate_for_guard`, and some shorter inline comments. For readers who want more historical context, we also link to the PR that added the old comment, and the PR that removed the `autoref` flag. --- .../rustc_mir_build/src/build/matches/mod.rs | 165 +++++++++--------- 1 file changed, 84 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 5695c881ecc2..7b92c0a1be8f 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -2177,92 +2177,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.ascribe_types(block, ascriptions); - // rust-lang/rust#27282: The `autoref` business deserves some - // explanation here. - // - // The intent of the `autoref` flag is that when it is true, - // then any pattern bindings of type T will map to a `&T` - // within the context of the guard expression, but will - // continue to map to a `T` in the context of the arm body. To - // avoid surfacing this distinction in the user source code - // (which would be a severe change to the language and require - // far more revision to the compiler), when `autoref` is true, - // then any occurrence of the identifier in the guard - // expression will automatically get a deref op applied to it. - // - // So an input like: - // - // ``` - // let place = Foo::new(); - // match place { foo if inspect(foo) - // => feed(foo), ... } - // ``` - // - // will be treated as if it were really something like: - // - // ``` - // let place = Foo::new(); - // match place { Foo { .. } if { let tmp1 = &place; inspect(*tmp1) } - // => { let tmp2 = place; feed(tmp2) }, ... } - // ``` - // - // And an input like: - // - // ``` - // let place = Foo::new(); - // match place { ref mut foo if inspect(foo) - // => feed(foo), ... } - // ``` - // - // will be treated as if it were really something like: - // - // ``` - // let place = Foo::new(); - // match place { Foo { .. } if { let tmp1 = & &mut place; inspect(*tmp1) } - // => { let tmp2 = &mut place; feed(tmp2) }, ... } - // ``` - // - // In short, any pattern binding will always look like *some* - // kind of `&T` within the guard at least in terms of how the - // MIR-borrowck views it, and this will ensure that guard - // expressions cannot mutate their the match inputs via such - // bindings. (It also ensures that guard expressions can at - // most *copy* values from such bindings; non-Copy things - // cannot be moved via pattern bindings in guard expressions.) - // - // ---- - // - // Implementation notes (under assumption `autoref` is true). - // - // To encode the distinction above, we must inject the - // temporaries `tmp1` and `tmp2`. - // - // There are two cases of interest: binding by-value, and binding by-ref. - // - // 1. Binding by-value: Things are simple. - // - // * Establishing `tmp1` creates a reference into the - // matched place. This code is emitted by - // bind_matched_candidate_for_guard. - // - // * `tmp2` is only initialized "lazily", after we have - // checked the guard. Thus, the code that can trigger - // moves out of the candidate can only fire after the - // guard evaluated to true. This initialization code is - // emitted by bind_matched_candidate_for_arm. - // - // 2. Binding by-reference: Things are tricky. - // - // * Here, the guard expression wants a `&&` or `&&mut` - // into the original input. This means we need to borrow - // the reference that we create for the arm. - // * So we eagerly create the reference for the arm and then take a - // reference to that. + // Lower an instance of the arm guard (if present) for this candidate, + // and then perform bindings for the arm body. if let Some((arm, match_scope)) = arm_match_scope && let Some(guard) = arm.guard { let tcx = self.tcx; + // Bindings for guards require some extra handling to automatically + // insert implicit references/dereferences. self.bind_matched_candidate_for_guard(block, schedule_drops, bindings.clone()); let guard_frame = GuardFrame { locals: bindings.clone().map(|b| GuardFrameLocal::new(b.var_id)).collect(), @@ -2402,6 +2325,82 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + /// Binding for guards is a bit different from binding for the arm body, + /// because an extra layer of implicit reference/dereference is added. + /// + /// The idea is that any pattern bindings of type T will map to a `&T` within + /// the context of the guard expression, but will continue to map to a `T` + /// in the context of the arm body. To avoid surfacing this distinction in + /// the user source code (which would be a severe change to the language and + /// require far more revision to the compiler), any occurrence of the + /// identifier in the guard expression will automatically get a deref op + /// applied to it. (See the caller of [`Self::is_bound_var_in_guard`].) + /// + /// So an input like: + /// + /// ```ignore (illustrative) + /// let place = Foo::new(); + /// match place { foo if inspect(foo) + /// => feed(foo), ... } + /// ``` + /// + /// will be treated as if it were really something like: + /// + /// ```ignore (illustrative) + /// let place = Foo::new(); + /// match place { Foo { .. } if { let tmp1 = &place; inspect(*tmp1) } + /// => { let tmp2 = place; feed(tmp2) }, ... } + /// ``` + /// + /// And an input like: + /// + /// ```ignore (illustrative) + /// let place = Foo::new(); + /// match place { ref mut foo if inspect(foo) + /// => feed(foo), ... } + /// ``` + /// + /// will be treated as if it were really something like: + /// + /// ```ignore (illustrative) + /// let place = Foo::new(); + /// match place { Foo { .. } if { let tmp1 = & &mut place; inspect(*tmp1) } + /// => { let tmp2 = &mut place; feed(tmp2) }, ... } + /// ``` + /// --- + /// + /// ## Implementation notes + /// + /// To encode the distinction above, we must inject the + /// temporaries `tmp1` and `tmp2`. + /// + /// There are two cases of interest: binding by-value, and binding by-ref. + /// + /// 1. Binding by-value: Things are simple. + /// + /// * Establishing `tmp1` creates a reference into the + /// matched place. This code is emitted by + /// [`Self::bind_matched_candidate_for_guard`]. + /// + /// * `tmp2` is only initialized "lazily", after we have + /// checked the guard. Thus, the code that can trigger + /// moves out of the candidate can only fire after the + /// guard evaluated to true. This initialization code is + /// emitted by [`Self::bind_matched_candidate_for_arm_body`]. + /// + /// 2. Binding by-reference: Things are tricky. + /// + /// * Here, the guard expression wants a `&&` or `&&mut` + /// into the original input. This means we need to borrow + /// the reference that we create for the arm. + /// * So we eagerly create the reference for the arm and then take a + /// reference to that. + /// + /// --- + /// + /// See these PRs for some historical context: + /// - (introduction of autoref) + /// - (always use autoref) fn bind_matched_candidate_for_guard<'b>( &mut self, block: BasicBlock, @@ -2433,10 +2432,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); match binding.binding_mode.0 { ByRef::No => { + // The arm binding will be by value, so for the guard binding + // just take a shared reference to the matched place. let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, binding.source); self.cfg.push_assign(block, source_info, ref_for_guard, rvalue); } ByRef::Yes(mutbl) => { + // The arm binding will be by reference, so eagerly create it now. let value_for_arm = self.storage_live_binding( block, binding.var_id, @@ -2448,6 +2450,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let rvalue = Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source); self.cfg.push_assign(block, source_info, value_for_arm, rvalue); + // For the guard binding, take a shared reference to that reference. let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, value_for_arm); self.cfg.push_assign(block, source_info, ref_for_guard, rvalue); } From 5824ab178b0b28c948798576de78625ba8209adc Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 26 Jun 2024 14:02:52 +0000 Subject: [PATCH 097/734] Support lists and stylings in more places for `rustc --explain` --- .../src/error_codes/E0373.md | 2 +- .../src/error_codes/E0378.md | 2 +- compiler/rustc_errors/src/lib.rs | 1 + compiler/rustc_errors/src/markdown/parse.rs | 62 ++++++++++-------- .../rustc_errors/src/markdown/tests/parse.rs | 65 +++++++++++++++++-- 5 files changed, 96 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0373.md b/compiler/rustc_error_codes/src/error_codes/E0373.md index effa597aad91..d4d26007aa50 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0373.md +++ b/compiler/rustc_error_codes/src/error_codes/E0373.md @@ -70,4 +70,4 @@ fn spawn(future: F) { Similarly to closures, `async` blocks are not executed immediately and may capture closed-over data by reference. For more information, see -https://rust-lang.github.io/async-book/03_async_await/01_chapter.html. +. diff --git a/compiler/rustc_error_codes/src/error_codes/E0378.md b/compiler/rustc_error_codes/src/error_codes/E0378.md index c6fe997f3dcf..7d939b99b04e 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0378.md +++ b/compiler/rustc_error_codes/src/error_codes/E0378.md @@ -20,7 +20,7 @@ where The `DispatchFromDyn` trait currently can only be implemented for builtin pointer types and structs that are newtype wrappers around them -— that is, the struct must have only one field (except for`PhantomData`), +— that is, the struct must have only one field (except for `PhantomData`), and that field must itself implement `DispatchFromDyn`. ``` diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 91112a572770..76045c69cc1c 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -15,6 +15,7 @@ #![feature(box_patterns)] #![feature(error_reporter)] #![feature(extract_if)] +#![feature(if_let_guard)] #![feature(let_chains)] #![feature(negative_impls)] #![feature(never_type)] diff --git a/compiler/rustc_errors/src/markdown/parse.rs b/compiler/rustc_errors/src/markdown/parse.rs index 67e4963fddf7..69e7120e7149 100644 --- a/compiler/rustc_errors/src/markdown/parse.rs +++ b/compiler/rustc_errors/src/markdown/parse.rs @@ -10,15 +10,15 @@ const CBK: &[u8] = b"```"; const CIL: &[u8] = b"`"; const CMT_E: &[u8] = b"-->"; const CMT_S: &[u8] = b" $DIR/normalize-tait-in-const.rs:27:42 +error: expected a trait, found type + --> $DIR/normalize-tait-in-const.rs:27:34 | LL | const fn with_positive Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/normalize-tait-in-const.rs:27:69 - | -LL | const fn with_positive Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { - | ^^^^^^^^ +error: aborting due to 1 previous error -error[E0015]: cannot call non-const closure in constant functions - --> $DIR/normalize-tait-in-const.rs:28:5 - | -LL | fun(filter_positive()); - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: consider further restricting this bound - | -LL | const fn with_positive Fn(&'a Alias<'a>) + ~const Destruct + ~const Fn(&foo::Alias<'_>)>(fun: F) { - | ++++++++++++++++++++++++++++ -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | - -error[E0493]: destructor of `F` cannot be evaluated at compile-time - --> $DIR/normalize-tait-in-const.rs:27:79 - | -LL | const fn with_positive Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { - | ^^^ the destructor for this type cannot be evaluated in constant functions -LL | fun(filter_positive()); -LL | } - | - value is dropped here - -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0015, E0493. -For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/issues/issue-39089.rs b/tests/ui/issues/issue-39089.rs index b00b84238023..e6bec3373549 100644 --- a/tests/ui/issues/issue-39089.rs +++ b/tests/ui/issues/issue-39089.rs @@ -1,5 +1,4 @@ -//@ check-pass -#![allow(dead_code)] fn f Sized>() {} +//~^ ERROR expected a trait, found type fn main() {} diff --git a/tests/ui/issues/issue-39089.stderr b/tests/ui/issues/issue-39089.stderr new file mode 100644 index 000000000000..3e57a6fcbcb5 --- /dev/null +++ b/tests/ui/issues/issue-39089.stderr @@ -0,0 +1,8 @@ +error: expected a trait, found type + --> $DIR/issue-39089.rs:1:10 + | +LL | fn f Sized>() {} + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/bounds-type.rs b/tests/ui/parser/bounds-type.rs index a1971fa3146d..2b2a44b70628 100644 --- a/tests/ui/parser/bounds-type.rs +++ b/tests/ui/parser/bounds-type.rs @@ -5,7 +5,7 @@ struct S< T: Tr + 'a, // OK T: 'a, // OK T:, // OK - T: ?for<'a> Trait, // OK + T: for<'a> ?Trait, // OK T: Tr +, // OK T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs index 496f97b5e24a..4dd0e69598d7 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs @@ -4,6 +4,6 @@ #![feature(const_trait_impl)] struct S< - T: ~const ?for<'a> Tr<'a> + 'static + ~const std::ops::Add, - T: ~const ?for<'a: 'b> m::Trait<'a>, + T: for<'a> ~const ?Tr<'a> + 'static + ~const std::ops::Add, + T: for<'a: 'b> ~const ?m::Trait<'a>, >; From 32c8bfdb11e519c6608ead730b6dfafc6cafb9c5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 27 Jun 2024 13:07:03 -0400 Subject: [PATCH 100/734] Improve error message --- compiler/rustc_parse/messages.ftl | 3 ++ compiler/rustc_parse/src/errors.rs | 9 ++++ compiler/rustc_parse/src/parser/ty.rs | 8 ++++ src/tools/tidy/src/ui_tests.rs | 2 +- .../ui/impl-trait/normalize-tait-in-const.rs | 2 +- .../impl-trait/normalize-tait-in-const.stderr | 43 ++++++++++++++++--- tests/ui/issues/issue-39089.rs | 2 +- tests/ui/issues/issue-39089.stderr | 8 ++-- 8 files changed, 66 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 02c3c87313bc..5fb59eeb4f32 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -53,6 +53,9 @@ parse_bare_cr = {$double_quotes -> parse_bare_cr_in_raw_string = bare CR not allowed in raw string +parse_binder_before_modifiers = `for<...>` binder should be placed before trait bound modifiers + .label = place the `for<...>` binder before any modifiers + parse_bounds_not_allowed_on_trait_aliases = bounds are not allowed on trait aliases parse_box_not_pat = expected pattern, found {$descr} diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 3ae9b6dad998..6738cc4a1200 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3041,3 +3041,12 @@ pub struct UnsafeAttrOutsideUnsafeSuggestion { #[suggestion_part(code = ")")] pub right: Span, } + +#[derive(Diagnostic)] +#[diag(parse_binder_before_modifiers)] +pub struct BinderBeforeModifiers { + #[primary_span] + pub binder_span: Span, + #[label] + pub modifiers_span: Span, +} diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 24183ac1218e..306029ca94c6 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -989,7 +989,10 @@ impl<'a> Parser<'a> { leading_token: &Token, ) -> PResult<'a, GenericBound> { let (mut lifetime_defs, binder_span) = self.parse_late_bound_lifetime_defs()?; + + let modifiers_lo = self.token.span; let modifiers = self.parse_trait_bound_modifiers()?; + let modifiers_span = modifiers_lo.to(self.prev_token.span); // Recover erroneous lifetime bound with modifiers or binder. // e.g. `T: for<'a> 'a` or `T: ~const 'a`. @@ -998,6 +1001,11 @@ impl<'a> Parser<'a> { return self.parse_generic_lt_bound(lo, has_parens); } + if let (more_lifetime_defs, Some(binder_span)) = self.parse_late_bound_lifetime_defs()? { + lifetime_defs.extend(more_lifetime_defs); + self.dcx().emit_err(errors::BinderBeforeModifiers { binder_span, modifiers_span }); + } + let mut path = if self.token.is_keyword(kw::Fn) && self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis)) && let Some(path) = self.recover_path_from_fn() diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 5e6992038e39..0ae0356b2c45 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -16,7 +16,7 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: u32 = 901; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: u32 = 1672; +const ISSUES_ENTRY_LIMIT: u32 = 1673; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/ui/impl-trait/normalize-tait-in-const.rs b/tests/ui/impl-trait/normalize-tait-in-const.rs index fc90139d6409..e3f53e5f8a82 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.rs +++ b/tests/ui/impl-trait/normalize-tait-in-const.rs @@ -24,7 +24,7 @@ mod foo { } use foo::*; -const fn with_positive Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { +const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { fun(filter_positive()); } diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr index 77de689fb97a..b20dabe7b25a 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.stderr +++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr @@ -1,8 +1,41 @@ -error: expected a trait, found type - --> $DIR/normalize-tait-in-const.rs:27:34 +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/normalize-tait-in-const.rs:27:42 | -LL | const fn with_positive Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { + | ^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/normalize-tait-in-const.rs:27:69 + | +LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { + | ^^^^^^^^ +error[E0015]: cannot call non-const closure in constant functions + --> $DIR/normalize-tait-in-const.rs:28:5 + | +LL | fun(filter_positive()); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: consider further restricting this bound + | +LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct + ~const Fn(&foo::Alias<'_>)>(fun: F) { + | ++++++++++++++++++++++++++++ +help: add `#![feature(effects)]` to the crate attributes to enable + | +LL + #![feature(effects)] + | + +error[E0493]: destructor of `F` cannot be evaluated at compile-time + --> $DIR/normalize-tait-in-const.rs:27:79 + | +LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { + | ^^^ the destructor for this type cannot be evaluated in constant functions +LL | fun(filter_positive()); +LL | } + | - value is dropped here + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0015, E0493. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/issues/issue-39089.rs b/tests/ui/issues/issue-39089.rs index e6bec3373549..822c47503afe 100644 --- a/tests/ui/issues/issue-39089.rs +++ b/tests/ui/issues/issue-39089.rs @@ -1,4 +1,4 @@ fn f Sized>() {} -//~^ ERROR expected a trait, found type +//~^ ERROR `for<...>` binder should be placed before trait bound modifiers fn main() {} diff --git a/tests/ui/issues/issue-39089.stderr b/tests/ui/issues/issue-39089.stderr index 3e57a6fcbcb5..a81010aedff5 100644 --- a/tests/ui/issues/issue-39089.stderr +++ b/tests/ui/issues/issue-39089.stderr @@ -1,8 +1,10 @@ -error: expected a trait, found type - --> $DIR/issue-39089.rs:1:10 +error: `for<...>` binder should be placed before trait bound modifiers + --> $DIR/issue-39089.rs:1:13 | LL | fn f Sized>() {} - | ^^^^^^^^^^^^^ + | - ^^^^ + | | + | place the `for<...>` binder before any modifiers error: aborting due to 1 previous error From 898ed2ffa6c485530af1fbe6117c0deb4290715f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 10 Jul 2024 17:49:50 -0400 Subject: [PATCH 101/734] Enforce that ? and for<...> are not combined --- compiler/rustc_parse/messages.ftl | 3 +++ compiler/rustc_parse/src/errors.rs | 10 ++++++++++ compiler/rustc_parse/src/parser/ty.rs | 13 +++++++++++++ tests/ui/parser/bounds-type.rs | 2 +- tests/ui/parser/bounds-type.stderr | 10 +++++++++- .../rfc-2632-const-trait-impl/tilde-const-syntax.rs | 4 ++-- 6 files changed, 38 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 5fb59eeb4f32..5b4a5f4dd38e 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -53,6 +53,9 @@ parse_bare_cr = {$double_quotes -> parse_bare_cr_in_raw_string = bare CR not allowed in raw string +parse_binder_and_polarity = `for<...>` binder not allowed with `{$polarity}` trait polarity modifier + .label = there is not a well-defined meaning for a higher-ranked `{$polarity}` trait + parse_binder_before_modifiers = `for<...>` binder should be placed before trait bound modifiers .label = place the `for<...>` binder before any modifiers diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 6738cc4a1200..9b18a771fdea 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3050,3 +3050,13 @@ pub struct BinderBeforeModifiers { #[label] pub modifiers_span: Span, } + +#[derive(Diagnostic)] +#[diag(parse_binder_and_polarity)] +pub struct BinderAndPolarity { + #[primary_span] + pub polarity_span: Span, + #[label] + pub binder_span: Span, + pub polarity: &'static str, +} diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 306029ca94c6..6de778fa9f21 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -994,6 +994,19 @@ impl<'a> Parser<'a> { let modifiers = self.parse_trait_bound_modifiers()?; let modifiers_span = modifiers_lo.to(self.prev_token.span); + if let Some(binder_span) = binder_span { + match modifiers.polarity { + BoundPolarity::Negative(polarity_span) | BoundPolarity::Maybe(polarity_span) => { + self.dcx().emit_err(errors::BinderAndPolarity { + binder_span, + polarity_span, + polarity: modifiers.polarity.as_str(), + }); + } + BoundPolarity::Positive => {} + } + } + // Recover erroneous lifetime bound with modifiers or binder. // e.g. `T: for<'a> 'a` or `T: ~const 'a`. if self.token.is_lifetime() { diff --git a/tests/ui/parser/bounds-type.rs b/tests/ui/parser/bounds-type.rs index 2b2a44b70628..47fec7b1e77f 100644 --- a/tests/ui/parser/bounds-type.rs +++ b/tests/ui/parser/bounds-type.rs @@ -5,7 +5,7 @@ struct S< T: Tr + 'a, // OK T: 'a, // OK T:, // OK - T: for<'a> ?Trait, // OK + T: for<'a> ?Trait, //~ ERROR `for<...>` binder not allowed with `?` trait polarity modifier T: Tr +, // OK T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds diff --git a/tests/ui/parser/bounds-type.stderr b/tests/ui/parser/bounds-type.stderr index d1210e88d667..fa8ab6812b15 100644 --- a/tests/ui/parser/bounds-type.stderr +++ b/tests/ui/parser/bounds-type.stderr @@ -1,3 +1,11 @@ +error: `for<...>` binder not allowed with `?` trait polarity modifier + --> $DIR/bounds-type.rs:8:16 + | +LL | T: for<'a> ?Trait, + | ---- ^ + | | + | there is not a well-defined meaning for a higher-ranked `?` trait + error: `?` may only modify trait bounds, not lifetime bounds --> $DIR/bounds-type.rs:10:8 | @@ -16,5 +24,5 @@ error: `const` may only modify trait bounds, not lifetime bounds LL | T: const 'a, | ^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs index 4dd0e69598d7..d65ecae3d067 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs @@ -4,6 +4,6 @@ #![feature(const_trait_impl)] struct S< - T: for<'a> ~const ?Tr<'a> + 'static + ~const std::ops::Add, - T: for<'a: 'b> ~const ?m::Trait<'a>, + T: for<'a> ~const Tr<'a> + 'static + ~const std::ops::Add, + T: for<'a: 'b> ~const m::Trait<'a>, >; From de560c30659281e8c91a48579f907097efe22adf Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 20 Feb 2024 21:40:25 +0100 Subject: [PATCH 102/734] Implement `ambiguous_negative_literals` lint --- compiler/rustc_lint/messages.ftl | 5 + compiler/rustc_lint/src/lib.rs | 3 + compiler/rustc_lint/src/lints.rs | 29 ++++ compiler/rustc_lint/src/precedence.rs | 70 ++++++++++ tests/ui/lint/negative_literals.rs | 35 +++++ tests/ui/lint/negative_literals.stderr | 179 +++++++++++++++++++++++++ 6 files changed, 321 insertions(+) create mode 100644 compiler/rustc_lint/src/precedence.rs create mode 100644 tests/ui/lint/negative_literals.rs create mode 100644 tests/ui/lint/negative_literals.stderr diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index f048f6fe8ad4..4f7f01e56b63 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -5,6 +5,11 @@ lint_ambiguous_glob_reexport = ambiguous glob re-exports .label_first_reexport = the name `{$name}` in the {$namespace} namespace is first re-exported here .label_duplicate_reexport = but the name `{$name}` in the {$namespace} namespace is also re-exported here +lint_ambiguous_negative_literals = `-` has lower precedence than method calls, which might be unexpected + .example = e.g. `-4.abs()` equals `-4`; while `(-4).abs()` equals `4` + .negative_literal = add parentheses around the `-` and the literal to call the method on a negative literal + .current_behavior = add parentheses around the literal and the method call to keep the current behavior + lint_ambiguous_wide_pointer_comparisons = ambiguous wide pointer comparison, the comparison includes metadata which may not be expected .addr_metadata_suggestion = use explicit `std::ptr::eq` method to compare metadata and addresses .addr_suggestion = use `std::ptr::addr_eq` or untyped pointers to only compare their addresses diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 868a44a980a0..0a058b675ffa 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -72,6 +72,7 @@ mod noop_method_call; mod opaque_hidden_inferred_bound; mod pass_by_value; mod passes; +mod precedence; mod ptr_nulls; mod redundant_semicolon; mod reference_casting; @@ -109,6 +110,7 @@ use nonstandard_style::*; use noop_method_call::*; use opaque_hidden_inferred_bound::*; use pass_by_value::*; +use precedence::*; use ptr_nulls::*; use redundant_semicolon::*; use reference_casting::*; @@ -173,6 +175,7 @@ early_lint_methods!( RedundantSemicolons: RedundantSemicolons, UnusedDocComment: UnusedDocComment, Expr2024: Expr2024, + Precedence: Precedence, ] ] ); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 54c73710eca6..873322c13b46 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1489,6 +1489,35 @@ pub struct NonLocalDefinitionsCargoUpdateNote { pub crate_name: Symbol, } +// precedence.rs +#[derive(LintDiagnostic)] +#[diag(lint_ambiguous_negative_literals)] +#[note(lint_example)] +pub struct AmbiguousNegativeLiteralsDiag { + #[subdiagnostic] + pub negative_literal: AmbiguousNegativeLiteralsNegativeLiteralSuggestion, + #[subdiagnostic] + pub current_behavior: AmbiguousNegativeLiteralsCurrentBehaviorSuggestion, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(lint_negative_literal, applicability = "maybe-incorrect")] +pub struct AmbiguousNegativeLiteralsNegativeLiteralSuggestion { + #[suggestion_part(code = "(")] + pub start_span: Span, + #[suggestion_part(code = ")")] + pub end_span: Span, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(lint_current_behavior, applicability = "maybe-incorrect")] +pub struct AmbiguousNegativeLiteralsCurrentBehaviorSuggestion { + #[suggestion_part(code = "(")] + pub start_span: Span, + #[suggestion_part(code = ")")] + pub end_span: Span, +} + // pass_by_value.rs #[derive(LintDiagnostic)] #[diag(lint_pass_by_value)] diff --git a/compiler/rustc_lint/src/precedence.rs b/compiler/rustc_lint/src/precedence.rs new file mode 100644 index 000000000000..eb2ba3972779 --- /dev/null +++ b/compiler/rustc_lint/src/precedence.rs @@ -0,0 +1,70 @@ +use rustc_ast::token::LitKind; +use rustc_ast::{Expr, ExprKind, MethodCall, UnOp}; +use rustc_session::{declare_lint, declare_lint_pass}; + +use crate::lints::{ + AmbiguousNegativeLiteralsCurrentBehaviorSuggestion, AmbiguousNegativeLiteralsDiag, + AmbiguousNegativeLiteralsNegativeLiteralSuggestion, +}; +use crate::{EarlyContext, EarlyLintPass, LintContext}; + +declare_lint! { + /// The `ambiguous_negative_literals` lint checks for cases that are + /// confusing between a negative literal and a negation that's not part + /// of the literal. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #![allow(unused)] + /// -1i32.abs(); // equals -1, while `(-1i32).abs()` equals 1 + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Method calls take precedence over unary precedence. Setting the + /// precedence explicitly makes the code clearer and avoid potential bugs. + pub AMBIGUOUS_NEGATIVE_LITERALS, + Deny, + "ambiguous negative literals operations", + report_in_external_macro +} + +declare_lint_pass!(Precedence => [AMBIGUOUS_NEGATIVE_LITERALS]); + +impl EarlyLintPass for Precedence { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + let ExprKind::Unary(UnOp::Neg, operand) = &expr.kind else { + return; + }; + + let mut arg = operand; + let mut at_least_one = false; + while let ExprKind::MethodCall(box MethodCall { receiver, .. }) = &arg.kind { + at_least_one = true; + arg = receiver; + } + + if at_least_one + && let ExprKind::Lit(lit) = &arg.kind + && let LitKind::Integer | LitKind::Float = &lit.kind + { + cx.emit_span_lint( + AMBIGUOUS_NEGATIVE_LITERALS, + expr.span, + AmbiguousNegativeLiteralsDiag { + negative_literal: AmbiguousNegativeLiteralsNegativeLiteralSuggestion { + start_span: expr.span.shrink_to_lo(), + end_span: arg.span.shrink_to_hi(), + }, + current_behavior: AmbiguousNegativeLiteralsCurrentBehaviorSuggestion { + start_span: operand.span.shrink_to_lo(), + end_span: operand.span.shrink_to_hi(), + }, + }, + ); + } + } +} diff --git a/tests/ui/lint/negative_literals.rs b/tests/ui/lint/negative_literals.rs new file mode 100644 index 000000000000..048fcd6ff57b --- /dev/null +++ b/tests/ui/lint/negative_literals.rs @@ -0,0 +1,35 @@ +//@ check-fail + +fn main() { + let _ = -1i32.abs(); + //~^ ERROR `-` has lower precedence than method calls + let _ = -1f32.abs(); + //~^ ERROR `-` has lower precedence than method calls + let _ = -1f64.asin(); + //~^ ERROR `-` has lower precedence than method calls + let _ = -1f64.asinh(); + //~^ ERROR `-` has lower precedence than method calls + let _ = -1f64.tan(); + //~^ ERROR `-` has lower precedence than method calls + let _ = -1f64.tanh(); + //~^ ERROR `-` has lower precedence than method calls + let _ = -1.0_f64.cos().cos(); + //~^ ERROR `-` has lower precedence than method calls + let _ = -1.0_f64.cos().sin(); + //~^ ERROR `-` has lower precedence than method calls + let _ = -1.0_f64.sin().cos(); + //~^ ERROR `-` has lower precedence than method calls + let _ = -1f64.sin().sin(); + //~^ ERROR `-` has lower precedence than method calls + + dbg!( -1.0_f32.cos() ); + //~^ ERROR `-` has lower precedence than method calls + + // should not warn + let _ = (-1i32).abs(); + let _ = (-1f32).abs(); + let _ = -(1i32).abs(); + let _ = -(1f32).abs(); + let _ = -(1i32.abs()); + let _ = -(1f32.abs()); +} diff --git a/tests/ui/lint/negative_literals.stderr b/tests/ui/lint/negative_literals.stderr new file mode 100644 index 000000000000..df000a718825 --- /dev/null +++ b/tests/ui/lint/negative_literals.stderr @@ -0,0 +1,179 @@ +error: `-` has lower precedence than method calls, which might be unexpected + --> $DIR/negative_literals.rs:4:13 + | +LL | let _ = -1i32.abs(); + | ^^^^^^^^^^^ + | + = note: e.g. `-4.abs()` equals `-4`; while `(-4).abs()` equals `4` + = note: `#[deny(ambiguous_negative_literals)]` on by default +help: add parentheses around the `-` and the literal to call the method on a negative literal + | +LL | let _ = (-1i32).abs(); + | + + +help: add parentheses around the literal and the method call to keep the current behavior + | +LL | let _ = -(1i32.abs()); + | + + + +error: `-` has lower precedence than method calls, which might be unexpected + --> $DIR/negative_literals.rs:6:13 + | +LL | let _ = -1f32.abs(); + | ^^^^^^^^^^^ + | + = note: e.g. `-4.abs()` equals `-4`; while `(-4).abs()` equals `4` +help: add parentheses around the `-` and the literal to call the method on a negative literal + | +LL | let _ = (-1f32).abs(); + | + + +help: add parentheses around the literal and the method call to keep the current behavior + | +LL | let _ = -(1f32.abs()); + | + + + +error: `-` has lower precedence than method calls, which might be unexpected + --> $DIR/negative_literals.rs:8:13 + | +LL | let _ = -1f64.asin(); + | ^^^^^^^^^^^^ + | + = note: e.g. `-4.abs()` equals `-4`; while `(-4).abs()` equals `4` +help: add parentheses around the `-` and the literal to call the method on a negative literal + | +LL | let _ = (-1f64).asin(); + | + + +help: add parentheses around the literal and the method call to keep the current behavior + | +LL | let _ = -(1f64.asin()); + | + + + +error: `-` has lower precedence than method calls, which might be unexpected + --> $DIR/negative_literals.rs:10:13 + | +LL | let _ = -1f64.asinh(); + | ^^^^^^^^^^^^^ + | + = note: e.g. `-4.abs()` equals `-4`; while `(-4).abs()` equals `4` +help: add parentheses around the `-` and the literal to call the method on a negative literal + | +LL | let _ = (-1f64).asinh(); + | + + +help: add parentheses around the literal and the method call to keep the current behavior + | +LL | let _ = -(1f64.asinh()); + | + + + +error: `-` has lower precedence than method calls, which might be unexpected + --> $DIR/negative_literals.rs:12:13 + | +LL | let _ = -1f64.tan(); + | ^^^^^^^^^^^ + | + = note: e.g. `-4.abs()` equals `-4`; while `(-4).abs()` equals `4` +help: add parentheses around the `-` and the literal to call the method on a negative literal + | +LL | let _ = (-1f64).tan(); + | + + +help: add parentheses around the literal and the method call to keep the current behavior + | +LL | let _ = -(1f64.tan()); + | + + + +error: `-` has lower precedence than method calls, which might be unexpected + --> $DIR/negative_literals.rs:14:13 + | +LL | let _ = -1f64.tanh(); + | ^^^^^^^^^^^^ + | + = note: e.g. `-4.abs()` equals `-4`; while `(-4).abs()` equals `4` +help: add parentheses around the `-` and the literal to call the method on a negative literal + | +LL | let _ = (-1f64).tanh(); + | + + +help: add parentheses around the literal and the method call to keep the current behavior + | +LL | let _ = -(1f64.tanh()); + | + + + +error: `-` has lower precedence than method calls, which might be unexpected + --> $DIR/negative_literals.rs:16:13 + | +LL | let _ = -1.0_f64.cos().cos(); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: e.g. `-4.abs()` equals `-4`; while `(-4).abs()` equals `4` +help: add parentheses around the `-` and the literal to call the method on a negative literal + | +LL | let _ = (-1.0_f64).cos().cos(); + | + + +help: add parentheses around the literal and the method call to keep the current behavior + | +LL | let _ = -(1.0_f64.cos().cos()); + | + + + +error: `-` has lower precedence than method calls, which might be unexpected + --> $DIR/negative_literals.rs:18:13 + | +LL | let _ = -1.0_f64.cos().sin(); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: e.g. `-4.abs()` equals `-4`; while `(-4).abs()` equals `4` +help: add parentheses around the `-` and the literal to call the method on a negative literal + | +LL | let _ = (-1.0_f64).cos().sin(); + | + + +help: add parentheses around the literal and the method call to keep the current behavior + | +LL | let _ = -(1.0_f64.cos().sin()); + | + + + +error: `-` has lower precedence than method calls, which might be unexpected + --> $DIR/negative_literals.rs:20:13 + | +LL | let _ = -1.0_f64.sin().cos(); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: e.g. `-4.abs()` equals `-4`; while `(-4).abs()` equals `4` +help: add parentheses around the `-` and the literal to call the method on a negative literal + | +LL | let _ = (-1.0_f64).sin().cos(); + | + + +help: add parentheses around the literal and the method call to keep the current behavior + | +LL | let _ = -(1.0_f64.sin().cos()); + | + + + +error: `-` has lower precedence than method calls, which might be unexpected + --> $DIR/negative_literals.rs:22:13 + | +LL | let _ = -1f64.sin().sin(); + | ^^^^^^^^^^^^^^^^^ + | + = note: e.g. `-4.abs()` equals `-4`; while `(-4).abs()` equals `4` +help: add parentheses around the `-` and the literal to call the method on a negative literal + | +LL | let _ = (-1f64).sin().sin(); + | + + +help: add parentheses around the literal and the method call to keep the current behavior + | +LL | let _ = -(1f64.sin().sin()); + | + + + +error: `-` has lower precedence than method calls, which might be unexpected + --> $DIR/negative_literals.rs:25:11 + | +LL | dbg!( -1.0_f32.cos() ); + | ^^^^^^^^^^^^^^ + | + = note: e.g. `-4.abs()` equals `-4`; while `(-4).abs()` equals `4` +help: add parentheses around the `-` and the literal to call the method on a negative literal + | +LL | dbg!( (-1.0_f32).cos() ); + | + + +help: add parentheses around the literal and the method call to keep the current behavior + | +LL | dbg!( -(1.0_f32.cos()) ); + | + + + +error: aborting due to 11 previous errors + From c5e1a12efc32b4e487a8899b143909e17d864adf Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 20 Feb 2024 22:19:26 +0100 Subject: [PATCH 103/734] Remove unary neg from `clippy::precedence` lint --- .../clippy/clippy_lints/src/precedence.rs | 56 +------------------ src/tools/clippy/tests/ui/precedence.fixed | 34 ----------- src/tools/clippy/tests/ui/precedence.rs | 34 ----------- src/tools/clippy/tests/ui/precedence.stderr | 32 +---------- .../clippy/tests/ui/unnecessary_cast.fixed | 2 +- src/tools/clippy/tests/ui/unnecessary_cast.rs | 2 +- 6 files changed, 4 insertions(+), 156 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs index ff83725da691..37f5dd5583bf 100644 --- a/src/tools/clippy/clippy_lints/src/precedence.rs +++ b/src/tools/clippy/clippy_lints/src/precedence.rs @@ -1,38 +1,17 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use rustc_ast::ast::{BinOpKind, Expr, ExprKind, MethodCall, UnOp}; -use rustc_ast::token; +use rustc_ast::ast::{BinOpKind, Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; -const ALLOWED_ODD_FUNCTIONS: [&str; 14] = [ - "asin", - "asinh", - "atan", - "atanh", - "cbrt", - "fract", - "round", - "signum", - "sin", - "sinh", - "tan", - "tanh", - "to_degrees", - "to_radians", -]; - declare_clippy_lint! { /// ### What it does /// Checks for operations where precedence may be unclear /// and suggests to add parentheses. Currently it catches the following: /// * mixed usage of arithmetic and bit shifting/combining operators without /// parentheses - /// * a "negative" numeric literal (which is really a unary `-` followed by a - /// numeric literal) - /// followed by a method call /// /// ### Why is this bad? /// Not everyone knows the precedence of those operators by @@ -41,7 +20,6 @@ declare_clippy_lint! { /// /// ### Example /// * `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7 - /// * `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1 #[clippy::version = "pre 1.29.0"] pub PRECEDENCE, complexity, @@ -104,38 +82,6 @@ impl EarlyLintPass for Precedence { (false, false) => (), } } - - if let ExprKind::Unary(UnOp::Neg, operand) = &expr.kind { - let mut arg = operand; - - let mut all_odd = true; - while let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &arg.kind { - let seg_str = seg.ident.name.as_str(); - all_odd &= ALLOWED_ODD_FUNCTIONS - .iter() - .any(|odd_function| **odd_function == *seg_str); - arg = receiver; - } - - if !all_odd - && let ExprKind::Lit(lit) = &arg.kind - && let token::LitKind::Integer | token::LitKind::Float = &lit.kind - { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - PRECEDENCE, - expr.span, - "unary minus has lower precedence than method call", - "consider adding parentheses to clarify your intent", - format!( - "-({})", - snippet_with_applicability(cx, operand.span, "..", &mut applicability) - ), - applicability, - ); - } - } } } diff --git a/src/tools/clippy/tests/ui/precedence.fixed b/src/tools/clippy/tests/ui/precedence.fixed index cc87de0d90f1..c25c2062aceb 100644 --- a/src/tools/clippy/tests/ui/precedence.fixed +++ b/src/tools/clippy/tests/ui/precedence.fixed @@ -20,40 +20,6 @@ fn main() { 1 ^ (1 - 1); 3 | (2 - 1); 3 & (5 - 2); - -(1i32.abs()); - -(1f32.abs()); - - // These should not trigger an error - let _ = (-1i32).abs(); - let _ = (-1f32).abs(); - let _ = -(1i32).abs(); - let _ = -(1f32).abs(); - let _ = -(1i32.abs()); - let _ = -(1f32.abs()); - - // Odd functions should not trigger an error - let _ = -1f64.asin(); - let _ = -1f64.asinh(); - let _ = -1f64.atan(); - let _ = -1f64.atanh(); - let _ = -1f64.cbrt(); - let _ = -1f64.fract(); - let _ = -1f64.round(); - let _ = -1f64.signum(); - let _ = -1f64.sin(); - let _ = -1f64.sinh(); - let _ = -1f64.tan(); - let _ = -1f64.tanh(); - let _ = -1f64.to_degrees(); - let _ = -1f64.to_radians(); - - // Chains containing any non-odd function should trigger (issue #5924) - let _ = -(1.0_f64.cos().cos()); - let _ = -(1.0_f64.cos().sin()); - let _ = -(1.0_f64.sin().cos()); - - // Chains of odd functions shouldn't trigger - let _ = -1f64.sin().sin(); let b = 3; trip!(b * 8); diff --git a/src/tools/clippy/tests/ui/precedence.rs b/src/tools/clippy/tests/ui/precedence.rs index 00c18d92b5fb..dc242ecf4c72 100644 --- a/src/tools/clippy/tests/ui/precedence.rs +++ b/src/tools/clippy/tests/ui/precedence.rs @@ -20,40 +20,6 @@ fn main() { 1 ^ 1 - 1; 3 | 2 - 1; 3 & 5 - 2; - -1i32.abs(); - -1f32.abs(); - - // These should not trigger an error - let _ = (-1i32).abs(); - let _ = (-1f32).abs(); - let _ = -(1i32).abs(); - let _ = -(1f32).abs(); - let _ = -(1i32.abs()); - let _ = -(1f32.abs()); - - // Odd functions should not trigger an error - let _ = -1f64.asin(); - let _ = -1f64.asinh(); - let _ = -1f64.atan(); - let _ = -1f64.atanh(); - let _ = -1f64.cbrt(); - let _ = -1f64.fract(); - let _ = -1f64.round(); - let _ = -1f64.signum(); - let _ = -1f64.sin(); - let _ = -1f64.sinh(); - let _ = -1f64.tan(); - let _ = -1f64.tanh(); - let _ = -1f64.to_degrees(); - let _ = -1f64.to_radians(); - - // Chains containing any non-odd function should trigger (issue #5924) - let _ = -1.0_f64.cos().cos(); - let _ = -1.0_f64.cos().sin(); - let _ = -1.0_f64.sin().cos(); - - // Chains of odd functions shouldn't trigger - let _ = -1f64.sin().sin(); let b = 3; trip!(b * 8); diff --git a/src/tools/clippy/tests/ui/precedence.stderr b/src/tools/clippy/tests/ui/precedence.stderr index 47e61326219d..8057c25a5e49 100644 --- a/src/tools/clippy/tests/ui/precedence.stderr +++ b/src/tools/clippy/tests/ui/precedence.stderr @@ -43,35 +43,5 @@ error: operator precedence can trip the unwary LL | 3 & 5 - 2; | ^^^^^^^^^ help: consider parenthesizing your expression: `3 & (5 - 2)` -error: unary minus has lower precedence than method call - --> tests/ui/precedence.rs:23:5 - | -LL | -1i32.abs(); - | ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1i32.abs())` - -error: unary minus has lower precedence than method call - --> tests/ui/precedence.rs:24:5 - | -LL | -1f32.abs(); - | ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1f32.abs())` - -error: unary minus has lower precedence than method call - --> tests/ui/precedence.rs:51:13 - | -LL | let _ = -1.0_f64.cos().cos(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1.0_f64.cos().cos())` - -error: unary minus has lower precedence than method call - --> tests/ui/precedence.rs:52:13 - | -LL | let _ = -1.0_f64.cos().sin(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1.0_f64.cos().sin())` - -error: unary minus has lower precedence than method call - --> tests/ui/precedence.rs:53:13 - | -LL | let _ = -1.0_f64.sin().cos(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1.0_f64.sin().cos())` - -error: aborting due to 12 previous errors +error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.fixed b/src/tools/clippy/tests/ui/unnecessary_cast.fixed index 288541362cdd..c43e50761bd5 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_cast.fixed @@ -206,7 +206,7 @@ mod fixable { fn issue_9563() { let _: f64 = (-8.0_f64).exp(); - #[allow(clippy::precedence)] + #[allow(ambiguous_negative_literals)] let _: f64 = -8.0_f64.exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior } diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.rs b/src/tools/clippy/tests/ui/unnecessary_cast.rs index eef3a42e3514..4a5ca231315e 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.rs +++ b/src/tools/clippy/tests/ui/unnecessary_cast.rs @@ -206,7 +206,7 @@ mod fixable { fn issue_9563() { let _: f64 = (-8.0 as f64).exp(); - #[allow(clippy::precedence)] + #[allow(ambiguous_negative_literals)] let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior } From de88bc5c8921774681ecac0a5249b370a9768a6c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 10 Jul 2024 18:06:44 -0400 Subject: [PATCH 104/734] And additionally enforce ? and async/const aren't mixed --- compiler/rustc_ast_passes/messages.ftl | 2 - .../rustc_ast_passes/src/ast_validation.rs | 11 ----- compiler/rustc_ast_passes/src/errors.rs | 9 ---- compiler/rustc_parse/messages.ftl | 3 ++ compiler/rustc_parse/src/errors.rs | 11 +++++ compiler/rustc_parse/src/parser/ty.rs | 29 ++++++++++++ tests/ui/parser/bounds-type.rs | 13 +++++- tests/ui/parser/bounds-type.stderr | 46 +++++++++++++++++-- ...utually-exclusive-trait-bound-modifiers.rs | 8 ++-- ...lly-exclusive-trait-bound-modifiers.stderr | 32 ++++++++----- 10 files changed, 120 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 7da726ef4086..0408f6ad5435 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -152,8 +152,6 @@ ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed .help = remove one of these features -ast_passes_incompatible_trait_bound_modifiers = `{$left}` and `{$right}` are mutually exclusive - ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation} .because = {$annotation} because of this .type = inherent impl for this type diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index dd0d904c52cc..8041b89abe25 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1435,17 +1435,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }; self.dcx().emit_err(errors::TildeConstDisallowed { span, reason }); } - ( - _, - BoundConstness::Always(_) | BoundConstness::Maybe(_), - BoundPolarity::Negative(_) | BoundPolarity::Maybe(_), - ) => { - self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers { - span: bound.span(), - left: modifiers.constness.as_str(), - right: modifiers.polarity.as_str(), - }); - } _ => {} } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index bfb904764501..51f80b9ad4ac 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -657,15 +657,6 @@ pub enum TildeConstReason { Item, } -#[derive(Diagnostic)] -#[diag(ast_passes_incompatible_trait_bound_modifiers)] -pub struct IncompatibleTraitBoundModifiers { - #[primary_span] - pub span: Span, - pub left: &'static str, - pub right: &'static str, -} - #[derive(Diagnostic)] #[diag(ast_passes_const_and_async)] pub struct ConstAndAsync { diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 5b4a5f4dd38e..f0cdb6c63a49 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -575,6 +575,9 @@ parse_missing_trait_in_trait_impl = missing trait in a trait impl parse_modifier_lifetime = `{$modifier}` may only modify trait bounds, not lifetime bounds .suggestion = remove the `{$modifier}` +parse_modifiers_and_polarity = `{$modifiers_concatenated}` trait not allowed with `{$polarity}` trait polarity modifier + .label = there is not a well-defined meaning for a `{$modifiers_concatenated} {$polarity}` trait + parse_more_than_one_char = character literal may only contain one codepoint .followed_by = this `{$chr}` is followed by the combining {$len -> [one] mark diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 9b18a771fdea..75417885d2af 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3060,3 +3060,14 @@ pub struct BinderAndPolarity { pub binder_span: Span, pub polarity: &'static str, } + +#[derive(Diagnostic)] +#[diag(parse_modifiers_and_polarity)] +pub struct PolarityAndModifiers { + #[primary_span] + pub polarity_span: Span, + #[label] + pub modifiers_span: Span, + pub polarity: &'static str, + pub modifiers_concatenated: String, +} diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 6de778fa9f21..a2db4b6feef7 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -930,6 +930,7 @@ impl<'a> Parser<'a> { /// TRAIT_BOUND_MODIFIERS = [["~"] "const"] ["async"] ["?" | "!"] /// ``` fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> { + let modifier_lo = self.token.span; let constness = if self.eat(&token::Tilde) { let tilde = self.prev_token.span; self.expect_keyword(kw::Const)?; @@ -962,6 +963,7 @@ impl<'a> Parser<'a> { } else { BoundAsyncness::Normal }; + let modifier_hi = self.prev_token.span; let polarity = if self.eat(&token::Question) { BoundPolarity::Maybe(self.prev_token.span) @@ -972,6 +974,33 @@ impl<'a> Parser<'a> { BoundPolarity::Positive }; + // Enforce the mutual-exclusivity of `const`/`async` and `?`/`!`. + match polarity { + BoundPolarity::Positive => { + // All trait bound modifiers allowed to combine with positive polarity + } + BoundPolarity::Maybe(polarity_span) | BoundPolarity::Negative(polarity_span) => { + match (asyncness, constness) { + (BoundAsyncness::Normal, BoundConstness::Never) => { + // Ok, no modifiers. + } + (_, _) => { + let constness = constness.as_str(); + let asyncness = asyncness.as_str(); + let glue = + if !constness.is_empty() && !asyncness.is_empty() { " " } else { "" }; + let modifiers_concatenated = format!("{constness}{glue}{asyncness}"); + self.dcx().emit_err(errors::PolarityAndModifiers { + polarity_span, + polarity: polarity.as_str(), + modifiers_span: modifier_lo.to(modifier_hi), + modifiers_concatenated, + }); + } + } + } + } + Ok(TraitBoundModifiers { constness, asyncness, polarity }) } diff --git a/tests/ui/parser/bounds-type.rs b/tests/ui/parser/bounds-type.rs index 47fec7b1e77f..7cee6def32f8 100644 --- a/tests/ui/parser/bounds-type.rs +++ b/tests/ui/parser/bounds-type.rs @@ -1,4 +1,5 @@ //@ compile-flags: -Z parse-only +//@ edition: 2021 struct S< T: 'a + Tr, // OK @@ -10,10 +11,20 @@ struct S< T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds T: ~const Tr, // OK - T: ~const ?Tr, // OK + T: ~const ?Tr, //~ ERROR `~const` trait not allowed with `?` trait polarity modifier T: ~const Tr + 'a, // OK T: ~const 'a, //~ ERROR `~const` may only modify trait bounds, not lifetime bounds T: const 'a, //~ ERROR `const` may only modify trait bounds, not lifetime bounds + + T: async Tr, // OK + T: async ?Tr, //~ ERROR `async` trait not allowed with `?` trait polarity modifier + T: async Tr + 'a, // OK + T: async 'a, //~ ERROR `async` may only modify trait bounds, not lifetime bounds + + T: const async Tr, // OK + T: const async ?Tr, //~ ERROR `const async` trait not allowed with `?` trait polarity modifier + T: const async Tr + 'a, // OK + T: const async 'a, //~ ERROR `const` may only modify trait bounds, not lifetime bounds >; fn main() {} diff --git a/tests/ui/parser/bounds-type.stderr b/tests/ui/parser/bounds-type.stderr index fa8ab6812b15..09c35c12b000 100644 --- a/tests/ui/parser/bounds-type.stderr +++ b/tests/ui/parser/bounds-type.stderr @@ -1,5 +1,5 @@ error: `for<...>` binder not allowed with `?` trait polarity modifier - --> $DIR/bounds-type.rs:8:16 + --> $DIR/bounds-type.rs:9:16 | LL | T: for<'a> ?Trait, | ---- ^ @@ -7,22 +7,58 @@ LL | T: for<'a> ?Trait, | there is not a well-defined meaning for a higher-ranked `?` trait error: `?` may only modify trait bounds, not lifetime bounds - --> $DIR/bounds-type.rs:10:8 + --> $DIR/bounds-type.rs:11:8 | LL | T: ?'a, | ^ +error: `~const` trait not allowed with `?` trait polarity modifier + --> $DIR/bounds-type.rs:14:15 + | +LL | T: ~const ?Tr, + | ------ ^ + | | + | there is not a well-defined meaning for a `~const ?` trait + error: `~const` may only modify trait bounds, not lifetime bounds - --> $DIR/bounds-type.rs:15:8 + --> $DIR/bounds-type.rs:16:8 | LL | T: ~const 'a, | ^^^^^^ error: `const` may only modify trait bounds, not lifetime bounds - --> $DIR/bounds-type.rs:16:8 + --> $DIR/bounds-type.rs:17:8 | LL | T: const 'a, | ^^^^^ -error: aborting due to 4 previous errors +error: `async` trait not allowed with `?` trait polarity modifier + --> $DIR/bounds-type.rs:20:14 + | +LL | T: async ?Tr, + | ----- ^ + | | + | there is not a well-defined meaning for a `async ?` trait + +error: `async` may only modify trait bounds, not lifetime bounds + --> $DIR/bounds-type.rs:22:8 + | +LL | T: async 'a, + | ^^^^^ + +error: `const async` trait not allowed with `?` trait polarity modifier + --> $DIR/bounds-type.rs:25:20 + | +LL | T: const async ?Tr, + | ----------- ^ + | | + | there is not a well-defined meaning for a `const async ?` trait + +error: `const` may only modify trait bounds, not lifetime bounds + --> $DIR/bounds-type.rs:27:8 + | +LL | T: const async 'a, + | ^^^^^ + +error: aborting due to 9 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs index 37e285f2c659..aaab8e819a39 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs @@ -1,17 +1,17 @@ #![feature(const_trait_impl)] const fn maybe_const_maybe() {} -//~^ ERROR `~const` and `?` are mutually exclusive +//~^ ERROR `~const` trait not allowed with `?` trait polarity modifier fn const_maybe() {} -//~^ ERROR `const` and `?` are mutually exclusive +//~^ ERROR `const` trait not allowed with `?` trait polarity modifier const fn maybe_const_negative() {} -//~^ ERROR `~const` and `!` are mutually exclusive +//~^ ERROR `~const` trait not allowed with `!` trait polarity modifier //~| ERROR negative bounds are not supported fn const_negative() {} -//~^ ERROR `const` and `!` are mutually exclusive +//~^ ERROR `const` trait not allowed with `!` trait polarity modifier //~| ERROR negative bounds are not supported #[const_trait] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr index 1938f740170b..18e4d160f5f4 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr @@ -1,26 +1,34 @@ -error: `~const` and `?` are mutually exclusive - --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:3:31 +error: `~const` trait not allowed with `?` trait polarity modifier + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:3:38 | LL | const fn maybe_const_maybe() {} - | ^^^^^^^^^^^^^ + | ------ ^ + | | + | there is not a well-defined meaning for a `~const ?` trait -error: `const` and `?` are mutually exclusive - --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:6:19 +error: `const` trait not allowed with `?` trait polarity modifier + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:6:25 | LL | fn const_maybe() {} - | ^^^^^^^^^^^^ + | ----- ^ + | | + | there is not a well-defined meaning for a `const ?` trait -error: `~const` and `!` are mutually exclusive - --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:34 +error: `~const` trait not allowed with `!` trait polarity modifier + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:41 | LL | const fn maybe_const_negative() {} - | ^^^^^^^^^^^^^ + | ------ ^ + | | + | there is not a well-defined meaning for a `~const !` trait -error: `const` and `!` are mutually exclusive - --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:22 +error: `const` trait not allowed with `!` trait polarity modifier + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:28 | LL | fn const_negative() {} - | ^^^^^^^^^^^^ + | ----- ^ + | | + | there is not a well-defined meaning for a `const !` trait error: negative bounds are not supported --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:41 From c1fd25d0aa56c27f1e8dd6fe00981eefba0d2e11 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 11 Jul 2024 15:44:03 +0200 Subject: [PATCH 105/734] Merge commit 'b794b8e08c16517a941dc598bb1483e8e12a8592' into clippy-subtree-update --- .github/workflows/lintcheck.yml | 4 +- CHANGELOG.md | 6 + book/src/lint_configuration.md | 3 +- clippy.toml | 4 + clippy_config/src/conf.rs | 3 +- clippy_config/src/msrvs.rs | 4 +- clippy_dev/src/new_lint.rs | 4 +- clippy_lints/src/almost_complete_range.rs | 104 +-- clippy_lints/src/assertions_on_constants.rs | 20 +- clippy_lints/src/assigning_clones.rs | 500 ++++++--------- clippy_lints/src/await_holding_invalid.rs | 46 +- clippy_lints/src/bool_to_int_with_if.rs | 134 ++-- clippy_lints/src/byte_char_slices.rs | 80 +++ clippy_lints/src/casts/mod.rs | 113 ++-- clippy_lints/src/casts/ptr_as_ptr.rs | 2 +- clippy_lints/src/cfg_not_test.rs | 60 ++ clippy_lints/src/declared_lints.rs | 10 +- clippy_lints/src/default.rs | 10 +- clippy_lints/src/default_numeric_fallback.rs | 2 + clippy_lints/src/dereference.rs | 37 +- clippy_lints/src/disallowed_methods.rs | 42 +- clippy_lints/src/disallowed_names.rs | 46 +- clippy_lints/src/disallowed_script_idents.rs | 41 +- clippy_lints/src/doc/lazy_continuation.rs | 29 +- clippy_lints/src/doc/mod.rs | 21 +- clippy_lints/src/endian_bytes.rs | 4 +- .../src/functions/impl_trait_in_params.rs | 8 +- clippy_lints/src/incompatible_msrv.rs | 4 +- clippy_lints/src/inherent_to_string.rs | 5 +- clippy_lints/src/init_numbered_fields.rs | 87 +-- clippy_lints/src/inline_fn_without_body.rs | 41 +- clippy_lints/src/instant_subtraction.rs | 21 +- clippy_lints/src/items_after_statements.rs | 59 +- .../src/iter_not_returning_iterator.rs | 21 +- clippy_lints/src/iter_without_into_iter.rs | 4 +- clippy_lints/src/large_const_arrays.rs | 4 +- clippy_lints/src/large_enum_variant.rs | 17 +- clippy_lints/src/large_futures.rs | 43 +- clippy_lints/src/large_include_file.rs | 20 +- clippy_lints/src/legacy_numeric_constants.rs | 46 +- clippy_lints/src/len_zero.rs | 19 +- clippy_lints/src/let_if_seq.rs | 8 +- clippy_lints/src/let_underscore.rs | 2 +- clippy_lints/src/let_with_type_underscore.rs | 17 +- clippy_lints/src/lib.rs | 24 +- clippy_lints/src/literal_representation.rs | 16 +- clippy_lints/src/manual_bits.rs | 5 +- clippy_lints/src/manual_float_methods.rs | 29 +- clippy_lints/src/manual_let_else.rs | 6 +- clippy_lints/src/manual_main_separator_str.rs | 8 +- clippy_lints/src/manual_non_exhaustive.rs | 14 +- clippy_lints/src/manual_range_patterns.rs | 5 +- clippy_lints/src/manual_rem_euclid.rs | 49 +- clippy_lints/src/manual_retain.rs | 3 +- clippy_lints/src/manual_rotate.rs | 117 ++++ .../src/manual_slice_size_calculation.rs | 6 +- clippy_lints/src/manual_strip.rs | 7 +- clippy_lints/src/manual_unwrap_or_default.rs | 9 +- clippy_lints/src/map_unit_fn.rs | 13 +- clippy_lints/src/matches/mod.rs | 13 +- .../matches/significant_drop_in_scrutinee.rs | 111 +++- clippy_lints/src/methods/manual_inspect.rs | 26 +- clippy_lints/src/methods/mod.rs | 9 +- .../src/methods/unnecessary_to_owned.rs | 70 ++- .../src/methods/unwrap_expect_used.rs | 4 +- clippy_lints/src/minmax.rs | 37 +- clippy_lints/src/misc.rs | 6 +- clippy_lints/src/missing_assert_message.rs | 4 +- clippy_lints/src/missing_const_for_fn.rs | 33 +- ...t.rs => missing_const_for_thread_local.rs} | 14 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 11 +- clippy_lints/src/no_effect.rs | 11 +- clippy_lints/src/operators/float_cmp.rs | 1 - clippy_lints/src/operators/mod.rs | 144 +++-- .../src/overflow_check_conditional.rs | 70 --- clippy_lints/src/panicking_overflow_checks.rs | 86 +++ clippy_lints/src/renamed_lints.rs | 2 + clippy_lints/src/returns.rs | 47 +- clippy_lints/src/same_name_method.rs | 2 +- clippy_lints/src/set_contains_or_insert.rs | 125 ++++ clippy_lints/src/utils/internal_lints.rs | 1 - .../internal_lints/compiler_lint_functions.rs | 73 --- clippy_lints/src/wildcard_imports.rs | 19 +- clippy_lints/src/write.rs | 5 +- clippy_utils/src/lib.rs | 67 +- clippy_utils/src/paths.rs | 1 + clippy_utils/src/ty.rs | 26 +- lintcheck/Cargo.toml | 1 + lintcheck/README.md | 16 +- lintcheck/lintcheck_crates.toml | 52 +- lintcheck/src/config.rs | 4 + lintcheck/src/driver.rs | 2 - lintcheck/src/input.rs | 288 +++++++++ lintcheck/src/json.rs | 101 ++- lintcheck/src/main.rs | 595 ++---------------- lintcheck/src/output.rs | 235 +++++++ lintcheck/src/popular_crates.rs | 2 +- lintcheck/src/recursive.rs | 7 +- rust-toolchain | 3 +- tests/ui-internal/disallow_span_lint.stderr | 16 +- .../await_holding_invalid_type.stderr | 6 +- .../needless_pass_by_ref_mut/clippy.toml | 1 + .../needless_pass_by_ref_mut.fixed | 10 + .../needless_pass_by_ref_mut.rs | 10 + .../needless_pass_by_ref_mut.stderr | 12 + .../conf_disallowed_methods.stderr | 36 +- tests/ui/assertions_on_constants.rs | 11 +- tests/ui/assertions_on_constants.stderr | 18 +- tests/ui/await_holding_lock.rs | 26 +- tests/ui/await_holding_lock.stderr | 78 +-- tests/ui/await_holding_refcell_ref.rs | 12 +- tests/ui/await_holding_refcell_ref.stderr | 24 +- tests/ui/byte_char_slices.fixed | 13 + tests/ui/byte_char_slices.rs | 13 + tests/ui/byte_char_slices.stderr | 38 ++ tests/ui/cfg_not_test.rs | 32 + tests/ui/cfg_not_test.stderr | 45 ++ tests/ui/crashes/ice-12616.stderr | 2 +- tests/ui/disallowed_names.rs | 1 + tests/ui/doc/doc_lazy_blank_line.fixed | 47 ++ tests/ui/doc/doc_lazy_blank_line.rs | 43 ++ tests/ui/doc/doc_lazy_blank_line.stderr | 56 ++ tests/ui/doc/doc_lazy_blockquote.fixed | 12 +- tests/ui/doc/doc_lazy_blockquote.rs | 12 +- tests/ui/doc/doc_lazy_blockquote.stderr | 12 +- tests/ui/doc/doc_lazy_list.fixed | 31 +- tests/ui/doc/doc_lazy_list.rs | 22 +- tests/ui/doc/doc_lazy_list.stderr | 49 +- tests/ui/doc/unbalanced_ticks.rs | 17 + tests/ui/doc/unbalanced_ticks.stderr | 18 +- tests/ui/explicit_auto_deref.fixed | 36 ++ tests/ui/explicit_auto_deref.rs | 36 ++ tests/ui/explicit_auto_deref.stderr | 8 +- tests/ui/float_cmp.rs | 6 - tests/ui/float_cmp.stderr | 21 +- tests/ui/float_cmp_const.rs | 8 - tests/ui/float_cmp_const.stderr | 39 +- ...ields.fixed => init_numbered_fields.fixed} | 9 + ...ered_fields.rs => init_numbered_fields.rs} | 9 + ...lds.stderr => init_numbered_fields.stderr} | 12 +- tests/ui/into_iter_without_iter.rs | 39 ++ tests/ui/iter_next_loop.rs | 2 +- tests/ui/iter_next_loop.stderr | 10 +- tests/ui/manual_inspect.stderr | 24 +- tests/ui/manual_rotate.fixed | 31 + tests/ui/manual_rotate.rs | 31 + tests/ui/manual_rotate.stderr | 71 +++ .../ui/missing_const_for_fn/cant_be_const.rs | 18 + .../missing_const_for_fn/could_be_const.fixed | 30 + .../ui/missing_const_for_fn/could_be_const.rs | 30 + .../could_be_const.stderr | 41 +- .../could_be_const_with_const_extern_fn.fixed | 14 + .../could_be_const_with_const_extern_fn.rs | 14 + ...could_be_const_with_const_extern_fn.stderr | 59 ++ ...d => missing_const_for_thread_local.fixed} | 2 +- ...t.rs => missing_const_for_thread_local.rs} | 2 +- ... => missing_const_for_thread_local.stderr} | 16 +- tests/ui/needless_pass_by_ref_mut.rs | 18 +- tests/ui/needless_pass_by_ref_mut.stderr | 52 +- tests/ui/needless_pass_by_ref_mut2.fixed | 4 +- tests/ui/needless_pass_by_ref_mut2.rs | 4 +- tests/ui/needless_pass_by_ref_mut2.stderr | 15 +- tests/ui/needless_return.fixed | 35 +- tests/ui/needless_return.rs | 35 +- tests/ui/needless_return.stderr | 28 +- tests/ui/overflow_check_conditional.rs | 36 -- tests/ui/overflow_check_conditional.stderr | 53 -- tests/ui/panicking_overflow_checks.rs | 27 + tests/ui/panicking_overflow_checks.stderr | 41 ++ tests/ui/ptr_as_ptr.stderr | 66 +- tests/ui/rename.fixed | 4 + tests/ui/rename.rs | 4 + tests/ui/rename.stderr | 130 ++-- tests/ui/set_contains_or_insert.rs | 83 +++ tests/ui/set_contains_or_insert.stderr | 61 ++ tests/ui/significant_drop_in_scrutinee.rs | 26 + tests/ui/significant_drop_in_scrutinee.stderr | 29 +- tests/ui/unnecessary_operation.fixed | 14 +- tests/ui/unnecessary_operation.rs | 14 +- tests/ui/unnecessary_operation.stderr | 8 +- tests/ui/unnecessary_to_owned.fixed | 19 + tests/ui/unnecessary_to_owned.rs | 19 + tests/ui/unnecessary_to_owned.stderr | 60 +- tests/ui/wildcard_imports.fixed | 3 + tests/ui/wildcard_imports.rs | 3 + tests/ui/wildcard_imports.stderr | 10 +- .../wildcard_imports_2021.edition2018.fixed | 3 + .../wildcard_imports_2021.edition2018.stderr | 10 +- .../wildcard_imports_2021.edition2021.fixed | 3 + .../wildcard_imports_2021.edition2021.stderr | 10 +- tests/ui/wildcard_imports_2021.rs | 3 + 191 files changed, 4157 insertions(+), 2504 deletions(-) create mode 100644 clippy_lints/src/byte_char_slices.rs create mode 100644 clippy_lints/src/cfg_not_test.rs create mode 100644 clippy_lints/src/manual_rotate.rs rename clippy_lints/src/{thread_local_initializer_can_be_made_const.rs => missing_const_for_thread_local.rs} (92%) delete mode 100644 clippy_lints/src/overflow_check_conditional.rs create mode 100644 clippy_lints/src/panicking_overflow_checks.rs create mode 100644 clippy_lints/src/set_contains_or_insert.rs delete mode 100644 clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs create mode 100644 lintcheck/src/input.rs create mode 100644 lintcheck/src/output.rs create mode 100644 tests/ui-toml/needless_pass_by_ref_mut/clippy.toml create mode 100644 tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed create mode 100644 tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs create mode 100644 tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr create mode 100644 tests/ui/byte_char_slices.fixed create mode 100644 tests/ui/byte_char_slices.rs create mode 100644 tests/ui/byte_char_slices.stderr create mode 100644 tests/ui/cfg_not_test.rs create mode 100644 tests/ui/cfg_not_test.stderr create mode 100644 tests/ui/doc/doc_lazy_blank_line.fixed create mode 100644 tests/ui/doc/doc_lazy_blank_line.rs create mode 100644 tests/ui/doc/doc_lazy_blank_line.stderr rename tests/ui/{numbered_fields.fixed => init_numbered_fields.fixed} (82%) rename tests/ui/{numbered_fields.rs => init_numbered_fields.rs} (84%) rename tests/ui/{numbered_fields.stderr => init_numbered_fields.stderr} (63%) create mode 100644 tests/ui/manual_rotate.fixed create mode 100644 tests/ui/manual_rotate.rs create mode 100644 tests/ui/manual_rotate.stderr create mode 100644 tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed create mode 100644 tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs create mode 100644 tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr rename tests/ui/{thread_local_initializer_can_be_made_const.fixed => missing_const_for_thread_local.fixed} (97%) rename tests/ui/{thread_local_initializer_can_be_made_const.rs => missing_const_for_thread_local.rs} (97%) rename tests/ui/{thread_local_initializer_can_be_made_const.stderr => missing_const_for_thread_local.stderr} (72%) delete mode 100644 tests/ui/overflow_check_conditional.rs delete mode 100644 tests/ui/overflow_check_conditional.stderr create mode 100644 tests/ui/panicking_overflow_checks.rs create mode 100644 tests/ui/panicking_overflow_checks.stderr create mode 100644 tests/ui/set_contains_or_insert.rs create mode 100644 tests/ui/set_contains_or_insert.stderr diff --git a/.github/workflows/lintcheck.yml b/.github/workflows/lintcheck.yml index 91c98b3a2560..f016a7700592 100644 --- a/.github/workflows/lintcheck.yml +++ b/.github/workflows/lintcheck.yml @@ -58,7 +58,7 @@ jobs: - name: Run lintcheck if: steps.cache-json.outputs.cache-hit != 'true' - run: ./target/debug/lintcheck --format json + run: ./target/debug/lintcheck --format json --warn-all - name: Upload base JSON uses: actions/upload-artifact@v4 @@ -86,7 +86,7 @@ jobs: run: cargo build --manifest-path=lintcheck/Cargo.toml - name: Run lintcheck - run: ./target/debug/lintcheck --format json + run: ./target/debug/lintcheck --format json --warn-all - name: Upload head JSON uses: actions/upload-artifact@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 70ef2c793640..55281f3cbec0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5236,6 +5236,7 @@ Released 2018-09-13 [`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local [`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code [`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow +[`byte_char_slices`]: https://rust-lang.github.io/rust-clippy/master/index.html#byte_char_slices [`bytes_count_to_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_count_to_len [`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth [`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata @@ -5253,6 +5254,7 @@ Released 2018-09-13 [`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss [`cast_slice_different_sizes`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_different_sizes [`cast_slice_from_raw_parts`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_from_raw_parts +[`cfg_not_test`]: https://rust-lang.github.io/rust-clippy/master/index.html#cfg_not_test [`char_lit_as_u8`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8 [`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp [`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp @@ -5539,6 +5541,7 @@ Released 2018-09-13 [`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns [`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid [`manual_retain`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain +[`manual_rotate`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rotate [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic [`manual_slice_size_calculation`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_size_calculation [`manual_split_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once @@ -5587,6 +5590,7 @@ Released 2018-09-13 [`missing_assert_message`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_assert_message [`missing_asserts_for_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_asserts_for_indexing [`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn +[`missing_const_for_thread_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_thread_local [`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items [`missing_enforced_import_renames`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames [`missing_errors_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc @@ -5701,6 +5705,7 @@ Released 2018-09-13 [`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic [`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn [`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params +[`panicking_overflow_checks`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_overflow_checks [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap [`partial_pub_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#partial_pub_fields [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl @@ -5797,6 +5802,7 @@ Released 2018-09-13 [`semicolon_outside_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block [`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse +[`set_contains_or_insert`]: https://rust-lang.github.io/rust-clippy/master/index.html#set_contains_or_insert [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse [`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same [`shadow_unrelated`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index cfd34c7d2a7d..ad29339a84ad 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -348,6 +348,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat * [`enum_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names) * [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) * [`linkedlist`](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist) +* [`needless_pass_by_ref_mut`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut) * [`option_option`](https://rust-lang.github.io/rust-clippy/master/index.html#option_option) * [`rc_buffer`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer) * [`rc_mutex`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex) @@ -454,7 +455,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` --- **Affected lints:** diff --git a/clippy.toml b/clippy.toml index 62ed55beb1f3..319b72e8c5d5 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1,5 +1,9 @@ avoid-breaking-exported-api = false +[[disallowed-methods]] +path = "rustc_lint::context::LintContext::lint" +reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead" + [[disallowed-methods]] path = "rustc_lint::context::LintContext::span_lint" reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead" diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index dbab3b106a80..7f53aad67933 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -31,6 +31,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", + "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", @@ -262,7 +263,7 @@ define_Conf! { /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] /// ``` (arithmetic_side_effects_allowed_unary: FxHashSet = <_>::default()), - /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN. + /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN, NEEDLESS_PASS_BY_REF_MUT. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index a5761d3270cd..fc56ac517968 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -25,8 +25,8 @@ msrv_aliases! { 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } 1,63,0 { CLONE_INTO } - 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } - 1,59,0 { THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST } + 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_FN } + 1,59,0 { THREAD_LOCAL_CONST_INIT } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF } 1,56,0 { CONST_FN_UNION } 1,55,0 { SEEK_REWIND } diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 2e56eb8ec15f..d762e30ef02e 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -273,7 +273,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { result.push_str(&if enable_msrv { formatdoc!( r#" - use clippy_utils::msrvs::{{self, Msrv}}; + use clippy_config::msrvs::{{self, Msrv}}; {pass_import} use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; use rustc_session::impl_lint_pass; @@ -399,7 +399,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R let _: fmt::Result = writedoc!( lint_file_contents, r#" - use clippy_utils::msrvs::{{self, Msrv}}; + use clippy_config::msrvs::{{self, Msrv}}; use rustc_lint::{{{context_import}, LintContext}}; use super::{name_upper}; diff --git a/clippy_lints/src/almost_complete_range.rs b/clippy_lints/src/almost_complete_range.rs index 57a5cd8fba81..96e9c949b750 100644 --- a/clippy_lints/src/almost_complete_range.rs +++ b/clippy_lints/src/almost_complete_range.rs @@ -6,7 +6,6 @@ use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -41,61 +40,80 @@ impl AlmostCompleteRange { } impl EarlyLintPass for AlmostCompleteRange { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { - if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind { - let ctxt = e.span.ctxt(); - let sugg = if let Some(start) = walk_span_to_context(start.span, ctxt) - && let Some(end) = walk_span_to_context(end.span, ctxt) - && self.msrv.meets(msrvs::RANGE_INCLUSIVE) - { - Some((trim_span(cx.sess().source_map(), start.between(end)), "..=")) - } else { - None - }; - check_range(cx, e.span, start, end, sugg); + if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind + && is_incomplete_range(start, end) + && !in_external_macro(cx.sess(), e.span) + { + span_lint_and_then( + cx, + ALMOST_COMPLETE_RANGE, + e.span, + "almost complete ascii range", + |diag| { + let ctxt = e.span.ctxt(); + if let Some(start) = walk_span_to_context(start.span, ctxt) + && let Some(end) = walk_span_to_context(end.span, ctxt) + && self.msrv.meets(msrvs::RANGE_INCLUSIVE) + { + diag.span_suggestion( + trim_span(cx.sess().source_map(), start.between(end)), + "use an inclusive range", + "..=".to_owned(), + Applicability::MaybeIncorrect, + ); + } + }, + ); } } fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &Pat) { if let PatKind::Range(Some(start), Some(end), kind) = &p.kind && matches!(kind.node, RangeEnd::Excluded) + && is_incomplete_range(start, end) + && !in_external_macro(cx.sess(), p.span) { - let sugg = if self.msrv.meets(msrvs::RANGE_INCLUSIVE) { - "..=" - } else { - "..." - }; - check_range(cx, p.span, start, end, Some((kind.span, sugg))); + span_lint_and_then( + cx, + ALMOST_COMPLETE_RANGE, + p.span, + "almost complete ascii range", + |diag| { + diag.span_suggestion( + kind.span, + "use an inclusive range", + if self.msrv.meets(msrvs::RANGE_INCLUSIVE) { + "..=".to_owned() + } else { + "...".to_owned() + }, + Applicability::MaybeIncorrect, + ); + }, + ); } } extract_msrv_attr!(EarlyContext); } -fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg: Option<(Span, &str)>) { - if let ExprKind::Lit(start_token_lit) = start.peel_parens().kind - && let ExprKind::Lit(end_token_lit) = end.peel_parens().kind - && matches!( - ( - LitKind::from_token_lit(start_token_lit), - LitKind::from_token_lit(end_token_lit), - ), - ( - Ok(LitKind::Byte(b'a') | LitKind::Char('a')), - Ok(LitKind::Byte(b'z') | LitKind::Char('z')) - ) | ( - Ok(LitKind::Byte(b'A') | LitKind::Char('A')), - Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')), - ) | ( - Ok(LitKind::Byte(b'0') | LitKind::Char('0')), - Ok(LitKind::Byte(b'9') | LitKind::Char('9')), +fn is_incomplete_range(start: &Expr, end: &Expr) -> bool { + match (&start.peel_parens().kind, &end.peel_parens().kind) { + (&ExprKind::Lit(start_lit), &ExprKind::Lit(end_lit)) => { + matches!( + (LitKind::from_token_lit(start_lit), LitKind::from_token_lit(end_lit),), + ( + Ok(LitKind::Byte(b'a') | LitKind::Char('a')), + Ok(LitKind::Byte(b'z') | LitKind::Char('z')) + ) | ( + Ok(LitKind::Byte(b'A') | LitKind::Char('A')), + Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')), + ) | ( + Ok(LitKind::Byte(b'0') | LitKind::Char('0')), + Ok(LitKind::Byte(b'9') | LitKind::Char('9')), + ) ) - ) - && !in_external_macro(cx.sess(), span) - { - span_lint_and_then(cx, ALMOST_COMPLETE_RANGE, span, "almost complete ascii range", |diag| { - if let Some((span, sugg)) = sugg { - diag.span_suggestion(span, "use an inclusive range", sugg, Applicability::MaybeIncorrect); - } - }); + }, + _ => false, } } diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 2003dd1fb0e2..ed4cdce8cb88 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -1,7 +1,8 @@ -use clippy_utils::consts::{constant_with_source, Constant, ConstantSource}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_inside_always_const_context; use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn}; -use rustc_hir::{Expr, Item, ItemKind, Node}; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::sym; @@ -42,17 +43,16 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else { return; }; - let Some((Constant::Bool(val), source)) = constant_with_source(cx, cx.typeck_results(), condition) else { + let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else { return; }; - if let ConstantSource::Constant = source - && let Node::Item(Item { - kind: ItemKind::Const(..), - .. - }) = cx.tcx.parent_hir_node(e.hir_id) - { - return; + + match condition.kind { + ExprKind::Path(..) | ExprKind::Lit(_) => {}, + _ if is_inside_always_const_context(cx.tcx, e.hir_id) => return, + _ => {}, } + if val { span_lint_and_help( cx, diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index 406f38f411ec..0de0031ed24f 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -1,18 +1,16 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::macros::HirNode; use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap}; use clippy_utils::sugg::Sugg; -use clippy_utils::{is_trait_method, local_is_initialized, path_to_local}; +use clippy_utils::{is_diag_trait_item, last_path_segment, local_is_initialized, path_to_local}; use rustc_errors::Applicability; use rustc_hir::{self as hir, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir; use rustc_middle::ty::{self, Instance, Mutability}; use rustc_session::impl_lint_pass; -use rustc_span::def_id::DefId; use rustc_span::symbol::sym; -use rustc_span::{ExpnKind, Span, SyntaxContext}; +use rustc_span::{Span, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -68,167 +66,84 @@ impl AssigningClones { impl_lint_pass!(AssigningClones => [ASSIGNING_CLONES]); impl<'tcx> LateLintPass<'tcx> for AssigningClones { - fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx Expr<'_>) { - // Do not fire the lint in macros - let ctxt = assign_expr.span().ctxt(); - let expn_data = ctxt.outer_expn_data(); - match expn_data.kind { - ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) | ExpnKind::Macro(..) => return, - ExpnKind::Root => {}, - } - - let ExprKind::Assign(lhs, rhs, _span) = assign_expr.kind else { - return; - }; - - let Some(call) = extract_call(cx, rhs) else { - return; - }; - - if is_ok_to_suggest(cx, lhs, &call, &self.msrv) { - suggest(cx, ctxt, assign_expr, lhs, &call); + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + if let ExprKind::Assign(lhs, rhs, _) = e.kind + && let typeck = cx.typeck_results() + && let (call_kind, fn_name, fn_id, fn_arg, fn_gen_args) = match rhs.kind { + ExprKind::Call(f, [arg]) + if let ExprKind::Path(fn_path) = &f.kind + && let Some(id) = typeck.qpath_res(fn_path, f.hir_id).opt_def_id() => + { + (CallKind::Ufcs, last_path_segment(fn_path).ident.name, id, arg, typeck.node_args(f.hir_id)) + }, + ExprKind::MethodCall(name, recv, [], _) if let Some(id) = typeck.type_dependent_def_id(rhs.hir_id) => { + (CallKind::Method, name.ident.name, id, recv, typeck.node_args(rhs.hir_id)) + }, + _ => return, + } + && let ctxt = e.span.ctxt() + // Don't lint in macros. + && ctxt.is_root() + && let which_trait = match fn_name { + sym::clone if is_diag_trait_item(cx, fn_id, sym::Clone) => CloneTrait::Clone, + _ if fn_name.as_str() == "to_owned" + && is_diag_trait_item(cx, fn_id, sym::ToOwned) + && self.msrv.meets(msrvs::CLONE_INTO) => + { + CloneTrait::ToOwned + }, + _ => return, + } + && let Ok(Some(resolved_fn)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_id, fn_gen_args) + // TODO: This check currently bails if the local variable has no initializer. + // That is overly conservative - the lint should fire even if there was no initializer, + // but the variable has been initialized before `lhs` was evaluated. + && path_to_local(lhs).map_or(true, |lhs| local_is_initialized(cx, lhs)) + && let Some(resolved_impl) = cx.tcx.impl_of_method(resolved_fn.def_id()) + // Derived forms don't implement `clone_from`/`clone_into`. + // See https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305 + && !cx.tcx.is_builtin_derived(resolved_impl) + // Don't suggest calling a function we're implementing. + && resolved_impl.as_local().map_or(true, |block_id| { + cx.tcx.hir().parent_owner_iter(e.hir_id).all(|(id, _)| id.def_id != block_id) + }) + && let resolved_assoc_items = cx.tcx.associated_items(resolved_impl) + // Only suggest if `clone_from`/`clone_into` is explicitly implemented + && resolved_assoc_items.in_definition_order().any(|assoc| + match which_trait { + CloneTrait::Clone => assoc.name == sym::clone_from, + CloneTrait::ToOwned => assoc.name.as_str() == "clone_into", + } + ) + && !clone_source_borrows_from_dest(cx, lhs, rhs.span) + { + span_lint_and_then( + cx, + ASSIGNING_CLONES, + e.span, + match which_trait { + CloneTrait::Clone => "assigning the result of `Clone::clone()` may be inefficient", + CloneTrait::ToOwned => "assigning the result of `ToOwned::to_owned()` may be inefficient", + }, + |diag| { + let mut app = Applicability::Unspecified; + diag.span_suggestion( + e.span, + match which_trait { + CloneTrait::Clone => "use `clone_from()`", + CloneTrait::ToOwned => "use `clone_into()`", + }, + build_sugg(cx, ctxt, lhs, fn_arg, which_trait, call_kind, &mut app), + app, + ); + }, + ); } } extract_msrv_attr!(LateContext); } -// Try to resolve the call to `Clone::clone` or `ToOwned::to_owned`. -fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option> { - let fn_def_id = clippy_utils::fn_def_id(cx, expr)?; - - // Fast paths to only check method calls without arguments or function calls with a single argument - let (target, kind, resolved_method) = match expr.kind { - ExprKind::MethodCall(path, receiver, [], _span) => { - let args = cx.typeck_results().node_args(expr.hir_id); - - // If we could not resolve the method, don't apply the lint - let Ok(Some(resolved_method)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args) else { - return None; - }; - if is_trait_method(cx, expr, sym::Clone) && path.ident.name == sym::clone { - (TargetTrait::Clone, CallKind::MethodCall { receiver }, resolved_method) - } else if is_trait_method(cx, expr, sym::ToOwned) && path.ident.name.as_str() == "to_owned" { - (TargetTrait::ToOwned, CallKind::MethodCall { receiver }, resolved_method) - } else { - return None; - } - }, - ExprKind::Call(function, [arg]) => { - let kind = cx.typeck_results().node_type(function.hir_id).kind(); - - // If we could not resolve the method, don't apply the lint - let Ok(Some(resolved_method)) = (match kind { - ty::FnDef(_, args) => Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args), - _ => Ok(None), - }) else { - return None; - }; - if cx.tcx.is_diagnostic_item(sym::to_owned_method, fn_def_id) { - ( - TargetTrait::ToOwned, - CallKind::FunctionCall { self_arg: arg }, - resolved_method, - ) - } else if let Some(trait_did) = cx.tcx.trait_of_item(fn_def_id) - && cx.tcx.is_diagnostic_item(sym::Clone, trait_did) - { - ( - TargetTrait::Clone, - CallKind::FunctionCall { self_arg: arg }, - resolved_method, - ) - } else { - return None; - } - }, - _ => return None, - }; - - Some(CallCandidate { - span: expr.span, - target, - kind, - method_def_id: resolved_method.def_id(), - }) -} - -// Return true if we find that the called method has a custom implementation and isn't derived or -// provided by default by the corresponding trait. -fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>, msrv: &Msrv) -> bool { - // For calls to .to_owned we suggest using .clone_into(), which was only stablilized in 1.63. - // If the current MSRV is below that, don't suggest the lint. - if !msrv.meets(msrvs::CLONE_INTO) && matches!(call.target, TargetTrait::ToOwned) { - return false; - } - - // If the left-hand side is a local variable, it might be uninitialized at this point. - // In that case we do not want to suggest the lint. - if let Some(local) = path_to_local(lhs) { - // TODO: This check currently bails if the local variable has no initializer. - // That is overly conservative - the lint should fire even if there was no initializer, - // but the variable has been initialized before `lhs` was evaluated. - if !local_is_initialized(cx, local) { - return false; - } - } - - let Some(impl_block) = cx.tcx.impl_of_method(call.method_def_id) else { - return false; - }; - - // If the method implementation comes from #[derive(Clone)], then don't suggest the lint. - // Automatically generated Clone impls do not currently override `clone_from`. - // See e.g. https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305 for more details. - if cx.tcx.is_builtin_derived(impl_block) { - return false; - } - - // If the call expression is inside an impl block that contains the method invoked by the - // call expression, we bail out to avoid suggesting something that could result in endless - // recursion. - if let Some(local_block_id) = impl_block.as_local() - && let Some(block) = cx.tcx.hir_node_by_def_id(local_block_id).as_owner() - { - let impl_block_owner = block.def_id(); - if cx - .tcx - .hir() - .parent_id_iter(lhs.hir_id) - .any(|parent| parent.owner == impl_block_owner) - { - return false; - } - } - - // Find the function for which we want to check that it is implemented. - let provided_fn = match call.target { - TargetTrait::Clone => cx.tcx.get_diagnostic_item(sym::Clone).and_then(|clone| { - cx.tcx - .provided_trait_methods(clone) - .find(|item| item.name == sym::clone_from) - }), - TargetTrait::ToOwned => cx.tcx.get_diagnostic_item(sym::ToOwned).and_then(|to_owned| { - cx.tcx - .provided_trait_methods(to_owned) - .find(|item| item.name.as_str() == "clone_into") - }), - }; - let Some(provided_fn) = provided_fn else { - return false; - }; - - if clone_source_borrows_from_dest(cx, lhs, call.span) { - return false; - } - - // Now take a look if the impl block defines an implementation for the method that we're interested - // in. If not, then we're using a default implementation, which is not interesting, so we will - // not suggest the lint. - let implemented_fns = cx.tcx.impl_item_implementor_ids(impl_block); - implemented_fns.contains_key(&provided_fn.def_id) -} - /// Checks if the data being cloned borrows from the place that is being assigned to: /// /// ``` @@ -239,16 +154,6 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC /// /// This cannot be written `s2.clone_into(&mut s)` because it has conflicting borrows. fn clone_source_borrows_from_dest(cx: &LateContext<'_>, lhs: &Expr<'_>, call_span: Span) -> bool { - /// If this basic block only exists to drop a local as part of an assignment, returns its - /// successor. Otherwise returns the basic block that was passed in. - fn skip_drop_block(mir: &mir::Body<'_>, bb: mir::BasicBlock) -> mir::BasicBlock { - if let mir::TerminatorKind::Drop { target, .. } = mir.basic_blocks[bb].terminator().kind { - target - } else { - bb - } - } - let Some(mir) = enclosing_mir(cx.tcx, lhs.hir_id) else { return false; }; @@ -267,172 +172,123 @@ fn clone_source_borrows_from_dest(cx: &LateContext<'_>, lhs: &Expr<'_>, call_spa // // bb2: // s = s_temp - for bb in mir.basic_blocks.iter() { - let terminator = bb.terminator(); - - // Look for the to_owned/clone call. - if terminator.source_info.span != call_span { - continue; + if let Some(terminator) = mir.basic_blocks.iter() + .map(mir::BasicBlockData::terminator) + .find(|term| term.source_info.span == call_span) + && let mir::TerminatorKind::Call { ref args, target: Some(assign_bb), .. } = terminator.kind + && let [source] = &**args + && let mir::Operand::Move(source) = &source.node + && let assign_bb = &mir.basic_blocks[assign_bb] + && let assign_bb = match assign_bb.terminator().kind { + // Skip the drop of the assignment's destination. + mir::TerminatorKind::Drop { target, .. } => &mir.basic_blocks[target], + _ => assign_bb, } - - if let mir::TerminatorKind::Call { ref args, target: Some(assign_bb), .. } = terminator.kind - && let [source] = &**args - && let mir::Operand::Move(source) = &source.node - && let assign_bb = skip_drop_block(mir, assign_bb) - // Skip any storage statements as they are just noise - && let Some(assignment) = mir.basic_blocks[assign_bb].statements - .iter() - .find(|stmt| { - !matches!(stmt.kind, mir::StatementKind::StorageDead(_) | mir::StatementKind::StorageLive(_)) - }) - && let mir::StatementKind::Assign(box (borrowed, _)) = &assignment.kind - && let Some(borrowers) = borrow_map.get(&borrowed.local) - && borrowers.contains(source.local) - { - return true; - } - - return false; + // Skip any storage statements as they are just noise + && let Some(assignment) = assign_bb.statements + .iter() + .find(|stmt| { + !matches!(stmt.kind, mir::StatementKind::StorageDead(_) | mir::StatementKind::StorageLive(_)) + }) + && let mir::StatementKind::Assign(box (borrowed, _)) = &assignment.kind + && let Some(borrowers) = borrow_map.get(&borrowed.local) + { + borrowers.contains(source.local) + } else { + false } - false } -fn suggest<'tcx>( - cx: &LateContext<'tcx>, - ctxt: SyntaxContext, - assign_expr: &Expr<'tcx>, - lhs: &Expr<'tcx>, - call: &CallCandidate<'tcx>, -) { - span_lint_and_then(cx, ASSIGNING_CLONES, assign_expr.span, call.message(), |diag| { - let mut applicability = Applicability::Unspecified; - - diag.span_suggestion( - assign_expr.span, - call.suggestion_msg(), - call.suggested_replacement(cx, ctxt, lhs, &mut applicability), - applicability, - ); - }); -} - -#[derive(Copy, Clone, Debug)] -enum CallKind<'tcx> { - MethodCall { receiver: &'tcx Expr<'tcx> }, - FunctionCall { self_arg: &'tcx Expr<'tcx> }, -} - -#[derive(Copy, Clone, Debug)] -enum TargetTrait { +#[derive(Clone, Copy)] +enum CloneTrait { Clone, ToOwned, } -#[derive(Debug)] -struct CallCandidate<'tcx> { - span: Span, - target: TargetTrait, - kind: CallKind<'tcx>, - // DefId of the called method from an impl block that implements the target trait - method_def_id: DefId, +#[derive(Copy, Clone)] +enum CallKind { + Ufcs, + Method, } -impl<'tcx> CallCandidate<'tcx> { - #[inline] - fn message(&self) -> &'static str { - match self.target { - TargetTrait::Clone => "assigning the result of `Clone::clone()` may be inefficient", - TargetTrait::ToOwned => "assigning the result of `ToOwned::to_owned()` may be inefficient", - } - } - - #[inline] - fn suggestion_msg(&self) -> &'static str { - match self.target { - TargetTrait::Clone => "use `clone_from()`", - TargetTrait::ToOwned => "use `clone_into()`", - } - } - - fn suggested_replacement( - &self, - cx: &LateContext<'tcx>, - ctxt: SyntaxContext, - lhs: &Expr<'tcx>, - applicability: &mut Applicability, - ) -> String { - match self.target { - TargetTrait::Clone => { - match self.kind { - CallKind::MethodCall { receiver } => { - let receiver_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { - // `*lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)` - Sugg::hir_with_applicability(cx, ref_expr, "_", applicability) - } else { - // `lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)` - Sugg::hir_with_applicability(cx, lhs, "_", applicability) - } - .maybe_par(); - - // Determine whether we need to reference the argument to clone_from(). - let clone_receiver_type = cx.typeck_results().expr_ty(receiver); - let clone_receiver_adj_type = cx.typeck_results().expr_ty_adjusted(receiver); - let mut arg_sugg = Sugg::hir_with_context(cx, receiver, ctxt, "_", applicability); - if clone_receiver_type != clone_receiver_adj_type { - // The receiver may have been a value type, so we need to add an `&` to - // be sure the argument to clone_from will be a reference. - arg_sugg = arg_sugg.addr(); - }; - - format!("{receiver_sugg}.clone_from({arg_sugg})") - }, - CallKind::FunctionCall { self_arg, .. } => { - let self_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { - // `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(lhs, self_expr)` - Sugg::hir_with_applicability(cx, ref_expr, "_", applicability) - } else { - // `lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut lhs, self_expr)` - Sugg::hir_with_applicability(cx, lhs, "_", applicability).mut_addr() - }; - // The RHS had to be exactly correct before the call, there is no auto-deref for function calls. - let rhs_sugg = Sugg::hir_with_context(cx, self_arg, ctxt, "_", applicability); - - format!("Clone::clone_from({self_sugg}, {rhs_sugg})") - }, - } - }, - TargetTrait::ToOwned => { - let rhs_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { - // `*lhs = rhs.to_owned()` -> `rhs.clone_into(lhs)` - // `*lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, lhs)` - let sugg = Sugg::hir_with_applicability(cx, ref_expr, "_", applicability).maybe_par(); - let inner_type = cx.typeck_results().expr_ty(ref_expr); - // If after unwrapping the dereference, the type is not a mutable reference, we add &mut to make it - // deref to a mutable reference. - if matches!(inner_type.kind(), ty::Ref(_, _, Mutability::Mut)) { - sugg +fn build_sugg<'tcx>( + cx: &LateContext<'tcx>, + ctxt: SyntaxContext, + lhs: &'tcx Expr<'_>, + fn_arg: &'tcx Expr<'_>, + which_trait: CloneTrait, + call_kind: CallKind, + app: &mut Applicability, +) -> String { + match which_trait { + CloneTrait::Clone => { + match call_kind { + CallKind::Method => { + let receiver_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { + // `*lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)` + Sugg::hir_with_applicability(cx, ref_expr, "_", app) } else { - sugg.mut_addr() + // `lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)` + Sugg::hir_with_applicability(cx, lhs, "_", app) } - } else { - // `lhs = rhs.to_owned()` -> `rhs.clone_into(&mut lhs)` - // `lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, &mut lhs)` - Sugg::hir_with_applicability(cx, lhs, "_", applicability) - .maybe_par() - .mut_addr() - }; + .maybe_par(); - match self.kind { - CallKind::MethodCall { receiver } => { - let receiver_sugg = Sugg::hir_with_context(cx, receiver, ctxt, "_", applicability); - format!("{receiver_sugg}.clone_into({rhs_sugg})") - }, - CallKind::FunctionCall { self_arg, .. } => { - let self_sugg = Sugg::hir_with_context(cx, self_arg, ctxt, "_", applicability); - format!("ToOwned::clone_into({self_sugg}, {rhs_sugg})") - }, + // Determine whether we need to reference the argument to clone_from(). + let clone_receiver_type = cx.typeck_results().expr_ty(fn_arg); + let clone_receiver_adj_type = cx.typeck_results().expr_ty_adjusted(fn_arg); + let mut arg_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app); + if clone_receiver_type != clone_receiver_adj_type { + // The receiver may have been a value type, so we need to add an `&` to + // be sure the argument to clone_from will be a reference. + arg_sugg = arg_sugg.addr(); + }; + + format!("{receiver_sugg}.clone_from({arg_sugg})") + }, + CallKind::Ufcs => { + let self_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { + // `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(lhs, self_expr)` + Sugg::hir_with_applicability(cx, ref_expr, "_", app) + } else { + // `lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut lhs, self_expr)` + Sugg::hir_with_applicability(cx, lhs, "_", app).mut_addr() + }; + // The RHS had to be exactly correct before the call, there is no auto-deref for function calls. + let rhs_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app); + + format!("Clone::clone_from({self_sugg}, {rhs_sugg})") + }, + } + }, + CloneTrait::ToOwned => { + let rhs_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { + // `*lhs = rhs.to_owned()` -> `rhs.clone_into(lhs)` + // `*lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, lhs)` + let sugg = Sugg::hir_with_applicability(cx, ref_expr, "_", app).maybe_par(); + let inner_type = cx.typeck_results().expr_ty(ref_expr); + // If after unwrapping the dereference, the type is not a mutable reference, we add &mut to make it + // deref to a mutable reference. + if matches!(inner_type.kind(), ty::Ref(_, _, Mutability::Mut)) { + sugg + } else { + sugg.mut_addr() } - }, - } + } else { + // `lhs = rhs.to_owned()` -> `rhs.clone_into(&mut lhs)` + // `lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, &mut lhs)` + Sugg::hir_with_applicability(cx, lhs, "_", app).maybe_par().mut_addr() + }; + + match call_kind { + CallKind::Method => { + let receiver_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app); + format!("{receiver_sugg}.clone_into({rhs_sugg})") + }, + CallKind::Ufcs => { + let self_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app); + format!("ToOwned::clone_into({self_sugg}, {rhs_sugg})") + }, + } + }, } } diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index f25a474d9bbd..d4a1e2780d08 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -11,21 +11,25 @@ use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does - /// Checks for calls to await while holding a non-async-aware MutexGuard. + /// Checks for calls to `await` while holding a non-async-aware + /// `MutexGuard`. /// /// ### Why is this bad? - /// The Mutex types found in std::sync and parking_lot - /// are not designed to operate in an async context across await points. + /// The Mutex types found in [`std::sync`][https://doc.rust-lang.org/stable/std/sync/] and + /// [`parking_lot`](https://docs.rs/parking_lot/latest/parking_lot/) are + /// not designed to operate in an async context across await points. /// - /// There are two potential solutions. One is to use an async-aware Mutex - /// type. Many asynchronous foundation crates provide such a Mutex type. The - /// other solution is to ensure the mutex is unlocked before calling await, - /// either by introducing a scope or an explicit call to Drop::drop. + /// There are two potential solutions. One is to use an async-aware `Mutex` + /// type. Many asynchronous foundation crates provide such a `Mutex` type. + /// The other solution is to ensure the mutex is unlocked before calling + /// `await`, either by introducing a scope or an explicit call to + /// [`Drop::drop`](https://doc.rust-lang.org/std/ops/trait.Drop.html). /// /// ### Known problems /// Will report false positive for explicitly dropped guards - /// ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A workaround for this is - /// to wrap the `.lock()` call in a block instead of explicitly dropping the guard. + /// ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A + /// workaround for this is to wrap the `.lock()` call in a block instead of + /// explicitly dropping the guard. /// /// ### Example /// ```no_run @@ -73,11 +77,11 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for calls to await while holding a `RefCell` `Ref` or `RefMut`. + /// Checks for calls to `await` while holding a `RefCell`, `Ref`, or `RefMut`. /// /// ### Why is this bad? /// `RefCell` refs only check for exclusive mutable access - /// at runtime. Holding onto a `RefCell` ref across an `await` suspension point + /// at runtime. Holding a `RefCell` ref across an await suspension point /// risks panics from a mutable ref shared while other refs are outstanding. /// /// ### Known problems @@ -131,13 +135,13 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Allows users to configure types which should not be held across `await` + /// Allows users to configure types which should not be held across await /// suspension points. /// /// ### Why is this bad? - /// There are some types which are perfectly "safe" to be used concurrently - /// from a memory access perspective but will cause bugs at runtime if they - /// are held in such a way. + /// There are some types which are perfectly safe to use concurrently from + /// a memory access perspective, but that will cause bugs at runtime if + /// they are held in such a way. /// /// ### Example /// @@ -228,15 +232,15 @@ impl AwaitHolding { cx, AWAIT_HOLDING_LOCK, ty_cause.source_info.span, - "this `MutexGuard` is held across an `await` point", + "this `MutexGuard` is held across an await point", |diag| { diag.help( "consider using an async-aware `Mutex` type or ensuring the \ - `MutexGuard` is dropped before calling await", + `MutexGuard` is dropped before calling `await`", ); diag.span_note( await_points(), - "these are all the `await` points this lock is held through", + "these are all the await points this lock is held through", ); }, ); @@ -245,12 +249,12 @@ impl AwaitHolding { cx, AWAIT_HOLDING_REFCELL_REF, ty_cause.source_info.span, - "this `RefCell` reference is held across an `await` point", + "this `RefCell` reference is held across an await point", |diag| { diag.help("ensure the reference is dropped before calling `await`"); diag.span_note( await_points(), - "these are all the `await` points this reference is held through", + "these are all the await points this reference is held through", ); }, ); @@ -268,7 +272,7 @@ fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPa AWAIT_HOLDING_INVALID_TYPE, span, format!( - "`{}` may not be held across an `await` point per `clippy.toml`", + "`{}` may not be held across an await point per `clippy.toml`", disallowed.path() ), |diag| { diff --git a/clippy_lints/src/bool_to_int_with_if.rs b/clippy_lints/src/bool_to_int_with_if.rs index cfb76cab6dc2..561ca9bd9866 100644 --- a/clippy_lints/src/bool_to_int_with_if.rs +++ b/clippy_lints/src/bool_to_int_with_if.rs @@ -1,13 +1,11 @@ -use clippy_utils::higher::If; -use rustc_ast::LitKind; -use rustc_hir::{Block, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; - use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::Sugg; -use clippy_utils::{in_constant, is_else_clause, is_integer_literal}; +use clippy_utils::{in_constant, is_else_clause}; +use rustc_ast::LitKind; use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does @@ -47,80 +45,64 @@ declare_clippy_lint! { declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]); impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { - if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) { - check_if_else(cx, expr); + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::If(cond, then, Some(else_)) = expr.kind + && matches!(cond.kind, ExprKind::DropTemps(_)) + && let Some(then_lit) = as_int_bool_lit(then) + && let Some(else_lit) = as_int_bool_lit(else_) + && then_lit != else_lit + && !expr.span.from_expansion() + && !in_constant(cx, expr.hir_id) + { + let ty = cx.typeck_results().expr_ty(then); + let mut applicability = Applicability::MachineApplicable; + let snippet = { + let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); + if !then_lit { + sugg = !sugg; + } + sugg + }; + let suggestion = { + let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into()); + // when used in else clause if statement should be wrapped in curly braces + if is_else_clause(cx.tcx, expr) { + s = s.blockify(); + } + s + }; + + let into_snippet = snippet.clone().maybe_par(); + let as_snippet = snippet.as_ty(ty); + + span_lint_and_then( + cx, + BOOL_TO_INT_WITH_IF, + expr.span, + "boolean to int conversion using if", + |diag| { + diag.span_suggestion(expr.span, "replace with from", suggestion, applicability); + diag.note(format!( + "`{as_snippet}` or `{into_snippet}.into()` can also be valid options" + )); + }, + ); } } } -fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { - if let Some(If { - cond, - then, - r#else: Some(r#else), - }) = If::hir(expr) - && let Some(then_lit) = int_literal(then) - && let Some(else_lit) = int_literal(r#else) +fn as_int_bool_lit(e: &Expr<'_>) -> Option { + if let ExprKind::Block(b, _) = e.kind + && b.stmts.is_empty() + && let Some(e) = b.expr + && let ExprKind::Lit(lit) = e.kind + && let LitKind::Int(x, _) = lit.node { - let inverted = if is_integer_literal(then_lit, 1) && is_integer_literal(else_lit, 0) { - false - } else if is_integer_literal(then_lit, 0) && is_integer_literal(else_lit, 1) { - true - } else { - // Expression isn't boolean, exit - return; - }; - let mut applicability = Applicability::MachineApplicable; - let snippet = { - let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); - if inverted { - sugg = !sugg; - } - sugg - }; - - let ty = cx.typeck_results().expr_ty(then_lit); // then and else must be of same type - - let suggestion = { - let wrap_in_curly = is_else_clause(cx.tcx, expr); - let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into()); - if wrap_in_curly { - s = s.blockify(); - } - s - }; // when used in else clause if statement should be wrapped in curly braces - - let into_snippet = snippet.clone().maybe_par(); - let as_snippet = snippet.as_ty(ty); - - span_lint_and_then( - cx, - BOOL_TO_INT_WITH_IF, - expr.span, - "boolean to int conversion using if", - |diag| { - diag.span_suggestion(expr.span, "replace with from", suggestion, applicability); - diag.note(format!( - "`{as_snippet}` or `{into_snippet}.into()` can also be valid options" - )); - }, - ); - }; -} - -// If block contains only a int literal expression, return literal expression -fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hir::Expr<'tcx>> { - if let ExprKind::Block(block, _) = expr.kind - && let Block { - stmts: [], // Shouldn't lint if statements with side effects - expr: Some(expr), - .. - } = block - && let ExprKind::Lit(lit) = &expr.kind - && let LitKind::Int(_, _) = lit.node - { - Some(expr) + match x.get() { + 0 => Some(false), + 1 => Some(true), + _ => None, + } } else { None } diff --git a/clippy_lints/src/byte_char_slices.rs b/clippy_lints/src/byte_char_slices.rs new file mode 100644 index 000000000000..a9fe190f1777 --- /dev/null +++ b/clippy_lints/src/byte_char_slices.rs @@ -0,0 +1,80 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast::ast::{BorrowKind, Expr, ExprKind, Mutability}; +use rustc_ast::token::{Lit, LitKind}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks for hard to read slices of byte characters, that could be more easily expressed as a + /// byte string. + /// + /// ### Why is this bad? + /// + /// Potentially makes the string harder to read. + /// + /// ### Example + /// ```ignore + /// &[b'H', b'e', b'l', b'l', b'o']; + /// ``` + /// Use instead: + /// ```ignore + /// b"Hello" + /// ``` + #[clippy::version = "1.68.0"] + pub BYTE_CHAR_SLICES, + style, + "hard to read byte char slice" +} +declare_lint_pass!(ByteCharSlice => [BYTE_CHAR_SLICES]); + +impl EarlyLintPass for ByteCharSlice { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if let Some(slice) = is_byte_char_slices(expr) + && !expr.span.from_expansion() + { + span_lint_and_sugg( + cx, + BYTE_CHAR_SLICES, + expr.span, + "can be more succinctly written as a byte str", + "try", + format!("b\"{slice}\""), + Applicability::MaybeIncorrect, + ); + } + } +} + +fn is_byte_char_slices(expr: &Expr) -> Option { + if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, expr) = &expr.kind { + match &expr.kind { + ExprKind::Array(members) => { + if members.is_empty() { + return None; + } + + members + .iter() + .map(|member| match &member.kind { + ExprKind::Lit(Lit { + kind: LitKind::Byte, + symbol, + .. + }) => Some(symbol.as_str()), + _ => None, + }) + .map(|maybe_quote| match maybe_quote { + Some("\"") => Some("\\\""), + Some("\\'") => Some("'"), + other => other, + }) + .collect::>() + }, + _ => None, + } + } else { + None + } +} diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index e60c36ced75d..54f0c7c46871 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -32,7 +32,7 @@ use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks for casts from any numerical to a float type where + /// Checks for casts from any numeric type to a float type where /// the receiving type cannot store all values from the original type without /// rounding errors. This possible rounding is to be expected, so this lint is /// `Allow` by default. @@ -58,14 +58,14 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts from a signed to an unsigned numerical + /// Checks for casts from a signed to an unsigned numeric /// type. In this case, negative values wrap around to large positive values, - /// which can be quite surprising in practice. However, as the cast works as + /// which can be quite surprising in practice. However, since the cast works as /// defined, this lint is `Allow` by default. /// /// ### Why is this bad? /// Possibly surprising results. You can activate this lint - /// as a one-time check to see where numerical wrapping can arise. + /// as a one-time check to see where numeric wrapping can arise. /// /// ### Example /// ```no_run @@ -80,7 +80,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts between numerical types that may + /// Checks for casts between numeric types that may /// truncate large values. This is expected behavior, so the cast is `Allow` by /// default. It suggests user either explicitly ignore the lint, /// or use `try_from()` and handle the truncation, default, or panic explicitly. @@ -120,17 +120,16 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for casts from an unsigned type to a signed type of - /// the same size, or possibly smaller due to target dependent integers. - /// Performing such a cast is a 'no-op' for the compiler, i.e., nothing is - /// changed at the bit level, and the binary representation of the value is + /// the same size, or possibly smaller due to target-dependent integers. + /// Performing such a cast is a no-op for the compiler (that is, nothing is + /// changed at the bit level), and the binary representation of the value is /// reinterpreted. This can cause wrapping if the value is too big /// for the target signed type. However, the cast works as defined, so this lint /// is `Allow` by default. /// /// ### Why is this bad? /// While such a cast is not bad in itself, the results can - /// be surprising when this is not the intended behavior, as demonstrated by the - /// example below. + /// be surprising when this is not the intended behavior: /// /// ### Example /// ```no_run @@ -144,16 +143,16 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts between numerical types that may - /// be replaced by safe conversion functions. + /// Checks for casts between numeric types that can be replaced by safe + /// conversion functions. /// /// ### Why is this bad? - /// Rust's `as` keyword will perform many kinds of - /// conversions, including silently lossy conversions. Conversion functions such - /// as `i32::from` will only perform lossless conversions. Using the conversion - /// functions prevents conversions from turning into silent lossy conversions if - /// the types of the input expressions ever change, and make it easier for - /// people reading the code to know that the conversion is lossless. + /// Rust's `as` keyword will perform many kinds of conversions, including + /// silently lossy conversions. Conversion functions such as `i32::from` + /// will only perform lossless conversions. Using the conversion functions + /// prevents conversions from becoming silently lossy if the input types + /// ever change, and makes it clear for people reading the code that the + /// conversion is lossless. /// /// ### Example /// ```no_run @@ -177,19 +176,21 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts to the same type, casts of int literals to integer types, casts of float - /// literals to float types and casts between raw pointers without changing type or constness. + /// Checks for casts to the same type, casts of int literals to integer + /// types, casts of float literals to float types, and casts between raw + /// pointers that don't change type or constness. /// /// ### Why is this bad? /// It's just unnecessary. /// /// ### Known problems - /// When the expression on the left is a function call, the lint considers the return type to be - /// a type alias if it's aliased through a `use` statement - /// (like `use std::io::Result as IoResult`). It will not lint such cases. + /// When the expression on the left is a function call, the lint considers + /// the return type to be a type alias if it's aliased through a `use` + /// statement (like `use std::io::Result as IoResult`). It will not lint + /// such cases. /// - /// This check is also rather primitive. It will only work on primitive types without any - /// intermediate references, raw pointers and trait objects may or may not work. + /// This check will only work on primitive types without any intermediate + /// references: raw pointers and trait objects may or may not work. /// /// ### Example /// ```no_run @@ -211,17 +212,17 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts, using `as` or `pointer::cast`, - /// from a less-strictly-aligned pointer to a more-strictly-aligned pointer + /// Checks for casts, using `as` or `pointer::cast`, from a + /// less strictly aligned pointer to a more strictly aligned pointer. /// /// ### Why is this bad? - /// Dereferencing the resulting pointer may be undefined - /// behavior. + /// Dereferencing the resulting pointer may be undefined behavior. /// /// ### Known problems - /// Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar - /// on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like - /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis. + /// Using [`std::ptr::read_unaligned`](https://doc.rust-lang.org/std/ptr/fn.read_unaligned.html) and [`std::ptr::write_unaligned`](https://doc.rust-lang.org/std/ptr/fn.write_unaligned.html) or + /// similar on the resulting pointer is fine. Is over-zealous: casts with + /// manual alignment checks or casts like `u64` -> `u8` -> `u16` can be + /// fine. Miri is able to do a more in-depth analysis. /// /// ### Example /// ```no_run @@ -234,20 +235,21 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub CAST_PTR_ALIGNMENT, pedantic, - "cast from a pointer to a more-strictly-aligned pointer" + "cast from a pointer to a more strictly aligned pointer" } declare_clippy_lint! { /// ### What it does - /// Checks for casts of function pointers to something other than usize + /// Checks for casts of function pointers to something other than `usize`. /// /// ### Why is this bad? - /// Casting a function pointer to anything other than usize/isize is not portable across - /// architectures, because you end up losing bits if the target type is too small or end up with a - /// bunch of extra bits that waste space and add more instructions to the final binary than - /// strictly necessary for the problem + /// Casting a function pointer to anything other than `usize`/`isize` is + /// not portable across architectures. If the target type is too small the + /// address would be truncated, and target types larger than `usize` are + /// unnecessary. /// - /// Casting to isize also doesn't make sense since there are no signed addresses. + /// Casting to `isize` also doesn't make sense, since addresses are never + /// signed. /// /// ### Example /// ```no_run @@ -263,17 +265,17 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub FN_TO_NUMERIC_CAST, style, - "casting a function pointer to a numeric type other than usize" + "casting a function pointer to a numeric type other than `usize`" } declare_clippy_lint! { /// ### What it does /// Checks for casts of a function pointer to a numeric type not wide enough to - /// store address. + /// store an address. /// /// ### Why is this bad? /// Such a cast discards some bits of the function's address. If this is intended, it would be more - /// clearly expressed by casting to usize first, then casting the usize to the intended type (with + /// clearly expressed by casting to `usize` first, then casting the `usize` to the intended type (with /// a comment) to perform the truncation. /// /// ### Example @@ -306,7 +308,7 @@ declare_clippy_lint! { /// ### Why restrict this? /// Casting a function pointer to an integer can have surprising results and can occur /// accidentally if parentheses are omitted from a function call. If you aren't doing anything - /// low-level with function pointers then you can opt-out of casting functions to integers in + /// low-level with function pointers then you can opt out of casting functions to integers in /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function /// pointer casts in your code. /// @@ -349,8 +351,8 @@ declare_clippy_lint! { /// ### Why is this bad? /// In general, casting values to smaller types is /// error-prone and should be avoided where possible. In the particular case of - /// converting a character literal to u8, it is easy to avoid by just using a - /// byte literal instead. As an added bonus, `b'a'` is even slightly shorter + /// converting a character literal to `u8`, it is easy to avoid by just using a + /// byte literal instead. As an added bonus, `b'a'` is also slightly shorter /// than `'a' as u8`. /// /// ### Example @@ -371,12 +373,13 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for `as` casts between raw pointers without changing its mutability, - /// namely `*const T` to `*const U` and `*mut T` to `*mut U`. + /// Checks for `as` casts between raw pointers that don't change their + /// constness, namely `*const T` to `*const U` and `*mut T` to `*mut U`. /// /// ### Why is this bad? - /// Though `as` casts between raw pointers are not terrible, `pointer::cast` is safer because - /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`. + /// Though `as` casts between raw pointers are not terrible, + /// `pointer::cast` is safer because it cannot accidentally change the + /// pointer's mutability, nor cast the pointer to other types like `usize`. /// /// ### Example /// ```no_run @@ -395,12 +398,12 @@ declare_clippy_lint! { #[clippy::version = "1.51.0"] pub PTR_AS_PTR, pedantic, - "casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`" + "casting using `as` between raw pointers that doesn't change their constness, where `pointer::cast` could take the place of `as`" } declare_clippy_lint! { /// ### What it does - /// Checks for `as` casts between raw pointers which change its constness, namely `*const T` to + /// Checks for `as` casts between raw pointers that change their constness, namely `*const T` to /// `*mut T` and `*mut T` to `*const T`. /// /// ### Why is this bad? @@ -423,12 +426,12 @@ declare_clippy_lint! { #[clippy::version = "1.72.0"] pub PTR_CAST_CONSTNESS, pedantic, - "casting using `as` from and to raw pointers to change constness when specialized methods apply" + "casting using `as` on raw pointers to change constness when specialized methods apply" } declare_clippy_lint! { /// ### What it does - /// Checks for casts from an enum type to an integral type which will definitely truncate the + /// Checks for casts from an enum type to an integral type that will definitely truncate the /// value. /// /// ### Why is this bad? @@ -442,7 +445,7 @@ declare_clippy_lint! { #[clippy::version = "1.61.0"] pub CAST_ENUM_TRUNCATION, suspicious, - "casts from an enum type to an integral type which will truncate the value" + "casts from an enum type to an integral type that will truncate the value" } declare_clippy_lint! { @@ -621,7 +624,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer + /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer. /// /// ### Why is this bad? /// Since `as_ptr` takes a `&self`, the pointer won't have write permissions unless interior diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index 2c168405ee26..86c5f6b9f0ba 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -92,7 +92,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { cx, PTR_AS_PTR, expr.span, - "`as` casting between raw pointers without changing its mutability", + "`as` casting between raw pointers without changing their constness", help, final_suggestion, app, diff --git a/clippy_lints/src/cfg_not_test.rs b/clippy_lints/src/cfg_not_test.rs new file mode 100644 index 000000000000..b54f392bf2fa --- /dev/null +++ b/clippy_lints/src/cfg_not_test.rs @@ -0,0 +1,60 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_ast::NestedMetaItem; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `cfg` that excludes code from `test` builds. (i.e., `#{cfg(not(test))]`) + /// + /// ### Why is this bad? + /// This may give the false impression that a codebase has 100% coverage, yet actually has untested code. + /// Enabling this also guards against excessive mockery as well, which is an anti-pattern. + /// + /// ### Example + /// ```rust + /// # fn important_check() {} + /// #[cfg(not(test))] + /// important_check(); // I'm not actually tested, but not including me will falsely increase coverage! + /// ``` + /// Use instead: + /// ```rust + /// # fn important_check() {} + /// important_check(); + /// ``` + #[clippy::version = "1.73.0"] + pub CFG_NOT_TEST, + restriction, + "enforce against excluding code from test builds" +} + +declare_lint_pass!(CfgNotTest => [CFG_NOT_TEST]); + +impl EarlyLintPass for CfgNotTest { + fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &rustc_ast::Attribute) { + if attr.has_name(rustc_span::sym::cfg) && contains_not_test(attr.meta_item_list().as_deref(), false) { + span_lint_and_then( + cx, + CFG_NOT_TEST, + attr.span, + "code is excluded from test builds", + |diag| { + diag.help("consider not excluding any code from test builds"); + diag.note_once("this could increase code coverage despite not actually being tested"); + }, + ); + } + } +} + +fn contains_not_test(list: Option<&[NestedMetaItem]>, not: bool) -> bool { + list.is_some_and(|list| { + list.iter().any(|item| { + item.ident().is_some_and(|ident| match ident.name { + rustc_span::sym::not => contains_not_test(item.meta_item_list(), !not), + rustc_span::sym::test => not, + _ => contains_not_test(item.meta_item_list(), not), + }) + }) + }) +} diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 638de5e818c8..eabc67601a2f 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -8,8 +8,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ #[cfg(feature = "internal")] crate::utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS_INFO, #[cfg(feature = "internal")] - crate::utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS_INFO, - #[cfg(feature = "internal")] crate::utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL_INFO, #[cfg(feature = "internal")] crate::utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR_INFO, @@ -73,6 +71,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::booleans::OVERLY_COMPLEX_BOOL_EXPR_INFO, crate::borrow_deref_ref::BORROW_DEREF_REF_INFO, crate::box_default::BOX_DEFAULT_INFO, + crate::byte_char_slices::BYTE_CHAR_SLICES_INFO, crate::cargo::CARGO_COMMON_METADATA_INFO, crate::cargo::LINT_GROUPS_PRIORITY_INFO, crate::cargo::MULTIPLE_CRATE_VERSIONS_INFO, @@ -103,6 +102,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::casts::REF_AS_PTR_INFO, crate::casts::UNNECESSARY_CAST_INFO, crate::casts::ZERO_PTR_INFO, + crate::cfg_not_test::CFG_NOT_TEST_INFO, crate::checked_conversions::CHECKED_CONVERSIONS_INFO, crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO, crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO, @@ -313,6 +313,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::manual_range_patterns::MANUAL_RANGE_PATTERNS_INFO, crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO, crate::manual_retain::MANUAL_RETAIN_INFO, + crate::manual_rotate::MANUAL_ROTATE_INFO, crate::manual_slice_size_calculation::MANUAL_SLICE_SIZE_CALCULATION_INFO, crate::manual_string_new::MANUAL_STRING_NEW_INFO, crate::manual_strip::MANUAL_STRIP_INFO, @@ -503,6 +504,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::missing_assert_message::MISSING_ASSERT_MESSAGE_INFO, crate::missing_asserts_for_indexing::MISSING_ASSERTS_FOR_INDEXING_INFO, crate::missing_const_for_fn::MISSING_CONST_FOR_FN_INFO, + crate::missing_const_for_thread_local::MISSING_CONST_FOR_THREAD_LOCAL_INFO, crate::missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS_INFO, crate::missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES_INFO, crate::missing_fields_in_debug::MISSING_FIELDS_IN_DEBUG_INFO, @@ -585,12 +587,12 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::operators::VERBOSE_BIT_MASK_INFO, crate::option_env_unwrap::OPTION_ENV_UNWRAP_INFO, crate::option_if_let_else::OPTION_IF_LET_ELSE_INFO, - crate::overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL_INFO, crate::panic_in_result_fn::PANIC_IN_RESULT_FN_INFO, crate::panic_unimplemented::PANIC_INFO, crate::panic_unimplemented::TODO_INFO, crate::panic_unimplemented::UNIMPLEMENTED_INFO, crate::panic_unimplemented::UNREACHABLE_INFO, + crate::panicking_overflow_checks::PANICKING_OVERFLOW_CHECKS_INFO, crate::partial_pub_fields::PARTIAL_PUB_FIELDS_INFO, crate::partialeq_ne_impl::PARTIALEQ_NE_IMPL_INFO, crate::partialeq_to_none::PARTIALEQ_TO_NONE_INFO, @@ -644,6 +646,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::semicolon_block::SEMICOLON_OUTSIDE_BLOCK_INFO, crate::semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED_INFO, crate::serde_api::SERDE_API_MISUSE_INFO, + crate::set_contains_or_insert::SET_CONTAINS_OR_INSERT_INFO, crate::shadow::SHADOW_REUSE_INFO, crate::shadow::SHADOW_SAME_INFO, crate::shadow::SHADOW_UNRELATED_INFO, @@ -679,7 +682,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::tabs_in_doc_comments::TABS_IN_DOC_COMMENTS_INFO, crate::temporary_assignment::TEMPORARY_ASSIGNMENT_INFO, crate::tests_outside_test_module::TESTS_OUTSIDE_TEST_MODULE_INFO, - crate::thread_local_initializer_can_be_made_const::THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST_INFO, crate::to_digit_is_some::TO_DIGIT_IS_SOME_INFO, crate::to_string_trait_impl::TO_STRING_TRAIT_IMPL_INFO, crate::trailing_empty_array::TRAILING_EMPTY_ARRAY_INFO, diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 2b3f4854255c..72fa05be3cc6 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{has_drop, is_copy}; -use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro}; +use clippy_utils::{contains_name, get_parent_expr, in_automatically_derived, is_from_proc_macro}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { // Avoid cases already linted by `field_reassign_with_default` && !self.reassigned_linted.contains(&expr.span) && let ExprKind::Call(path, ..) = expr.kind - && !any_parent_is_automatically_derived(cx.tcx, expr.hir_id) + && !in_automatically_derived(cx.tcx, expr.hir_id) && let ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() && cx.tcx.is_diagnostic_item(sym::default_fn, def_id) @@ -113,9 +113,9 @@ impl<'tcx> LateLintPass<'tcx> for Default { // start from the `let mut _ = _::default();` and look at all the following // statements, see if they re-assign the fields of the binding let stmts_head = match block.stmts { + [] | [_] => return, // Skip the last statement since there cannot possibly be any following statements that re-assign fields. - [head @ .., _] if !head.is_empty() => head, - _ => return, + [head @ .., _] => head, }; for (stmt_idx, stmt) in stmts_head.iter().enumerate() { // find all binding statements like `let mut _ = T::default()` where `T::default()` is the @@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { let (local, variant, binding_name, binding_type, span) = if let StmtKind::Let(local) = stmt.kind // only take `let ...` statements && let Some(expr) = local.init - && !any_parent_is_automatically_derived(cx.tcx, expr.hir_id) + && !in_automatically_derived(cx.tcx, expr.hir_id) && !expr.span.from_expansion() // only take bindings to identifiers && let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index ff631909bcb5..9af73db6849f 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -50,6 +50,8 @@ declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]); impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback { fn check_body(&mut self, cx: &LateContext<'tcx>, body: &Body<'tcx>) { let hir = cx.tcx.hir(); + // NOTE: this is different from `clippy_utils::is_inside_always_const_context`. + // Inline const supports type inference. let is_parent_const = matches!( hir.body_const_context(hir.body_owner_def_id(body.id())), Some(ConstContext::Const { inline: false } | ConstContext::Static(_)) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index a115f8d06314..253f9959e13e 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -3,7 +3,8 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::ty::{implements_trait, is_manually_drop, peel_mid_ty_refs}; use clippy_utils::{ - expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode, + expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, DefinedTy, + ExprUseNode, }; use core::mem; use rustc_ast::util::parser::{PREC_PREFIX, PREC_UNAMBIGUOUS}; @@ -175,6 +176,7 @@ struct StateData<'tcx> { adjusted_ty: Ty<'tcx>, } +#[derive(Debug)] struct DerefedBorrow { count: usize, msg: &'static str, @@ -182,6 +184,7 @@ struct DerefedBorrow { for_field_access: Option, } +#[derive(Debug)] enum State { // Any number of deref method calls. DerefMethod { @@ -744,7 +747,7 @@ fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> boo } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] enum TyCoercionStability { Deref, Reborrow, @@ -1042,16 +1045,28 @@ fn report<'tcx>( return; } - let (prefix, precedence) = if let Some(mutability) = mutability - && !typeck.expr_ty(expr).is_ref() + let ty = typeck.expr_ty(expr); + + // `&&[T; N]`, or `&&..&[T; N]` (src) cannot coerce to `&[T]` (dst). + if let ty::Ref(_, dst, _) = data.adjusted_ty.kind() + && dst.is_slice() { - let prefix = match mutability { - Mutability::Not => "&", - Mutability::Mut => "&mut ", - }; - (prefix, PREC_PREFIX) - } else { - ("", 0) + let (src, n_src_refs) = peel_middle_ty_refs(ty); + if n_src_refs >= 2 && src.is_array() { + return; + } + } + + let (prefix, precedence) = match mutability { + Some(mutability) if !ty.is_ref() => { + let prefix = match mutability { + Mutability::Not => "&", + Mutability::Mut => "&mut ", + }; + (prefix, PREC_PREFIX) + }, + None if !ty.is_ref() && data.adjusted_ty.is_ref() => ("&", 0), + _ => ("", 0), }; span_lint_hir_and_then( cx, diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 9de879604e2e..38fe687f7ccf 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -1,6 +1,6 @@ use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{fn_def_id, get_parent_expr, path_def_id}; +use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -83,26 +83,26 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let uncalled_path = if let Some(parent) = get_parent_expr(cx, expr) - && let ExprKind::Call(receiver, _) = parent.kind - && receiver.hir_id == expr.hir_id - { - None - } else { - path_def_id(cx, expr) + let (id, span) = match &expr.kind { + ExprKind::Path(path) + if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = + cx.qpath_res(path, expr.hir_id) => + { + (id, expr.span) + }, + ExprKind::MethodCall(name, ..) if let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => { + (id, name.ident.span) + }, + _ => return, }; - let Some(def_id) = uncalled_path.or_else(|| fn_def_id(cx, expr)) else { - return; - }; - let conf = match self.disallowed.get(&def_id) { - Some(&index) => &self.conf_disallowed[index], - None => return, - }; - let msg = format!("use of a disallowed method `{}`", conf.path()); - span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, msg, |diag| { - if let Some(reason) = conf.reason() { - diag.note(reason); - } - }); + if let Some(&index) = self.disallowed.get(&id) { + let conf = &self.conf_disallowed[index]; + let msg = format!("use of a disallowed method `{}`", conf.path()); + span_lint_and_then(cx, DISALLOWED_METHODS, span, msg, |diag| { + if let Some(reason) = conf.reason() { + diag.note(reason); + } + }); + } } } diff --git a/clippy_lints/src/disallowed_names.rs b/clippy_lints/src/disallowed_names.rs index 2afbf184117e..58809604c373 100644 --- a/clippy_lints/src/disallowed_names.rs +++ b/clippy_lints/src/disallowed_names.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_test_module_or_function; +use clippy_utils::is_in_test; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::{Item, Pat, PatKind}; +use rustc_hir::{Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -27,52 +27,30 @@ declare_clippy_lint! { #[derive(Clone, Debug)] pub struct DisallowedNames { disallow: FxHashSet, - test_modules_deep: u32, } impl DisallowedNames { pub fn new(disallowed_names: &[String]) -> Self { Self { disallow: disallowed_names.iter().cloned().collect(), - test_modules_deep: 0, } } - - fn in_test_module(&self) -> bool { - self.test_modules_deep != 0 - } } impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]); impl<'tcx> LateLintPass<'tcx> for DisallowedNames { - fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - if is_test_module_or_function(cx.tcx, item) { - self.test_modules_deep = self.test_modules_deep.saturating_add(1); - } - } - fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { - // Check whether we are under the `test` attribute. - if self.in_test_module() { - return; - } - - if let PatKind::Binding(.., ident, _) = pat.kind { - if self.disallow.contains(&ident.name.to_string()) { - span_lint( - cx, - DISALLOWED_NAMES, - ident.span, - format!("use of a disallowed/placeholder name `{}`", ident.name), - ); - } - } - } - - fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - if is_test_module_or_function(cx.tcx, item) { - self.test_modules_deep = self.test_modules_deep.saturating_sub(1); + if let PatKind::Binding(.., ident, _) = pat.kind + && self.disallow.contains(&ident.name.to_string()) + && !is_in_test(cx.tcx, pat.hir_id) + { + span_lint( + cx, + DISALLOWED_NAMES, + ident.span, + format!("use of a disallowed/placeholder name `{}`", ident.name), + ); } } } diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index a995f06fb73d..5ce11900adf8 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -82,30 +82,25 @@ impl EarlyLintPass for DisallowedScriptIdents { // Note: `symbol.as_str()` is an expensive operation, thus should not be called // more than once for a single symbol. let symbol_str = symbol.as_str(); - if symbol_str.is_ascii() { - continue; - } - for c in symbol_str.chars() { - // We want to iterate through all the scripts associated with this character - // and check whether at least of one scripts is in the whitelist. - let forbidden_script = c - .script_extension() - .iter() - .find(|script| !self.whitelist.contains(script)); - if let Some(script) = forbidden_script { - span_lint( - cx, - DISALLOWED_SCRIPT_IDENTS, - span, - format!( - "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}", - script.full_name() - ), - ); - // We don't want to spawn warning multiple times over a single identifier. - break; - } + // Check if any character in the symbol is not part of any allowed script. + // Fast path for ascii-only idents. + if !symbol_str.is_ascii() + && let Some(script) = symbol_str.chars().find_map(|c| { + c.script_extension() + .iter() + .find(|script| !self.whitelist.contains(script)) + }) + { + span_lint( + cx, + DISALLOWED_SCRIPT_IDENTS, + span, + format!( + "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}", + script.full_name() + ), + ); } } } diff --git a/clippy_lints/src/doc/lazy_continuation.rs b/clippy_lints/src/doc/lazy_continuation.rs index 38bc58a55019..bd1cc46e1850 100644 --- a/clippy_lints/src/doc/lazy_continuation.rs +++ b/clippy_lints/src/doc/lazy_continuation.rs @@ -22,6 +22,7 @@ pub(super) fn check( range: Range, mut span: Span, containers: &[super::Container], + line_break_span: Span, ) { if doc[range.clone()].contains('\t') { // We don't do tab stops correctly. @@ -46,11 +47,35 @@ pub(super) fn check( .sum(); if ccount < blockquote_level || lcount < list_indentation { let msg = if ccount < blockquote_level { - "doc quote missing `>` marker" + "doc quote line without `>` marker" } else { - "doc list item missing indentation" + "doc list item without indentation" }; span_lint_and_then(cx, DOC_LAZY_CONTINUATION, span, msg, |diag| { + let snippet = clippy_utils::source::snippet(cx, line_break_span, ""); + if snippet.chars().filter(|&c| c == '\n').count() > 1 + && let Some(doc_comment_start) = snippet.rfind('\n') + && let doc_comment = snippet[doc_comment_start..].trim() + && (doc_comment == "///" || doc_comment == "//!") + { + // suggest filling in a blank line + diag.span_suggestion_with_style( + line_break_span.shrink_to_lo(), + "if this should be its own paragraph, add a blank doc comment line", + format!("\n{doc_comment}"), + Applicability::MaybeIncorrect, + SuggestionStyle::ShowAlways, + ); + if ccount > 0 || blockquote_level > 0 { + diag.help("if this not intended to be a quote at all, escape it with `\\>`"); + } else { + let indent = list_indentation - lcount; + diag.help(format!( + "if this is intended to be part of the list, indent {indent} spaces" + )); + } + return; + } if ccount == 0 && blockquote_level == 0 { // simpler suggestion style for indentation let indent = list_indentation - lcount; diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 3e210fd153bf..a2a1a51920f3 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -6,7 +6,8 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::Visitable; use clippy_utils::{in_constant, is_entrypoint_fn, is_trait_impl_item, method_chain_args}; use pulldown_cmark::Event::{ - Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start, TaskListMarker, Text, + Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start, + TaskListMarker, Text, }; use pulldown_cmark::Tag::{BlockQuote, CodeBlock, FootnoteDefinition, Heading, Item, Link, Paragraph}; use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options, TagEnd}; @@ -747,7 +748,8 @@ fn check_doc<'a, Events: Iterator, Range in_footnote_definition = true, End(TagEnd::FootnoteDefinition) => in_footnote_definition = false, - Start(_) | End(_) => (), // We don't care about other tags + Start(_) | End(_) // We don't care about other tags + | TaskListMarker(_) | Code(_) | Rule | InlineMath(..) | DisplayMath(..) => (), SoftBreak | HardBreak => { if !containers.is_empty() && let Some((next_event, next_range)) = events.peek() @@ -762,13 +764,24 @@ fn check_doc<'a, Events: Iterator, Range (), FootnoteReference(text) | Text(text) => { paragraph_range.end = range.end; - ticks_unbalanced |= text.contains('`') && !in_code; + let range_ = range.clone(); + ticks_unbalanced |= text.contains('`') + && !in_code + && doc[range.clone()].bytes().enumerate().any(|(i, c)| { + // scan the markdown source code bytes for backquotes that aren't preceded by backslashes + // - use bytes, instead of chars, to avoid utf8 decoding overhead (special chars are ascii) + // - relevant backquotes are within doc[range], but backslashes are not, because they're not + // actually part of the rendered text (pulldown-cmark doesn't emit any events for escapes) + // - if `range_.start + i == 0`, then `range_.start + i - 1 == -1`, and since we're working in + // usize, that would underflow and maybe panic + c == b'`' && (range_.start + i == 0 || doc.as_bytes().get(range_.start + i - 1) != Some(&b'\\')) + }); if Some(&text) == in_link.as_ref() || ticks_unbalanced { // Probably a link of the form `` // Which are represented as a link to "http://example.com" with diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs index bb766e963387..99328e3e643f 100644 --- a/clippy_lints/src/endian_bytes.rs +++ b/clippy_lints/src/endian_bytes.rs @@ -33,7 +33,7 @@ declare_clippy_lint! { /// Checks for the usage of the `to_le_bytes` method and/or the function `from_le_bytes`. /// /// ### Why restrict this? - /// To ensure use of big endian or the target’s endianness rather than little endian. + /// To ensure use of big-endian or the target’s endianness rather than little-endian. /// /// ### Example /// ```rust,ignore @@ -51,7 +51,7 @@ declare_clippy_lint! { /// Checks for the usage of the `to_be_bytes` method and/or the function `from_be_bytes`. /// /// ### Why restrict this? - /// To ensure use of little endian or the target’s endianness rather than big endian. + /// To ensure use of little-endian or the target’s endianness rather than big-endian. /// /// ### Example /// ```rust,ignore diff --git a/clippy_lints/src/functions/impl_trait_in_params.rs b/clippy_lints/src/functions/impl_trait_in_params.rs index 6fb38a0d6dd8..cf85c74e688d 100644 --- a/clippy_lints/src/functions/impl_trait_in_params.rs +++ b/clippy_lints/src/functions/impl_trait_in_params.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::is_in_test_function; +use clippy_utils::is_in_test; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; @@ -41,7 +41,7 @@ fn report(cx: &LateContext<'_>, param: &GenericParam<'_>, generics: &Generics<'_ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) { if let FnKind::ItemFn(_, generics, _) = kind && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() - && !is_in_test_function(cx.tcx, hir_id) + && !is_in_test(cx.tcx, hir_id) { for param in generics.params { if param.is_impl_trait() { @@ -59,7 +59,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { && of_trait.is_none() && let body = cx.tcx.hir().body(body_id) && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() - && !is_in_test_function(cx.tcx, impl_item.hir_id()) + && !is_in_test(cx.tcx, impl_item.hir_id()) { for param in impl_item.generics.params { if param.is_impl_trait() { @@ -75,7 +75,7 @@ pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>, && let hir::Node::Item(item) = cx.tcx.parent_hir_node(trait_item.hir_id()) // ^^ (Will always be a trait) && !item.vis_span.is_empty() // Is public - && !is_in_test_function(cx.tcx, trait_item.hir_id()) + && !is_in_test(cx.tcx, trait_item.hir_id()) { for param in trait_item.generics.params { if param.is_impl_trait() { diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs index 35b4481bfee7..5c63d48adaf0 100644 --- a/clippy_lints/src/incompatible_msrv.rs +++ b/clippy_lints/src/incompatible_msrv.rs @@ -1,6 +1,6 @@ use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_in_test_function; +use clippy_utils::is_in_test; use rustc_attr::{StabilityLevel, StableSince}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Expr, ExprKind, HirId}; @@ -88,7 +88,7 @@ impl IncompatibleMsrv { return; } let version = self.get_def_id_version(cx.tcx, def_id); - if self.msrv.meets(version) || is_in_test_function(cx.tcx, node) { + if self.msrv.meets(version) || is_in_test(cx.tcx, node) { return; } if let ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) = span.ctxt().outer_expn_data().kind { diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index 9aedf5ec7e85..ec6174bc0301 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -91,10 +91,6 @@ declare_lint_pass!(InherentToString => [INHERENT_TO_STRING, INHERENT_TO_STRING_S impl<'tcx> LateLintPass<'tcx> for InherentToString { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { - if impl_item.span.from_expansion() { - return; - } - // Check if item is a method called `to_string` and has a parameter 'self' if let ImplItemKind::Fn(ref signature, _) = impl_item.kind // #11201 @@ -106,6 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString { && decl.implicit_self.has_implicit_self() && decl.inputs.len() == 1 && impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) + && !impl_item.span.from_expansion() // Check if return type is String && is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String) // Filters instances of to_string which are required by a trait diff --git a/clippy_lints/src/init_numbered_fields.rs b/clippy_lints/src/init_numbered_fields.rs index 1c8fd0a27f98..7f183bb601eb 100644 --- a/clippy_lints/src/init_numbered_fields.rs +++ b/clippy_lints/src/init_numbered_fields.rs @@ -1,13 +1,12 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::SyntaxContext; use std::borrow::Cow; -use std::cmp::Reverse; -use std::collections::BinaryHeap; declare_clippy_lint! { /// ### What it does @@ -44,38 +43,56 @@ declare_lint_pass!(NumberedFields => [INIT_NUMBERED_FIELDS]); impl<'tcx> LateLintPass<'tcx> for NumberedFields { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::Struct(path, fields, None) = e.kind { - if !fields.is_empty() - && !e.span.from_expansion() - && fields - .iter() - .all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit)) - && !matches!(cx.qpath_res(path, e.hir_id), Res::Def(DefKind::TyAlias, ..)) - { - let expr_spans = fields - .iter() - .map(|f| (Reverse(f.ident.as_str().parse::().unwrap()), f.expr.span)) - .collect::>(); - let mut appl = Applicability::MachineApplicable; - let snippet = format!( - "{}({})", - snippet_with_applicability(cx, path.span(), "..", &mut appl), - expr_spans - .into_iter_sorted() - .map(|(_, span)| snippet_with_context(cx, span, path.span().ctxt(), "..", &mut appl).0) - .intersperse(Cow::Borrowed(", ")) - .collect::() - ); - span_lint_and_sugg( - cx, - INIT_NUMBERED_FIELDS, - e.span, - "used a field initializer for a tuple struct", - "try", - snippet, - appl, - ); - } + if let ExprKind::Struct(path, fields @ [field, ..], None) = e.kind + // If the first character of any field is a digit it has to be a tuple. + && field.ident.as_str().as_bytes().first().is_some_and(u8::is_ascii_digit) + // Type aliases can't be used as functions. + && !matches!( + cx.qpath_res(path, e.hir_id), + Res::Def(DefKind::TyAlias | DefKind::AssocTy, _) + ) + // This is the only syntax macros can use that works for all struct types. + && !e.span.from_expansion() + && let mut has_side_effects = false + && let Ok(mut expr_spans) = fields + .iter() + .map(|f| { + has_side_effects |= f.expr.can_have_side_effects(); + f.ident.as_str().parse::().map(|x| (x, f.expr.span)) + }) + .collect::, _>>() + // We can only reorder the expressions if there are no side effects. + && (!has_side_effects || expr_spans.is_sorted_by_key(|&(idx, _)| idx)) + { + span_lint_and_then( + cx, + INIT_NUMBERED_FIELDS, + e.span, + "used a field initializer for a tuple struct", + |diag| { + if !has_side_effects { + // We already checked the order if there are side effects. + expr_spans.sort_by_key(|&(idx, _)| idx); + } + let mut app = Applicability::MachineApplicable; + diag.span_suggestion( + e.span, + "use tuple initialization", + format!( + "{}({})", + snippet_with_applicability(cx, path.span(), "..", &mut app), + expr_spans + .into_iter() + .map( + |(_, span)| snippet_with_context(cx, span, SyntaxContext::root(), "..", &mut app).0 + ) + .intersperse(Cow::Borrowed(", ")) + .collect::() + ), + app, + ); + }, + ); } } } diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index 860258fd030e..5657c58bb0a4 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -2,12 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::DiagExt; -use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir::{TraitFn, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Symbol}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -34,27 +33,23 @@ declare_lint_pass!(InlineFnWithoutBody => [INLINE_FN_WITHOUT_BODY]); impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { - if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind { - let attrs = cx.tcx.hir().attrs(item.hir_id()); - check_attrs(cx, item.ident.name, attrs); + if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind + && let Some(attr) = cx + .tcx + .hir() + .attrs(item.hir_id()) + .iter() + .find(|a| a.has_name(sym::inline)) + { + span_lint_and_then( + cx, + INLINE_FN_WITHOUT_BODY, + attr.span, + format!("use of `#[inline]` on trait method `{}` which has no body", item.ident), + |diag| { + diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable); + }, + ); } } } - -fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) { - for attr in attrs { - if !attr.has_name(sym::inline) { - continue; - } - - span_lint_and_then( - cx, - INLINE_FN_WITHOUT_BODY, - attr.span, - format!("use of `#[inline]` on trait method `{name}` which has no body"), - |diag| { - diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable); - }, - ); - } -} diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 10b00f632bb0..5fe152d1e301 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -85,16 +85,19 @@ impl LateLintPass<'_> for InstantSubtraction { lhs, rhs, ) = expr.kind + && let typeck = cx.typeck_results() + && ty::is_type_diagnostic_item(cx, typeck.expr_ty(lhs), sym::Instant) { + let rhs_ty = typeck.expr_ty(rhs); + if is_instant_now_call(cx, lhs) - && is_an_instant(cx, rhs) + && ty::is_type_diagnostic_item(cx, rhs_ty, sym::Instant) && let Some(sugg) = Sugg::hir_opt(cx, rhs) { print_manual_instant_elapsed_sugg(cx, expr, sugg); - } else if !expr.span.from_expansion() + } else if ty::is_type_diagnostic_item(cx, rhs_ty, sym::Duration) + && !expr.span.from_expansion() && self.msrv.meets(msrvs::TRY_FROM) - && is_an_instant(cx, lhs) - && is_a_duration(cx, rhs) { print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); } @@ -115,16 +118,6 @@ fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool { } } -fn is_an_instant(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let expr_ty = cx.typeck_results().expr_ty(expr); - ty::is_type_diagnostic_item(cx, expr_ty, sym::Instant) -} - -fn is_a_duration(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let expr_ty = cx.typeck_results().expr_ty(expr); - ty::is_type_diagnostic_item(cx, expr_ty, sym::Duration) -} - fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Sugg<'_>) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index 39223c20470b..a88d8e24fda8 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -54,36 +54,35 @@ declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]); impl LateLintPass<'_> for ItemsAfterStatements { fn check_block(&mut self, cx: &LateContext<'_>, block: &Block<'_>) { - if in_external_macro(cx.sess(), block.span) { - return; - } - - // skip initial items - let stmts = block - .stmts - .iter() - .skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..))); - - // lint on all further items - for stmt in stmts { - if let StmtKind::Item(item_id) = stmt.kind { - let item = cx.tcx.hir().item(item_id); - if in_external_macro(cx.sess(), item.span) || !item.span.eq_ctxt(block.span) { - return; - } - if let ItemKind::Macro(..) = item.kind { - // do not lint `macro_rules`, but continue processing further statements - continue; - } - span_lint_hir( - cx, - ITEMS_AFTER_STATEMENTS, - item.hir_id(), - item.span, - "adding items after statements is confusing, since items exist from the \ - start of the scope", - ); - } + if block.stmts.len() > 1 { + let ctxt = block.span.ctxt(); + let mut in_external = None; + block + .stmts + .iter() + .skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..))) + .filter_map(|stmt| match stmt.kind { + StmtKind::Item(id) => Some(cx.tcx.hir().item(id)), + _ => None, + }) + // Ignore macros since they can only see previously defined locals. + .filter(|item| !matches!(item.kind, ItemKind::Macro(..))) + // Stop linting if macros define items. + .take_while(|item| item.span.ctxt() == ctxt) + // Don't use `next` due to the complex filter chain. + .for_each(|item| { + // Only do the macro check once, but delay it until it's needed. + if !*in_external.get_or_insert_with(|| in_external_macro(cx.sess(), block.span)) { + span_lint_hir( + cx, + ITEMS_AFTER_STATEMENTS, + item.hir_id(), + item.span, + "adding items after statements is confusing, since items exist from the \ + start of the scope", + ); + } + }); } } } diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs index 1b5f1b499475..ba0cd5d6eb35 100644 --- a/clippy_lints/src/iter_not_returning_iterator.rs +++ b/clippy_lints/src/iter_not_returning_iterator.rs @@ -4,7 +4,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::{FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; +use rustc_span::{sym, Symbol}; declare_clippy_lint! { /// ### What it does @@ -43,30 +43,27 @@ declare_lint_pass!(IterNotReturningIterator => [ITER_NOT_RETURNING_ITERATOR]); impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { - let name = item.ident.name.as_str(); - if matches!(name, "iter" | "iter_mut") { - if let TraitItemKind::Fn(fn_sig, _) = &item.kind { - check_sig(cx, name, fn_sig, item.owner_id.def_id); - } + if let TraitItemKind::Fn(fn_sig, _) = &item.kind + && matches!(item.ident.name, sym::iter | sym::iter_mut) + { + check_sig(cx, item.ident.name, fn_sig, item.owner_id.def_id); } } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) { - let name = item.ident.name.as_str(); - if matches!(name, "iter" | "iter_mut") + if let ImplItemKind::Fn(fn_sig, _) = &item.kind + && matches!(item.ident.name, sym::iter | sym::iter_mut) && !matches!( cx.tcx.parent_hir_node(item.hir_id()), Node::Item(Item { kind: ItemKind::Impl(i), .. }) if i.of_trait.is_some() ) { - if let ImplItemKind::Fn(fn_sig, _) = &item.kind { - check_sig(cx, name, fn_sig, item.owner_id.def_id); - } + check_sig(cx, item.ident.name, fn_sig, item.owner_id.def_id); } } } -fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) { +fn check_sig(cx: &LateContext<'_>, name: Symbol, sig: &FnSig<'_>, fn_id: LocalDefId) { if sig.decl.implicit_self.has_implicit_self() { let ret_ty = cx .tcx diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs index 6b03f2597b08..1e6404190d3c 100644 --- a/clippy_lints/src/iter_without_into_iter.rs +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -125,13 +125,13 @@ fn is_ty_exported(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { impl LateLintPass<'_> for IterWithoutIntoIter { fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) { - if !in_external_macro(cx.sess(), item.span) - && let ItemKind::Impl(imp) = item.kind + if let ItemKind::Impl(imp) = item.kind && let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind && let Some(trait_ref) = imp.of_trait && trait_ref .trait_def_id() .is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did)) + && !in_external_macro(cx.sess(), item.span) && let &ty::Ref(_, ty, mtbl) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind() && let expected_method_name = match mtbl { Mutability::Mut => sym::iter_mut, diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index 7f8197c0cc01..b18ab625e609 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -46,12 +46,12 @@ impl_lint_pass!(LargeConstArrays => [LARGE_CONST_ARRAYS]); impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if !item.span.from_expansion() - && let ItemKind::Const(_, generics, _) = &item.kind + if let ItemKind::Const(_, generics, _) = &item.kind // Since static items may not have generics, skip generic const items. // FIXME(generic_const_items): I don't think checking `generics.hwcp` suffices as it // doesn't account for empty where-clauses that only consist of keyword `where` IINM. && generics.params.is_empty() && !generics.has_where_clause_predicates + && !item.span.from_expansion() && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && let ty::Array(element_type, cst) = ty.kind() && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind() diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index 0bf7389ef9cc..85daadcc5373 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -77,17 +77,12 @@ impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]); impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) { - if in_external_macro(cx.tcx.sess, item.span) { - return; - } - if let ItemKind::Enum(ref def, _) = item.kind { - let ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); - let ty::Adt(adt, subst) = ty.kind() else { - panic!("already checked whether this is an enum") - }; - if adt.variants().len() <= 1 { - return; - } + if let ItemKind::Enum(ref def, _) = item.kind + && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() + && let ty::Adt(adt, subst) = ty.kind() + && adt.variants().len() > 1 + && !in_external_macro(cx.tcx.sess, item.span) + { let variants_size = AdtVariantInfo::new(cx, *adt, subst); let mut difference = variants_size[0].size - variants_size[1].size; diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index 07488a512a37..602227e42490 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -54,29 +54,26 @@ impl_lint_pass!(LargeFuture => [LARGE_FUTURES]); impl<'tcx> LateLintPass<'tcx> for LargeFuture { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if matches!(expr.span.ctxt().outer_expn_data().kind, rustc_span::ExpnKind::Macro(..)) { - return; - } - if let ExprKind::Match(expr, _, MatchSource::AwaitDesugar) = expr.kind { - if let ExprKind::Call(func, [expr, ..]) = expr.kind - && let ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) = func.kind - && let ty = cx.typeck_results().expr_ty(expr) - && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() - && implements_trait(cx, ty, future_trait_def_id, &[]) - && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) - && let size = layout.layout.size() - && size >= Size::from_bytes(self.future_size_threshold) - { - span_lint_and_sugg( - cx, - LARGE_FUTURES, - expr.span, - format!("large future with a size of {} bytes", size.bytes()), - "consider `Box::pin` on it", - format!("Box::pin({})", snippet(cx, expr.span, "..")), - Applicability::Unspecified, - ); - } + if let ExprKind::Match(scrutinee, _, MatchSource::AwaitDesugar) = expr.kind + && let ExprKind::Call(func, [arg, ..]) = scrutinee.kind + && let ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) = func.kind + && !expr.span.from_expansion() + && let ty = cx.typeck_results().expr_ty(arg) + && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() + && implements_trait(cx, ty, future_trait_def_id, &[]) + && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) + && let size = layout.layout.size() + && size >= Size::from_bytes(self.future_size_threshold) + { + span_lint_and_sugg( + cx, + LARGE_FUTURES, + arg.span, + format!("large future with a size of {} bytes", size.bytes()), + "consider `Box::pin` on it", + format!("Box::pin({})", snippet(cx, arg.span, "..")), + Applicability::Unspecified, + ); } } } diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs index 07efee159aab..2688283a6ce8 100644 --- a/clippy_lints/src/large_include_file.rs +++ b/clippy_lints/src/large_include_file.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_note; -use clippy_utils::is_lint_allowed; use clippy_utils::macros::root_macro_call_first_node; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; @@ -52,24 +51,19 @@ impl_lint_pass!(LargeIncludeFile => [LARGE_INCLUDE_FILE]); impl LateLintPass<'_> for LargeIncludeFile { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { - if let Some(macro_call) = root_macro_call_first_node(cx, expr) - && !is_lint_allowed(cx, LARGE_INCLUDE_FILE, expr.hir_id) - && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id) - || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id)) - && let ExprKind::Lit(lit) = &expr.kind - { - let len = match &lit.node { + if let ExprKind::Lit(lit) = &expr.kind + && let len = match &lit.node { // include_bytes LitKind::ByteStr(bstr, _) => bstr.len(), // include_str LitKind::Str(sym, _) => sym.as_str().len(), _ => return, - }; - - if len as u64 <= self.max_file_size { - return; } - + && len as u64 > self.max_file_size + && let Some(macro_call) = root_macro_call_first_node(cx, expr) + && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id) + || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id)) + { span_lint_and_note( cx, LARGE_INCLUDE_FILE, diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs index eadfeb6e3418..a08b40bef372 100644 --- a/clippy_lints/src/legacy_numeric_constants.rs +++ b/clippy_lints/src/legacy_numeric_constants.rs @@ -48,15 +48,11 @@ impl_lint_pass!(LegacyNumericConstants => [LEGACY_NUMERIC_CONSTANTS]); impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - let Self { msrv } = self; - - if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), item.span) { - return; - } - // Integer modules are "TBD" deprecated, and the contents are too, // so lint on the `use` statement directly. if let ItemKind::Use(path, kind @ (UseKind::Single | UseKind::Glob)) = item.kind + && self.msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) + && !in_external_macro(cx.sess(), item.span) && let Some(def_id) = path.res[0].opt_def_id() { let module = if is_integer_module(cx, def_id) { @@ -103,12 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { - let Self { msrv } = self; - - if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), expr.span) { - return; - } - let ExprKind::Path(qpath) = expr.kind else { + let ExprKind::Path(qpath) = &expr.kind else { return; }; @@ -129,10 +120,10 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { ) // `::xxx_value` check } else if let QPath::TypeRelative(_, last_segment) = qpath - && let Some(def_id) = cx.qpath_res(&qpath, expr.hir_id).opt_def_id() - && is_integer_method(cx, def_id) + && let Some(def_id) = cx.qpath_res(qpath, expr.hir_id).opt_def_id() && let Some(par_expr) = get_parent_expr(cx, expr) - && let ExprKind::Call(_, _) = par_expr.kind + && let ExprKind::Call(_, []) = par_expr.kind + && is_integer_method(cx, def_id) { let name = last_segment.ident.name.as_str(); @@ -145,19 +136,20 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { return; }; - if is_from_proc_macro(cx, expr) { - return; + if self.msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) + && !in_external_macro(cx.sess(), expr.span) + && !is_from_proc_macro(cx, expr) + { + span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| { + diag.span_suggestion_with_style( + span, + "use the associated constant instead", + sugg, + Applicability::MaybeIncorrect, + SuggestionStyle::ShowAlways, + ); + }); } - - span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| { - diag.span_suggestion_with_style( - span, - "use the associated constant instead", - sugg, - Applicability::MaybeIncorrect, - SuggestionStyle::ShowAlways, - ); - }); } extract_msrv_attr!(LateContext); diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 57e0a7aa2c7e..4c737371bd23 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -121,11 +121,9 @@ declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMP impl<'tcx> LateLintPass<'tcx> for LenZero { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if item.span.from_expansion() { - return; - } - - if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind { + if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind + && !item.span.from_expansion() + { check_trait_items(cx, item, trait_items); } } @@ -162,17 +160,14 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if expr.span.from_expansion() { - return; - } - if let ExprKind::Let(lt) = expr.kind - && has_is_empty(cx, lt.init) && match lt.pat.kind { PatKind::Slice([], None, []) => true, PatKind::Lit(lit) if is_empty_string(lit) => true, _ => false, } + && !expr.span.from_expansion() + && has_is_empty(cx, lt.init) { let mut applicability = Applicability::MachineApplicable; @@ -190,7 +185,9 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { ); } - if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind { + if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind + && !expr.span.from_expansion() + { // expr.span might contains parenthesis, see issue #10529 let actual_span = span_without_enclosing_paren(cx, expr.span); match cmp { diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index a65cb3f4dfb4..0e488cee6b74 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -58,12 +58,10 @@ declare_lint_pass!(LetIfSeq => [USELESS_LET_IF_SEQ]); impl<'tcx> LateLintPass<'tcx> for LetIfSeq { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { - let mut it = block.stmts.iter().peekable(); - while let Some(stmt) = it.next() { - if let Some(expr) = it.peek() - && let hir::StmtKind::Let(local) = stmt.kind + for [stmt, next] in block.stmts.array_windows::<2>() { + if let hir::StmtKind::Let(local) = stmt.kind && let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind - && let hir::StmtKind::Expr(if_) = expr.kind + && let hir::StmtKind::Expr(if_) = next.kind && let hir::ExprKind::If( hir::Expr { kind: hir::ExprKind::DropTemps(cond), diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 9fd4f509aa47..8fa63f3e8fde 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -139,9 +139,9 @@ const SYNC_GUARD_PATHS: [&[&str]; 3] = [ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) { if matches!(local.source, LocalSource::Normal) - && !in_external_macro(cx.tcx.sess, local.span) && let PatKind::Wild = local.pat.kind && let Some(init) = local.init + && !in_external_macro(cx.tcx.sess, local.span) { let init_ty = cx.typeck_results().expr_ty(init); let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() { diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs index 593b29154b42..5a11702d7ce5 100644 --- a/clippy_lints/src/let_with_type_underscore.rs +++ b/clippy_lints/src/let_with_type_underscore.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::source::snippet; +use clippy_utils::is_from_proc_macro; use rustc_hir::{LetStmt, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -25,19 +25,14 @@ declare_clippy_lint! { } declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]); -impl LateLintPass<'_> for UnderscoreTyped { - fn check_local(&mut self, cx: &LateContext<'_>, local: &LetStmt<'_>) { - if !in_external_macro(cx.tcx.sess, local.span) - && let Some(ty) = local.ty // Ensure that it has a type defined +impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) { + if let Some(ty) = local.ty // Ensure that it has a type defined && let TyKind::Infer = &ty.kind // that type is '_' && local.span.eq_ctxt(ty.span) + && !in_external_macro(cx.tcx.sess, local.span) + && !is_from_proc_macro(cx, ty) { - // NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized, - // this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty` - if snippet(cx, ty.span, "_").trim() != "_" { - return; - } - span_lint_and_help( cx, LET_WITH_TYPE_UNDERSCORE, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 32fad0f02cea..c2dc26d6605b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -4,7 +4,9 @@ #![feature(f128)] #![feature(f16)] #![feature(if_let_guard)] +#![feature(is_sorted)] #![feature(iter_intersperse)] +#![feature(iter_partition_in_place)] #![feature(let_chains)] #![cfg_attr(bootstrap, feature(lint_reasons))] #![feature(never_type)] @@ -90,8 +92,10 @@ mod bool_to_int_with_if; mod booleans; mod borrow_deref_ref; mod box_default; +mod byte_char_slices; mod cargo; mod casts; +mod cfg_not_test; mod checked_conversions; mod cognitive_complexity; mod collapsible_if; @@ -212,6 +216,7 @@ mod manual_non_exhaustive; mod manual_range_patterns; mod manual_rem_euclid; mod manual_retain; +mod manual_rotate; mod manual_slice_size_calculation; mod manual_string_new; mod manual_strip; @@ -229,6 +234,7 @@ mod mismatching_type_param_order; mod missing_assert_message; mod missing_asserts_for_indexing; mod missing_const_for_fn; +mod missing_const_for_thread_local; mod missing_doc; mod missing_enforced_import_rename; mod missing_fields_in_debug; @@ -275,9 +281,9 @@ mod only_used_in_recursion; mod operators; mod option_env_unwrap; mod option_if_let_else; -mod overflow_check_conditional; mod panic_in_result_fn; mod panic_unimplemented; +mod panicking_overflow_checks; mod partial_pub_fields; mod partialeq_ne_impl; mod partialeq_to_none; @@ -318,6 +324,7 @@ mod self_named_constructors; mod semicolon_block; mod semicolon_if_nothing_returned; mod serde_api; +mod set_contains_or_insert; mod shadow; mod significant_drop_tightening; mod single_call_fn; @@ -339,7 +346,6 @@ mod swap_ptr_to_ref; mod tabs_in_doc_comments; mod temporary_assignment; mod tests_outside_test_module; -mod thread_local_initializer_can_be_made_const; mod to_digit_is_some; mod to_string_trait_impl; mod trailing_empty_array; @@ -639,9 +645,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { }); store.register_early_pass(|| Box::new(utils::internal_lints::produce_ice::ProduceIce)); store.register_late_pass(|_| Box::new(utils::internal_lints::collapsible_calls::CollapsibleCalls)); - store.register_late_pass(|_| { - Box::new(utils::internal_lints::compiler_lint_functions::CompilerLintFunctions::new()) - }); store.register_late_pass(|_| Box::new(utils::internal_lints::invalid_paths::InvalidPaths)); store.register_late_pass(|_| { Box::::default() @@ -788,7 +791,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { let format_args = format_args_storage.clone(); store.register_late_pass(move |_| Box::new(format::UselessFormat::new(format_args.clone()))); store.register_late_pass(|_| Box::new(swap::Swap)); - store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional)); + store.register_late_pass(|_| Box::new(panicking_overflow_checks::PanickingOverflowChecks)); store.register_late_pass(|_| Box::::default()); store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names))); store.register_late_pass(move |_| { @@ -1024,6 +1027,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty)); store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv()))); store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv()))); + store.register_late_pass(move |_| Box::new(manual_rotate::ManualRotate)); store.register_late_pass(move |_| { Box::new(operators::Operators::new( verbose_bit_mask_threshold, @@ -1153,9 +1157,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { behavior: pub_underscore_fields_behavior, }) }); - store.register_late_pass(move |_| { - Box::new(thread_local_initializer_can_be_made_const::ThreadLocalInitializerCanBeMadeConst::new(msrv())) - }); + store + .register_late_pass(move |_| Box::new(missing_const_for_thread_local::MissingConstForThreadLocal::new(msrv()))); store.register_late_pass(move |_| Box::new(incompatible_msrv::IncompatibleMsrv::new(msrv()))); store.register_late_pass(|_| Box::new(to_string_trait_impl::ToStringTraitImpl)); store.register_early_pass(|| Box::new(multiple_bound_locations::MultipleBoundLocations)); @@ -1171,6 +1174,9 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { }); store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(msrv()))); store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers)); + store.register_late_pass(|_| Box::new(set_contains_or_insert::HashsetInsertAfterContains)); + store.register_early_pass(|| Box::new(byte_char_slices::ByteCharSlice)); + store.register_early_pass(|| Box::new(cfg_not_test::CfgNotTest)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index d2a140a36a83..7481543941a6 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -233,11 +233,9 @@ 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) { - return; - } - - if let ExprKind::Lit(lit) = expr.kind { + if let ExprKind::Lit(lit) = expr.kind + && !in_external_macro(cx.sess(), expr.span) + { self.check_lit(cx, lit, expr.span); } } @@ -448,11 +446,9 @@ 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) { - return; - } - - if let ExprKind::Lit(lit) = expr.kind { + if let ExprKind::Lit(lit) = expr.kind + && !in_external_macro(cx.sess(), expr.span) + { self.check_lit(cx, lit, expr.span); } } diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index 24fc2b4faeac..d9f6be6dc2b5 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -50,13 +50,10 @@ impl_lint_pass!(ManualBits => [MANUAL_BITS]); impl<'tcx> LateLintPass<'tcx> for ManualBits { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !self.msrv.meets(msrvs::MANUAL_BITS) { - return; - } - if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind && let BinOpKind::Mul = &bin_op.node && !in_external_macro(cx.sess(), expr.span) + && self.msrv.meets(msrvs::MANUAL_BITS) && let ctxt = expr.span.ctxt() && left_expr.span.ctxt() == ctxt && right_expr.span.ctxt() == ctxt diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index 89eea0b4456d..03416ba96de7 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -82,29 +82,26 @@ impl Variant { impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if !in_external_macro(cx.sess(), expr.span) - && ( - matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst) - || cx.tcx.features().declared(sym!(const_float_classify)) - ) && let ExprKind::Binary(kind, lhs, rhs) = expr.kind + if let ExprKind::Binary(kind, lhs, rhs) = expr.kind && let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind && let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind // Checking all possible scenarios using a function would be a hopeless task, as we have // 16 possible alignments of constants/operands. For now, let's use `partition`. - && let (operands, constants) = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs] - .into_iter() - .partition::>, _>(|i| path_to_local(i).is_some()) - && let [first, second] = &*operands - && let Some([const_1, const_2]) = constants - .into_iter() - .map(|i| constant(cx, cx.typeck_results(), i)) - .collect::>>() - .as_deref() + && let mut exprs = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs] + && exprs.iter_mut().partition_in_place(|i| path_to_local(i).is_some()) == 2 + && !in_external_macro(cx.sess(), expr.span) + && ( + matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst) + || cx.tcx.features().declared(sym!(const_float_classify)) + ) + && let [first, second, const_1, const_2] = exprs + && let Some(const_1) = constant(cx, cx.typeck_results(), const_1) + && let Some(const_2) = constant(cx, cx.typeck_results(), const_2) && path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s)) // The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in // case somebody does that for some reason - && (is_infinity(const_1) && is_neg_infinity(const_2) - || is_neg_infinity(const_1) && is_infinity(const_2)) + && (is_infinity(&const_1) && is_neg_infinity(&const_2) + || is_neg_infinity(&const_1) && is_infinity(&const_2)) && let Some(local_snippet) = snippet_opt(cx, first.span) { let variant = match (kind.node, lhs_kind.node, rhs_kind.node) { diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 03e4d668dd8f..ebebdf679a86 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -49,16 +49,14 @@ declare_clippy_lint! { impl<'tcx> QuestionMark { pub(crate) fn check_manual_let_else(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) { - if !self.msrv.meets(msrvs::LET_ELSE) || in_external_macro(cx.sess(), stmt.span) { - return; - } - if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && local.els.is_none() && local.ty.is_none() && init.span.eq_ctxt(stmt.span) && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) + && self.msrv.meets(msrvs::LET_ELSE) + && !in_external_macro(cx.sess(), stmt.span) { match if_let_or_match { IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else, ..) => { diff --git a/clippy_lints/src/manual_main_separator_str.rs b/clippy_lints/src/manual_main_separator_str.rs index 5732bdda7f2c..8e8cdc3fb076 100644 --- a/clippy_lints/src/manual_main_separator_str.rs +++ b/clippy_lints/src/manual_main_separator_str.rs @@ -47,13 +47,13 @@ impl_lint_pass!(ManualMainSeparatorStr => [MANUAL_MAIN_SEPARATOR_STR]); impl LateLintPass<'_> for ManualMainSeparatorStr { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) - && let (target, _) = peel_hir_expr_refs(expr) - && is_trait_method(cx, target, sym::ToString) - && let ExprKind::MethodCall(path, receiver, &[], _) = target.kind + let (target, _) = peel_hir_expr_refs(expr); + if let ExprKind::MethodCall(path, receiver, &[], _) = target.kind && path.ident.name == sym::to_string && let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind && let Res::Def(DefKind::Const, receiver_def_id) = path.res + && is_trait_method(cx, target, sym::ToString) + && self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) && match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR) && let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind() && ty.is_str() diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index d2ac0ad8363e..73a505fd73ff 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -97,19 +97,15 @@ impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]); impl EarlyLintPass for ManualNonExhaustiveStruct { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { - if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) { - return; - } - - if let ast::ItemKind::Struct(variant_data, _) = &item.kind { - let (fields, delimiter) = match variant_data { + if let ast::ItemKind::Struct(variant_data, _) = &item.kind + && let (fields, delimiter) = match variant_data { ast::VariantData::Struct { fields, .. } => (&**fields, '{'), ast::VariantData::Tuple(fields, _) => (&**fields, '('), ast::VariantData::Unit(_) => return, - }; - if fields.len() <= 1 { - return; } + && fields.len() > 1 + && self.msrv.meets(msrvs::NON_EXHAUSTIVE) + { let mut iter = fields.iter().filter_map(|f| match f.vis.kind { VisibilityKind::Public => None, VisibilityKind::Inherited => Some(Ok(f)), diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs index ec60de92c4ba..07d4abbf5cd1 100644 --- a/clippy_lints/src/manual_range_patterns.rs +++ b/clippy_lints/src/manual_range_patterns.rs @@ -76,14 +76,11 @@ impl Num { impl LateLintPass<'_> for ManualRangePatterns { fn check_pat(&mut self, cx: &LateContext<'_>, pat: &'_ rustc_hir::Pat<'_>) { - if in_external_macro(cx.sess(), pat.span) { - return; - } - // a pattern like 1 | 2 seems fine, lint if there are at least 3 alternatives // or at least one range if let PatKind::Or(pats) = pat.kind && (pats.len() >= 3 || pats.iter().any(|p| matches!(p.kind, PatKind::Range(..)))) + && !in_external_macro(cx.sess(), pat.span) { let mut min = Num::dummy(i128::MAX); let mut max = Num::dummy(i128::MIN); diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs index ab9bca170cf7..b518dc26937c 100644 --- a/clippy_lints/src/manual_rem_euclid.rs +++ b/clippy_lints/src/manual_rem_euclid.rs @@ -48,35 +48,30 @@ impl_lint_pass!(ManualRemEuclid => [MANUAL_REM_EUCLID]); impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !self.msrv.meets(msrvs::REM_EUCLID) { - return; - } - - if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::REM_EUCLID_CONST) { - return; - } - - if in_external_macro(cx.sess(), expr.span) { - return; - } - // (x % c + c) % c - if let ExprKind::Binary(op1, expr1, right) = expr.kind - && op1.node == BinOpKind::Rem + if let ExprKind::Binary(rem_op, rem_lhs, rem_rhs) = expr.kind + && rem_op.node == BinOpKind::Rem + && let ExprKind::Binary(add_op, add_lhs, add_rhs) = rem_lhs.kind + && add_op.node == BinOpKind::Add && let ctxt = expr.span.ctxt() - && expr1.span.ctxt() == ctxt - && let Some(const1) = check_for_unsigned_int_constant(cx, right) - && let ExprKind::Binary(op2, left, right) = expr1.kind - && op2.node == BinOpKind::Add - && let Some((const2, expr2)) = check_for_either_unsigned_int_constant(cx, left, right) - && expr2.span.ctxt() == ctxt - && let ExprKind::Binary(op3, expr3, right) = expr2.kind - && op3.node == BinOpKind::Rem - && let Some(const3) = check_for_unsigned_int_constant(cx, right) + && rem_lhs.span.ctxt() == ctxt + && rem_rhs.span.ctxt() == ctxt + && add_lhs.span.ctxt() == ctxt + && add_rhs.span.ctxt() == ctxt + && !in_external_macro(cx.sess(), expr.span) + && self.msrv.meets(msrvs::REM_EUCLID) + && (self.msrv.meets(msrvs::REM_EUCLID_CONST) || !in_constant(cx, expr.hir_id)) + && let Some(const1) = check_for_unsigned_int_constant(cx, rem_rhs) + && let Some((const2, add_other)) = check_for_either_unsigned_int_constant(cx, add_lhs, add_rhs) + && let ExprKind::Binary(rem2_op, rem2_lhs, rem2_rhs) = add_other.kind + && rem2_op.node == BinOpKind::Rem + && const1 == const2 + && let Some(hir_id) = path_to_local(rem2_lhs) + && let Some(const3) = check_for_unsigned_int_constant(cx, rem2_rhs) // Also ensures the const is nonzero since zero can't be a divisor - && const1 == const2 && const2 == const3 - && let Some(hir_id) = path_to_local(expr3) - && let Node::Pat(_) = cx.tcx.hir_node(hir_id) + && const2 == const3 + && rem2_lhs.span.ctxt() == ctxt + && rem2_rhs.span.ctxt() == ctxt { // Apply only to params or locals with annotated types match cx.tcx.parent_hir_node(hir_id) { @@ -91,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { }; let mut app = Applicability::MachineApplicable; - let rem_of = snippet_with_context(cx, expr3.span, ctxt, "_", &mut app).0; + let rem_of = snippet_with_context(cx, rem2_lhs.span, ctxt, "_", &mut app).0; span_lint_and_sugg( cx, MANUAL_REM_EUCLID, diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index 3ddb06a1e08a..8f7b8abd0c38 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -70,9 +70,8 @@ impl_lint_pass!(ManualRetain => [MANUAL_RETAIN]); impl<'tcx> LateLintPass<'tcx> for ManualRetain { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if let Assign(left_expr, collect_expr, _) = &expr.kind - && let hir::ExprKind::MethodCall(seg, ..) = &collect_expr.kind + && let hir::ExprKind::MethodCall(seg, target_expr, [], _) = &collect_expr.kind && seg.args.is_none() - && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id) && cx.tcx.is_diagnostic_item(sym::iterator_collect_fn, collect_def_id) { diff --git a/clippy_lints/src/manual_rotate.rs b/clippy_lints/src/manual_rotate.rs new file mode 100644 index 000000000000..a517a4d50752 --- /dev/null +++ b/clippy_lints/src/manual_rotate.rs @@ -0,0 +1,117 @@ +use std::fmt::Display; + +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sugg; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// + /// It detects manual bit rotations that could be rewritten using standard + /// functions `rotate_left` or `rotate_right`. + /// + /// ### Why is this bad? + /// + /// Calling the function better conveys the intent. + /// + /// ### Known issues + /// + /// Currently, the lint only catches shifts by constant amount. + /// + /// ### Example + /// ```no_run + /// let x = 12345678_u32; + /// let _ = (x >> 8) | (x << 24); + /// ``` + /// Use instead: + /// ```no_run + /// let x = 12345678_u32; + /// let _ = x.rotate_right(8); + /// ``` + #[clippy::version = "1.81.0"] + pub MANUAL_ROTATE, + style, + "using bit shifts to rotate integers" +} + +declare_lint_pass!(ManualRotate => [MANUAL_ROTATE]); + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum ShiftDirection { + Left, + Right, +} + +impl Display for ShiftDirection { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + Self::Left => "rotate_left", + Self::Right => "rotate_right", + }) + } +} + +fn parse_shift<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, +) -> Option<(ShiftDirection, u128, &'tcx Expr<'tcx>)> { + if let ExprKind::Binary(op, l, r) = expr.kind { + let dir = match op.node { + BinOpKind::Shl => ShiftDirection::Left, + BinOpKind::Shr => ShiftDirection::Right, + _ => return None, + }; + let const_expr = constant(cx, cx.typeck_results(), r)?; + if let Constant::Int(shift) = const_expr { + return Some((dir, shift, l)); + } + } + None +} + +impl LateLintPass<'_> for ManualRotate { + fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if let ExprKind::Binary(op, l, r) = expr.kind + && let BinOpKind::Add | BinOpKind::BitOr = op.node + && let Some((l_shift_dir, l_amount, l_expr)) = parse_shift(cx, l) + && let Some((r_shift_dir, r_amount, r_expr)) = parse_shift(cx, r) + { + if l_shift_dir == r_shift_dir { + return; + } + if !clippy_utils::eq_expr_value(cx, l_expr, r_expr) { + return; + } + let Some(bit_width) = (match cx.typeck_results().expr_ty(expr).kind() { + ty::Int(itype) => itype.bit_width(), + ty::Uint(itype) => itype.bit_width(), + _ => return, + }) else { + return; + }; + if l_amount + r_amount == u128::from(bit_width) { + let (shift_function, amount) = if l_amount < r_amount { + (l_shift_dir, l_amount) + } else { + (r_shift_dir, r_amount) + }; + let mut applicability = Applicability::MachineApplicable; + let expr_sugg = sugg::Sugg::hir_with_applicability(cx, l_expr, "_", &mut applicability).maybe_par(); + span_lint_and_sugg( + cx, + MANUAL_ROTATE, + expr.span, + "there is no need to manually implement bit rotation", + "this expression can be rewritten as", + format!("{expr_sugg}.{shift_function}({amount})"), + Applicability::MachineApplicable, + ); + } + } + } +} diff --git a/clippy_lints/src/manual_slice_size_calculation.rs b/clippy_lints/src/manual_slice_size_calculation.rs index 1de686dbcb51..429ee2637c2f 100644 --- a/clippy_lints/src/manual_slice_size_calculation.rs +++ b/clippy_lints/src/manual_slice_size_calculation.rs @@ -40,11 +40,11 @@ declare_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION] impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - // Does not apply inside const because size_of_val is not cost in stable. - if !in_constant(cx, expr.hir_id) - && let ExprKind::Binary(ref op, left, right) = expr.kind + if let ExprKind::Binary(ref op, left, right) = expr.kind && BinOpKind::Mul == op.node && !expr.span.from_expansion() + // Does not apply inside const because size_of_val is not cost in stable. + && !in_constant(cx, expr.hir_id) && let Some(receiver) = simplify(cx, left, right) { let ctxt = expr.span.ctxt(); diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 45af9f07718d..6a523ad15647 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -66,14 +66,11 @@ enum StripKind { impl<'tcx> LateLintPass<'tcx> for ManualStrip { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !self.msrv.meets(msrvs::STR_STRIP_PREFIX) { - return; - } - if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr) && let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind - && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id) && let ExprKind::Path(target_path) = &target_arg.kind + && self.msrv.meets(msrvs::STR_STRIP_PREFIX) + && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id) { let strip_kind = if match_def_path(cx, method_def_id, &paths::STR_STARTS_WITH) { StripKind::Prefix diff --git a/clippy_lints/src/manual_unwrap_or_default.rs b/clippy_lints/src/manual_unwrap_or_default.rs index 58b2ebebbf08..f1acc4b21748 100644 --- a/clippy_lints/src/manual_unwrap_or_default.rs +++ b/clippy_lints/src/manual_unwrap_or_default.rs @@ -172,11 +172,10 @@ fn handle<'tcx>(cx: &LateContext<'tcx>, if_let_or_match: IfLetOrMatch<'tcx>, exp impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if expr.span.from_expansion() || in_constant(cx, expr.hir_id) { - return; - } - // Call handle only if the expression is `if let` or `match` - if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr) { + if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr) + && !expr.span.from_expansion() + && !in_constant(cx, expr.hir_id) + { handle(cx, if_let_or_match, expr); } } diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 9db04b615be7..2db71b1f7a38 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -253,14 +253,11 @@ fn lint_map_unit_fn( impl<'tcx> LateLintPass<'tcx> for MapUnit { fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) { - if stmt.span.from_expansion() { - return; - } - - if let hir::StmtKind::Semi(expr) = stmt.kind { - if let Some(arglists) = method_chain_args(expr, &["map"]) { - lint_map_unit_fn(cx, stmt, expr, arglists[0]); - } + if let hir::StmtKind::Semi(expr) = stmt.kind + && !stmt.span.from_expansion() + && let Some(arglists) = method_chain_args(expr, &["map"]) + { + lint_map_unit_fn(cx, stmt, expr, arglists[0]); } } } diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index bf7156cc53ec..22a299ae3d82 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -1019,6 +1019,7 @@ impl_lint_pass!(Matches => [ ]); impl<'tcx> LateLintPass<'tcx> for Matches { + #[expect(clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if is_direct_expn_of(expr.span, "matches").is_none() && in_external_macro(cx.sess(), expr.span) { return; @@ -1037,7 +1038,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { return; } if matches!(source, MatchSource::Normal | MatchSource::ForLoopDesugar) { - significant_drop_in_scrutinee::check(cx, expr, ex, arms, source); + significant_drop_in_scrutinee::check_match(cx, expr, ex, arms, source); } collapsible_match::check_match(cx, arms, &self.msrv); @@ -1084,6 +1085,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { } } else if let Some(if_let) = higher::IfLet::hir(cx, expr) { collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else, &self.msrv); + significant_drop_in_scrutinee::check_if_let(cx, expr, if_let.let_expr, if_let.if_then, if_let.if_else); if !from_expansion { if let Some(else_expr) = if_let.if_else { if self.msrv.meets(msrvs::MATCHES_MACRO) { @@ -1126,8 +1128,13 @@ impl<'tcx> LateLintPass<'tcx> for Matches { ); needless_match::check_if_let(cx, expr, &if_let); } - } else if !from_expansion { - redundant_pattern_match::check(cx, expr); + } else { + if let Some(while_let) = higher::WhileLet::hir(expr) { + significant_drop_in_scrutinee::check_while_let(cx, expr, while_let.let_expr, while_let.if_then); + } + if !from_expansion { + redundant_pattern_match::check(cx, expr); + } } } diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 2f72e59834fa..9047c9627d9a 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -16,7 +16,7 @@ use rustc_span::Span; use super::SIGNIFICANT_DROP_IN_SCRUTINEE; -pub(super) fn check<'tcx>( +pub(super) fn check_match<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, scrutinee: &'tcx Expr<'_>, @@ -27,10 +27,89 @@ pub(super) fn check<'tcx>( return; } - let (suggestions, message) = has_significant_drop_in_scrutinee(cx, scrutinee, source); + let scrutinee = match (source, &scrutinee.kind) { + (MatchSource::ForLoopDesugar, ExprKind::Call(_, [e])) => e, + _ => scrutinee, + }; + + let message = if source == MatchSource::Normal { + "temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression" + } else { + "temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression" + }; + + let arms = arms.iter().map(|arm| arm.body).collect::>(); + + check(cx, expr, scrutinee, &arms, message, Suggestion::Emit); +} + +pub(super) fn check_if_let<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + scrutinee: &'tcx Expr<'_>, + if_then: &'tcx Expr<'_>, + if_else: Option<&'tcx Expr<'_>>, +) { + if is_lint_allowed(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, expr.hir_id) { + return; + } + + let message = + "temporary with significant `Drop` in `if let` scrutinee will live until the end of the `if let` expression"; + + if let Some(if_else) = if_else { + check(cx, expr, scrutinee, &[if_then, if_else], message, Suggestion::Emit); + } else { + check(cx, expr, scrutinee, &[if_then], message, Suggestion::Emit); + } +} + +pub(super) fn check_while_let<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + scrutinee: &'tcx Expr<'_>, + body: &'tcx Expr<'_>, +) { + if is_lint_allowed(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, expr.hir_id) { + return; + } + + check( + cx, + expr, + scrutinee, + &[body], + "temporary with significant `Drop` in `while let` scrutinee will live until the end of the `while let` expression", + // Don't emit wrong suggestions: We cannot fix the significant drop in the `while let` scrutinee by simply + // moving it out. We need to change the `while` to a `loop` instead. + Suggestion::DontEmit, + ); +} + +#[derive(Copy, Clone, Debug)] +enum Suggestion { + Emit, + DontEmit, +} + +fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + scrutinee: &'tcx Expr<'_>, + arms: &[&'tcx Expr<'_>], + message: &'static str, + sugg: Suggestion, +) { + let mut helper = SigDropHelper::new(cx); + let suggestions = helper.find_sig_drop(scrutinee); + for found in suggestions { span_lint_and_then(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, found.found_span, message, |diag| { - set_diagnostic(diag, cx, expr, found); + match sugg { + Suggestion::Emit => set_suggestion(diag, cx, expr, found), + Suggestion::DontEmit => (), + } + let s = Span::new(expr.span.hi(), expr.span.hi(), expr.span.ctxt(), None); diag.span_label(s, "temporary lives until here"); for span in has_significant_drop_in_arms(cx, arms) { @@ -41,7 +120,7 @@ pub(super) fn check<'tcx>( } } -fn set_diagnostic<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) { +fn set_suggestion<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) { let original = snippet(cx, found.found_span, ".."); let trailing_indent = " ".repeat(indent_of(cx, found.found_span).unwrap_or(0)); @@ -79,26 +158,6 @@ fn set_diagnostic<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: & ); } -/// If the expression is an `ExprKind::Match`, check if the scrutinee has a significant drop that -/// may have a surprising lifetime. -fn has_significant_drop_in_scrutinee<'tcx>( - cx: &LateContext<'tcx>, - scrutinee: &'tcx Expr<'tcx>, - source: MatchSource, -) -> (Vec, &'static str) { - let mut helper = SigDropHelper::new(cx); - let scrutinee = match (source, &scrutinee.kind) { - (MatchSource::ForLoopDesugar, ExprKind::Call(_, [e])) => e, - _ => scrutinee, - }; - let message = if source == MatchSource::Normal { - "temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression" - } else { - "temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression" - }; - (helper.find_sig_drop(scrutinee), message) -} - struct SigDropChecker<'a, 'tcx> { seen_types: FxHashSet>, cx: &'a LateContext<'tcx>, @@ -428,10 +487,10 @@ impl<'a, 'tcx> ArmSigDropHelper<'a, 'tcx> { } } -fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) -> FxHashSet { +fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &[&'tcx Expr<'_>]) -> FxHashSet { let mut helper = ArmSigDropHelper::new(cx); for arm in arms { - helper.visit_expr(arm.body); + helper.visit_expr(arm); } helper.found_sig_drop_spans } diff --git a/clippy_lints/src/methods/manual_inspect.rs b/clippy_lints/src/methods/manual_inspect.rs index e3ce64c246a5..cac2e11f5916 100644 --- a/clippy_lints/src/methods/manual_inspect.rs +++ b/clippy_lints/src/methods/manual_inspect.rs @@ -167,14 +167,12 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: } else { edits.extend(addr_of_edits); } - edits.push(( - name_span, - String::from(match name { - "map" => "inspect", - "map_err" => "inspect_err", - _ => return, - }), - )); + let edit = match name { + "map" => "inspect", + "map_err" => "inspect_err", + _ => return, + }; + edits.push((name_span, edit.to_string())); edits.push(( final_expr .span @@ -187,9 +185,15 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: } else { Applicability::MachineApplicable }; - span_lint_and_then(cx, MANUAL_INSPECT, name_span, "", |diag| { - diag.multipart_suggestion("try", edits, app); - }); + span_lint_and_then( + cx, + MANUAL_INSPECT, + name_span, + format!("using `{name}` over `{edit}`"), + |diag| { + diag.multipart_suggestion("try", edits, app); + }, + ); } } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1408f4548200..a846552cddfa 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -628,12 +628,11 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or - /// `_.or_else(|x| Err(y))`. + /// Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` + /// or `_.or_else(|x| Err(y))`. /// /// ### Why is this bad? - /// Readability, this can be written more concisely as - /// `_.map(|x| y)` or `_.map_err(|x| y)`. + /// This can be written more concisely as `_.map(|x| y)` or `_.map_err(|x| y)`. /// /// ### Example /// ```no_run @@ -4121,7 +4120,7 @@ declare_clippy_lint! { /// ```no_run /// let x = Some(0).inspect(|x| println!("{x}")); /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.81.0"] pub MANUAL_INSPECT, complexity, "use of `map` returning the original item" diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index ae9aa83efd68..5d899415d772 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -1,13 +1,15 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_config::msrvs::{self, Msrv}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::{ get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item, peel_mid_ty_refs, }; use clippy_utils::visitors::find_all_ret_expressions; -use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty}; +use clippy_utils::{ + fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, match_def_path, paths, return_ty, +}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -52,6 +54,9 @@ pub fn check<'tcx>( if check_into_iter_call_arg(cx, expr, method_name, receiver, msrv) { return; } + if check_string_from_utf8(cx, expr, receiver) { + return; + } check_other_call_arg(cx, expr, method_name, receiver); } } else { @@ -240,6 +245,65 @@ fn check_into_iter_call_arg( false } +/// Checks for `&String::from_utf8(bytes.{to_vec,to_owned,...}()).unwrap()` coercing to `&str`, +/// which can be written as just `std::str::from_utf8(bytes).unwrap()`. +fn check_string_from_utf8<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, receiver: &'tcx Expr<'tcx>) -> bool { + if let Some((call, arg)) = skip_addr_of_ancestors(cx, expr) + && !arg.span.from_expansion() + && let ExprKind::Call(callee, _) = call.kind + && fn_def_id(cx, call).is_some_and(|did| match_def_path(cx, did, &paths::STRING_FROM_UTF8)) + && let Some(unwrap_call) = get_parent_expr(cx, call) + && let ExprKind::MethodCall(unwrap_method_name, ..) = unwrap_call.kind + && matches!(unwrap_method_name.ident.name, sym::unwrap | sym::expect) + && let Some(ref_string) = get_parent_expr(cx, unwrap_call) + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = ref_string.kind + && let adjusted_ty = cx.typeck_results().expr_ty_adjusted(ref_string) + // `&...` creates a `&String`, so only actually lint if this coerces to a `&str` + && matches!(adjusted_ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) + { + span_lint_and_then( + cx, + UNNECESSARY_TO_OWNED, + ref_string.span, + "allocating a new `String` only to create a temporary `&str` from it", + |diag| { + let arg_suggestion = format!( + "{borrow}{recv_snippet}", + recv_snippet = snippet(cx, receiver.span.source_callsite(), ".."), + borrow = if cx.typeck_results().expr_ty(receiver).is_ref() { + "" + } else { + // If not already a reference, prefix with a borrow so that it can coerce to one + "&" + } + ); + + diag.multipart_suggestion( + "convert from `&[u8]` to `&str` directly", + vec![ + // `&String::from_utf8(bytes.to_vec()).unwrap()` + // ^^^^^^^^^^^^^^^^^ + (callee.span, "core::str::from_utf8".into()), + // `&String::from_utf8(bytes.to_vec()).unwrap()` + // ^ + ( + ref_string.span.shrink_to_lo().to(unwrap_call.span.shrink_to_lo()), + String::new(), + ), + // `&String::from_utf8(bytes.to_vec()).unwrap()` + // ^^^^^^^^^^^^^^ + (arg.span, arg_suggestion), + ], + Applicability::MachineApplicable, + ); + }, + ); + true + } else { + false + } +} + /// Checks whether `expr` is an argument in an `into_iter` call and, if so, determines whether its /// call of a `to_owned`-like function is unnecessary. fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool { diff --git a/clippy_lints/src/methods/unwrap_expect_used.rs b/clippy_lints/src/methods/unwrap_expect_used.rs index 516b8984ad79..5b0bd0f716ab 100644 --- a/clippy_lints/src/methods/unwrap_expect_used.rs +++ b/clippy_lints/src/methods/unwrap_expect_used.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::{is_never_like, is_type_diagnostic_item}; -use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed}; +use clippy_utils::{is_in_test, is_lint_allowed}; use rustc_hir::Expr; use rustc_lint::{LateContext, Lint}; use rustc_middle::ty; @@ -61,7 +61,7 @@ pub(super) fn check( let method_suffix = if is_err { "_err" } else { "" }; - if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) { + if allow_unwrap_in_tests && is_in_test(cx.tcx, expr.hir_id) { return; } diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index fca626fa5c35..c3fbca1d560e 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::sym; -use std::cmp::Ordering; +use std::cmp::Ordering::{Equal, Greater, Less}; declare_clippy_lint! { /// ### What it does @@ -36,26 +36,21 @@ declare_lint_pass!(MinMaxPass => [MIN_MAX]); impl<'tcx> LateLintPass<'tcx> for MinMaxPass { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some((outer_max, outer_c, oe)) = min_max(cx, expr) { - if let Some((inner_max, inner_c, ie)) = min_max(cx, oe) { - if outer_max == inner_max { - return; - } - match ( - outer_max, - Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(ie), &outer_c, &inner_c), - ) { - (_, None) | (MinMax::Max, Some(Ordering::Less)) | (MinMax::Min, Some(Ordering::Greater)) => (), - _ => { - span_lint( - cx, - MIN_MAX, - expr.span, - "this `min`/`max` combination leads to constant result", - ); - }, - } - } + if let Some((outer_max, outer_c, oe)) = min_max(cx, expr) + && let Some((inner_max, inner_c, ie)) = min_max(cx, oe) + && outer_max != inner_max + && let Some(ord) = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(ie), &outer_c, &inner_c) + && matches!( + (outer_max, ord), + (MinMax::Max, Equal | Greater) | (MinMax::Min, Equal | Less) + ) + { + span_lint( + cx, + MIN_MAX, + expr.span, + "this `min`/`max` combination leads to constant result", + ); } } } diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index f3f9bf11a61c..32c8731c5374 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -2,8 +2,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then, span_lint_hir_and use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::{ - any_parent_is_automatically_derived, fulfill_or_allowed, get_parent_expr, is_lint_allowed, iter_input_pats, - last_path_segment, SpanlessEq, + fulfill_or_allowed, get_parent_expr, in_automatically_derived, is_lint_allowed, iter_input_pats, last_path_segment, + SpanlessEq, }; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -206,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if in_external_macro(cx.sess(), expr.span) || expr.span.desugaring_kind().is_some() - || any_parent_is_automatically_derived(cx.tcx, expr.hir_id) + || in_automatically_derived(cx.tcx, expr.hir_id) { return; } diff --git a/clippy_lints/src/missing_assert_message.rs b/clippy_lints/src/missing_assert_message.rs index dd98352da860..935ed48dacc5 100644 --- a/clippy_lints/src/missing_assert_message.rs +++ b/clippy_lints/src/missing_assert_message.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_in_test; use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_call_first_node, PanicExpn}; -use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingAssertMessage { }; // This lint would be very noisy in tests, so just ignore if we're in test context - if is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id) { + if is_in_test(cx.tcx, expr.hir_id) { return; } diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index bb0d714a31fd..ed5f46ddc8d2 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -8,9 +8,11 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_target::spec::abi::Abi; declare_clippy_lint! { /// ### What it does @@ -115,7 +117,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { .iter() .any(|param| matches!(param.kind, GenericParamKind::Const { .. })); - if already_const(header) || has_const_generic_params { + if already_const(header) + || has_const_generic_params + || !could_be_const_with_abi(cx, &self.msrv, header.abi) + { return; } }, @@ -127,6 +132,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { FnKind::Closure => return, } + if fn_inputs_has_impl_trait_ty(cx, def_id) { + return; + } + let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); // Const fns are not allowed as methods in a trait. @@ -171,3 +180,25 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { fn already_const(header: hir::FnHeader) -> bool { header.constness == Constness::Const } + +fn could_be_const_with_abi(cx: &LateContext<'_>, msrv: &Msrv, abi: Abi) -> bool { + match abi { + Abi::Rust => true, + // `const extern "C"` was stablized after 1.62.0 + Abi::C { unwind: false } => msrv.meets(msrvs::CONST_EXTERN_FN), + // Rest ABIs are still unstable and need the `const_extern_fn` feature enabled. + _ => cx.tcx.features().const_extern_fn, + } +} + +/// Return `true` when the given `def_id` is a function that has `impl Trait` ty as one of +/// its parameter types. +fn fn_inputs_has_impl_trait_ty(cx: &LateContext<'_>, def_id: LocalDefId) -> bool { + let inputs = cx.tcx.fn_sig(def_id).instantiate_identity().inputs().skip_binder(); + inputs.iter().any(|input| { + matches!( + input.kind(), + ty::Alias(ty::AliasTyKind::Weak, alias_ty) if cx.tcx.type_of(alias_ty.def_id).skip_binder().is_impl_trait() + ) + }) +} diff --git a/clippy_lints/src/thread_local_initializer_can_be_made_const.rs b/clippy_lints/src/missing_const_for_thread_local.rs similarity index 92% rename from clippy_lints/src/thread_local_initializer_can_be_made_const.rs rename to clippy_lints/src/missing_const_for_thread_local.rs index 4af3ee74d0ea..ab1b4aa3dee6 100644 --- a/clippy_lints/src/thread_local_initializer_can_be_made_const.rs +++ b/clippy_lints/src/missing_const_for_thread_local.rs @@ -39,23 +39,23 @@ declare_clippy_lint! { /// } /// ``` #[clippy::version = "1.77.0"] - pub THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST, + pub MISSING_CONST_FOR_THREAD_LOCAL, perf, "suggest using `const` in `thread_local!` macro" } -pub struct ThreadLocalInitializerCanBeMadeConst { +pub struct MissingConstForThreadLocal { msrv: Msrv, } -impl ThreadLocalInitializerCanBeMadeConst { +impl MissingConstForThreadLocal { #[must_use] pub fn new(msrv: Msrv) -> Self { Self { msrv } } } -impl_lint_pass!(ThreadLocalInitializerCanBeMadeConst => [THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST]); +impl_lint_pass!(MissingConstForThreadLocal => [MISSING_CONST_FOR_THREAD_LOCAL]); #[inline] fn is_thread_local_initializer( @@ -102,7 +102,7 @@ fn initializer_can_be_made_const(cx: &LateContext<'_>, defid: rustc_span::def_id false } -impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst { +impl<'tcx> LateLintPass<'tcx> for MissingConstForThreadLocal { fn check_fn( &mut self, cx: &LateContext<'tcx>, @@ -113,7 +113,7 @@ impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst { local_defid: rustc_span::def_id::LocalDefId, ) { let defid = local_defid.to_def_id(); - if self.msrv.meets(msrvs::THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST) + if self.msrv.meets(msrvs::THREAD_LOCAL_CONST_INIT) && is_thread_local_initializer(cx, fn_kind, span).unwrap_or(false) // Some implementations of `thread_local!` include an initializer fn. // In the case of a const initializer, the init fn is also const, @@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst { { span_lint_and_sugg( cx, - THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST, + MISSING_CONST_FOR_THREAD_LOCAL, unpeeled.span, "initializer for `thread_local` value can be made `const`", "replace with", diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index 57ba0da53319..5ffd41d78e0c 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { /// Check if a `&mut` function argument is actually used mutably. /// /// Be careful if the function is publicly reexported as it would break compatibility with - /// users of this function. + /// users of this function, when the users pass this function as an argument. /// /// ### Why is this bad? /// Less `mut` means less fights with the borrow checker. It can also lead to more @@ -138,6 +138,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { return; } + if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(fn_def_id) { + return; + } + let hir_id = cx.tcx.local_def_id_to_hir_id(fn_def_id); let is_async = match kind { FnKind::ItemFn(.., header) => { @@ -262,9 +266,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { .iter() .filter(|(def_id, _)| !self.used_fn_def_ids.contains(def_id)) { - let show_semver_warning = - self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(*fn_def_id); - let mut is_cfged = None; for input in unused { // If the argument is never used mutably, we emit the warning. @@ -284,7 +285,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { format!("&{}", snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_"),), Applicability::Unspecified, ); - if show_semver_warning { + if cx.effective_visibilities.is_exported(*fn_def_id) { diag.warn("changing this function will impact semver compatibility"); } if *is_cfged { diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 87f886b1128d..0ecfa7baa72d 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::has_drop; -use clippy_utils::{any_parent_is_automatically_derived, is_lint_allowed, path_to_local, peel_blocks}; +use clippy_utils::{ + in_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks, +}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ @@ -185,7 +187,7 @@ impl NoEffect { && has_no_effect(cx, init) && let PatKind::Binding(_, hir_id, ident, _) = local.pat.kind && ident.name.to_ident_string().starts_with('_') - && !any_parent_is_automatically_derived(cx.tcx, local.hir_id) + && !in_automatically_derived(cx.tcx, local.hir_id) { if let Some(l) = self.local_bindings.last_mut() { l.push(hir_id); @@ -258,13 +260,16 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { if let StmtKind::Semi(expr) = stmt.kind + && !in_external_macro(cx.sess(), stmt.span) && let ctxt = stmt.span.ctxt() && expr.span.ctxt() == ctxt && let Some(reduced) = reduce_expression(cx, expr) - && !in_external_macro(cx.sess(), stmt.span) && reduced.iter().all(|e| e.span.ctxt() == ctxt) { if let ExprKind::Index(..) = &expr.kind { + if is_inside_always_const_context(cx.tcx, expr.hir_id) { + return; + } let snippet = if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) { format!("assert!({}.len() > {});", &arr, &func) diff --git a/clippy_lints/src/operators/float_cmp.rs b/clippy_lints/src/operators/float_cmp.rs index faab79de9d3c..0e5b440c50f2 100644 --- a/clippy_lints/src/operators/float_cmp.rs +++ b/clippy_lints/src/operators/float_cmp.rs @@ -57,7 +57,6 @@ pub(crate) fn check<'tcx>( Applicability::HasPlaceholders, // snippet ); } - diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`"); }); } } diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index 48a442705b29..59834781a58a 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -242,6 +242,13 @@ declare_clippy_lint! { /// # let x = 1; /// if (x | 1 > 3) { } /// ``` + /// + /// Use instead: + /// + /// ```no_run + /// # let x = 1; + /// if (x >= 2) { } + /// ``` #[clippy::version = "pre 1.29.0"] pub INEFFECTIVE_BIT_MASK, correctness, @@ -265,6 +272,13 @@ declare_clippy_lint! { /// # let x = 1; /// if x & 0b1111 == 0 { } /// ``` + /// + /// Use instead: + /// + /// ```no_run + /// # let x: i32 = 1; + /// if x.trailing_zeros() > 4 { } + /// ``` #[clippy::version = "pre 1.29.0"] pub VERBOSE_BIT_MASK, pedantic, @@ -560,74 +574,128 @@ declare_clippy_lint! { /// implement equality for a type involving floats). /// /// ### Why is this bad? - /// Floating point calculations are usually imprecise, so - /// asking if two values are *exactly* equal is asking for trouble. For a good - /// guide on what to do, see [the floating point - /// guide](http://www.floating-point-gui.de/errors/comparison). + /// Floating point calculations are usually imprecise, so asking if two values are *exactly* + /// equal is asking for trouble because arriving at the same logical result via different + /// routes (e.g. calculation versus constant) may yield different values. /// /// ### Example - /// ```no_run - /// let x = 1.2331f64; - /// let y = 1.2332f64; /// - /// if y == 1.23f64 { } - /// if y != x {} // where both are floats + /// ```no_run + /// let a: f64 = 1000.1; + /// let b: f64 = 0.2; + /// let x = a + b; + /// let y = 1000.3; // Expected value. + /// + /// // Actual value: 1000.3000000000001 + /// println!("{x}"); + /// + /// let are_equal = x == y; + /// println!("{are_equal}"); // false /// ``` /// - /// Use instead: + /// The correct way to compare floating point numbers is to define an allowed error margin. This + /// may be challenging if there is no "natural" error margin to permit. Broadly speaking, there + /// are two cases: + /// + /// 1. If your values are in a known range and you can define a threshold for "close enough to + /// be equal", it may be appropriate to define an absolute error margin. For example, if your + /// data is "length of vehicle in centimeters", you may consider 0.1 cm to be "close enough". + /// 1. If your code is more general and you do not know the range of values, you should use a + /// relative error margin, accepting e.g. 0.1% of error regardless of specific values. + /// + /// For the scenario where you can define a meaningful absolute error margin, consider using: + /// /// ```no_run - /// # let x = 1.2331f64; - /// # let y = 1.2332f64; - /// let error_margin = f64::EPSILON; // Use an epsilon for comparison - /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead. - /// // let error_margin = std::f64::EPSILON; - /// if (y - 1.23f64).abs() < error_margin { } - /// if (y - x).abs() > error_margin { } + /// let a: f64 = 1000.1; + /// let b: f64 = 0.2; + /// let x = a + b; + /// let y = 1000.3; // Expected value. + /// + /// const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1; + /// let within_tolerance = (x - y).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM; + /// println!("{within_tolerance}"); // true /// ``` + /// + /// NB! Do not use `f64::EPSILON` - while the error margin is often called "epsilon", this is + /// a different use of the term that is not suitable for floating point equality comparison. + /// Indeed, for the example above using `f64::EPSILON` as the allowed error would return `false`. + /// + /// For the scenario where no meaningful absolute error can be defined, refer to + /// [the floating point guide](https://www.floating-point-gui.de/errors/comparison) + /// for a reference implementation of relative error based comparison of floating point values. + /// `MIN_NORMAL` in the reference implementation is equivalent to `MIN_POSITIVE` in Rust. #[clippy::version = "pre 1.29.0"] pub FLOAT_CMP, pedantic, - "using `==` or `!=` on float values instead of comparing difference with an epsilon" + "using `==` or `!=` on float values instead of comparing difference with an allowed error" } declare_clippy_lint! { /// ### What it does - /// Checks for (in-)equality comparisons on floating-point - /// value and constant, except in functions called `*eq*` (which probably + /// Checks for (in-)equality comparisons on constant floating-point + /// values (apart from zero), except in functions called `*eq*` (which probably /// implement equality for a type involving floats). /// /// ### Why restrict this? - /// Floating point calculations are usually imprecise, so - /// asking if two values are *exactly* equal is asking for trouble. For a good - /// guide on what to do, see [the floating point - /// guide](http://www.floating-point-gui.de/errors/comparison). + /// Floating point calculations are usually imprecise, so asking if two values are *exactly* + /// equal is asking for trouble because arriving at the same logical result via different + /// routes (e.g. calculation versus constant) may yield different values. /// /// ### Example - /// ```no_run - /// let x: f64 = 1.0; - /// const ONE: f64 = 1.00; /// - /// if x == ONE { } // where both are floats + /// ```no_run + /// let a: f64 = 1000.1; + /// let b: f64 = 0.2; + /// let x = a + b; + /// const Y: f64 = 1000.3; // Expected value. + /// + /// // Actual value: 1000.3000000000001 + /// println!("{x}"); + /// + /// let are_equal = x == Y; + /// println!("{are_equal}"); // false /// ``` /// - /// Use instead: + /// The correct way to compare floating point numbers is to define an allowed error margin. This + /// may be challenging if there is no "natural" error margin to permit. Broadly speaking, there + /// are two cases: + /// + /// 1. If your values are in a known range and you can define a threshold for "close enough to + /// be equal", it may be appropriate to define an absolute error margin. For example, if your + /// data is "length of vehicle in centimeters", you may consider 0.1 cm to be "close enough". + /// 1. If your code is more general and you do not know the range of values, you should use a + /// relative error margin, accepting e.g. 0.1% of error regardless of specific values. + /// + /// For the scenario where you can define a meaningful absolute error margin, consider using: + /// /// ```no_run - /// # let x: f64 = 1.0; - /// # const ONE: f64 = 1.00; - /// let error_margin = f64::EPSILON; // Use an epsilon for comparison - /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead. - /// // let error_margin = std::f64::EPSILON; - /// if (x - ONE).abs() < error_margin { } + /// let a: f64 = 1000.1; + /// let b: f64 = 0.2; + /// let x = a + b; + /// const Y: f64 = 1000.3; // Expected value. + /// + /// const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1; + /// let within_tolerance = (x - Y).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM; + /// println!("{within_tolerance}"); // true /// ``` + /// + /// NB! Do not use `f64::EPSILON` - while the error margin is often called "epsilon", this is + /// a different use of the term that is not suitable for floating point equality comparison. + /// Indeed, for the example above using `f64::EPSILON` as the allowed error would return `false`. + /// + /// For the scenario where no meaningful absolute error can be defined, refer to + /// [the floating point guide](https://www.floating-point-gui.de/errors/comparison) + /// for a reference implementation of relative error based comparison of floating point values. + /// `MIN_NORMAL` in the reference implementation is equivalent to `MIN_POSITIVE` in Rust. #[clippy::version = "pre 1.29.0"] pub FLOAT_CMP_CONST, restriction, - "using `==` or `!=` on float constants instead of comparing difference with an epsilon" + "using `==` or `!=` on float constants instead of comparing difference with an allowed error" } declare_clippy_lint! { /// ### What it does - /// Checks for getting the remainder of a division by one or minus + /// Checks for getting the remainder of integer division by one or minus /// one. /// /// ### Why is this bad? @@ -646,7 +714,7 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub MODULO_ONE, correctness, - "taking a number modulo +/-1, which can either panic/overflow or always returns 0" + "taking an integer modulo +/-1, which can either panic/overflow or always returns 0" } declare_clippy_lint! { diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs deleted file mode 100644 index de7898793310..000000000000 --- a/clippy_lints/src/overflow_check_conditional.rs +++ /dev/null @@ -1,70 +0,0 @@ -use clippy_utils::diagnostics::span_lint; -use clippy_utils::SpanlessEq; -use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; - -declare_clippy_lint! { - /// ### What it does - /// Detects classic underflow/overflow checks. - /// - /// ### Why is this bad? - /// Most classic C underflow/overflow checks will fail in - /// Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead. - /// - /// ### Example - /// ```no_run - /// # let a = 1; - /// # let b = 2; - /// a + b < a; - /// ``` - #[clippy::version = "pre 1.29.0"] - pub OVERFLOW_CHECK_CONDITIONAL, - complexity, - "overflow checks inspired by C which are likely to panic" -} - -declare_lint_pass!(OverflowCheckConditional => [OVERFLOW_CHECK_CONDITIONAL]); - -const OVERFLOW_MSG: &str = "you are trying to use classic C overflow conditions that will fail in Rust"; -const UNDERFLOW_MSG: &str = "you are trying to use classic C underflow conditions that will fail in Rust"; - -impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional { - // a + b < a, a > a + b, a < a - b, a - b > a - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let eq = |l, r| SpanlessEq::new(cx).eq_path_segment(l, r); - if let ExprKind::Binary(ref op, first, second) = expr.kind - && let ExprKind::Binary(ref op2, ident1, ident2) = first.kind - && let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind - && let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind - && let ExprKind::Path(QPath::Resolved(_, path3)) = second.kind - && (eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0])) - && cx.typeck_results().expr_ty(ident1).is_integral() - && cx.typeck_results().expr_ty(ident2).is_integral() - { - if op.node == BinOpKind::Lt && op2.node == BinOpKind::Add { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG); - } - if op.node == BinOpKind::Gt && op2.node == BinOpKind::Sub { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG); - } - } - - if let ExprKind::Binary(ref op, first, second) = expr.kind - && let ExprKind::Binary(ref op2, ident1, ident2) = second.kind - && let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind - && let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind - && let ExprKind::Path(QPath::Resolved(_, path3)) = first.kind - && (eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0])) - && cx.typeck_results().expr_ty(ident1).is_integral() - && cx.typeck_results().expr_ty(ident2).is_integral() - { - if op.node == BinOpKind::Gt && op2.node == BinOpKind::Add { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG); - } - if op.node == BinOpKind::Lt && op2.node == BinOpKind::Sub { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG); - } - } - } -} diff --git a/clippy_lints/src/panicking_overflow_checks.rs b/clippy_lints/src/panicking_overflow_checks.rs new file mode 100644 index 000000000000..7f100a746d5e --- /dev/null +++ b/clippy_lints/src/panicking_overflow_checks.rs @@ -0,0 +1,86 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::eq_expr_value; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Detects C-style underflow/overflow checks. + /// + /// ### Why is this bad? + /// These checks will, by default, panic in debug builds rather than check + /// whether the operation caused an overflow. + /// + /// ### Example + /// ```no_run + /// # let a = 1i32; + /// # let b = 2i32; + /// if a + b < a { + /// // handle overflow + /// } + /// ``` + /// + /// Use instead: + /// ```no_run + /// # let a = 1i32; + /// # let b = 2i32; + /// if a.checked_add(b).is_none() { + /// // handle overflow + /// } + /// ``` + /// + /// Or: + /// ```no_run + /// # let a = 1i32; + /// # let b = 2i32; + /// if a.overflowing_add(b).1 { + /// // handle overflow + /// } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub PANICKING_OVERFLOW_CHECKS, + correctness, + "overflow checks which will panic in debug mode" +} + +declare_lint_pass!(PanickingOverflowChecks => [PANICKING_OVERFLOW_CHECKS]); + +impl<'tcx> LateLintPass<'tcx> for PanickingOverflowChecks { + // a + b < a, a > a + b, a < a - b, a - b > a + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Binary(op, lhs, rhs) = expr.kind + && let (lt, gt) = match op.node { + BinOpKind::Lt => (lhs, rhs), + BinOpKind::Gt => (rhs, lhs), + _ => return, + } + && let ctxt = expr.span.ctxt() + && let (op_lhs, op_rhs, other, commutative) = match (<.kind, >.kind) { + (&ExprKind::Binary(op, lhs, rhs), _) if op.node == BinOpKind::Add && ctxt == lt.span.ctxt() => { + (lhs, rhs, gt, true) + }, + (_, &ExprKind::Binary(op, lhs, rhs)) if op.node == BinOpKind::Sub && ctxt == gt.span.ctxt() => { + (lhs, rhs, lt, false) + }, + _ => return, + } + && let typeck = cx.typeck_results() + && let ty = typeck.expr_ty(op_lhs) + && matches!(ty.kind(), ty::Uint(_)) + && ty == typeck.expr_ty(op_rhs) + && ty == typeck.expr_ty(other) + && !in_external_macro(cx.tcx.sess, expr.span) + && (eq_expr_value(cx, op_lhs, other) || (commutative && eq_expr_value(cx, op_rhs, other))) + { + span_lint( + cx, + PANICKING_OVERFLOW_CHECKS, + expr.span, + "you are trying to use classic C overflow conditions that will fail in Rust", + ); + } + } +} diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs index 85979903b587..8e999f3e89af 100644 --- a/clippy_lints/src/renamed_lints.rs +++ b/clippy_lints/src/renamed_lints.rs @@ -26,12 +26,14 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::option_map_unwrap_or", "clippy::map_unwrap_or"), ("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or"), ("clippy::option_unwrap_used", "clippy::unwrap_used"), + ("clippy::overflow_check_conditional", "clippy::panicking_overflow_checks"), ("clippy::ref_in_deref", "clippy::needless_borrow"), ("clippy::result_expect_used", "clippy::expect_used"), ("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or"), ("clippy::result_unwrap_used", "clippy::unwrap_used"), ("clippy::single_char_push_str", "clippy::single_char_add_str"), ("clippy::stutter", "clippy::module_name_repetitions"), + ("clippy::thread_local_initializer_can_be_made_const", "clippy::missing_const_for_thread_local"), ("clippy::to_string_in_display", "clippy::recursive_format_impl"), ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"), ("clippy::zero_width_space", "clippy::invisible_characters"), diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index c11da3147ef4..8ced47b48a43 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -7,6 +7,7 @@ use clippy_utils::{ path_to_local_id, span_contains_cfg, span_find_starting_semi, }; use core::ops::ControlFlow; +use rustc_ast::NestedMetaItem; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::LangItem::ResultErr; @@ -14,13 +15,13 @@ use rustc_hir::{ Block, Body, Expr, ExprKind, FnDecl, HirId, ItemKind, LangItem, MatchSource, Node, OwnerNode, PatKind, QPath, Stmt, StmtKind, }; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass, Level, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{BytePos, Pos, Span}; +use rustc_span::{sym, BytePos, Pos, Span}; use std::borrow::Cow; use std::fmt::Display; @@ -80,6 +81,9 @@ declare_clippy_lint! { /// ``` #[clippy::version = "pre 1.29.0"] pub NEEDLESS_RETURN, + // This lint requires some special handling in `check_final_expr` for `#[expect]`. + // This handling needs to be updated if the group gets changed. This should also + // be caught by tests. style, "using a return statement like `return expr;` where an expression would suffice" } @@ -91,6 +95,9 @@ declare_clippy_lint! { /// ### Why is this bad? /// The `return` is unnecessary. /// + /// Returns may be used to add attributes to the return expression. Return + /// statements with attributes are therefore be accepted by this lint. + /// /// ### Example /// ```rust,ignore /// fn foo(x: usize) -> Result<(), Box> { @@ -377,13 +384,39 @@ fn check_final_expr<'tcx>( } }; - if !cx.tcx.hir().attrs(expr.hir_id).is_empty() { - return; - } let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner)); if borrows { return; } + if ret_span.from_expansion() { + return; + } + + // Returns may be used to turn an expression into a statement in rustc's AST. + // This allows the addition of attributes, like `#[allow]` (See: clippy#9361) + // `#[expect(clippy::needless_return)]` needs to be handled separatly to + // actually fullfil the expectation (clippy::#12998) + match cx.tcx.hir().attrs(expr.hir_id) { + [] => {}, + [attr] => { + if matches!(Level::from_attr(attr), Some(Level::Expect(_))) + && let metas = attr.meta_item_list() + && let Some(lst) = metas + && let [NestedMetaItem::MetaItem(meta_item)] = lst.as_slice() + && let [tool, lint_name] = meta_item.path.segments.as_slice() + && tool.ident.name == sym::clippy + && matches!( + lint_name.ident.name.as_str(), + "needless_return" | "style" | "all" | "warnings" + ) + { + // This is an expectation of the `needless_return` lint + } else { + return; + } + }, + _ => return, + } emit_return_lint(cx, ret_span, semi_spans, &replacement, expr.hir_id); }, @@ -415,10 +448,6 @@ fn emit_return_lint( replacement: &RetReplacement<'_>, at: HirId, ) { - if ret_span.from_expansion() { - return; - } - span_lint_hir_and_then( cx, NEEDLESS_RETURN, diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index 8fdd19c549f5..508f3ae6def0 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -12,7 +12,7 @@ use std::collections::{BTreeMap, BTreeSet}; declare_clippy_lint! { /// ### What it does /// It lints if a struct has two methods with the same name: - /// one from a trait, another not from trait. + /// one from a trait, another not from a trait. /// /// ### Why restrict this? /// Confusing. diff --git a/clippy_lints/src/set_contains_or_insert.rs b/clippy_lints/src/set_contains_or_insert.rs new file mode 100644 index 000000000000..5e65b9fa5171 --- /dev/null +++ b/clippy_lints/src/set_contains_or_insert.rs @@ -0,0 +1,125 @@ +use std::ops::ControlFlow; + +use clippy_utils::diagnostics::span_lint; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::visitors::for_each_expr; +use clippy_utils::{higher, peel_hir_expr_while, SpanlessEq}; +use rustc_hir::{Expr, ExprKind, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; +use rustc_span::symbol::Symbol; +use rustc_span::{sym, Span}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `contains` to see if a value is not + /// present on `HashSet` followed by a `insert`. + /// + /// ### Why is this bad? + /// Using just `insert` and checking the returned `bool` is more efficient. + /// + /// ### Known problems + /// In case the value that wants to be inserted is borrowed and also expensive or impossible + /// to clone. In such a scenario, the developer might want to check with `contains` before inserting, + /// to avoid the clone. In this case, it will report a false positive. + /// + /// ### Example + /// ```rust + /// use std::collections::HashSet; + /// let mut set = HashSet::new(); + /// let value = 5; + /// if !set.contains(&value) { + /// set.insert(value); + /// println!("inserted {value:?}"); + /// } + /// ``` + /// Use instead: + /// ```rust + /// use std::collections::HashSet; + /// let mut set = HashSet::new(); + /// let value = 5; + /// if set.insert(&value) { + /// println!("inserted {value:?}"); + /// } + /// ``` + #[clippy::version = "1.80.0"] + pub SET_CONTAINS_OR_INSERT, + nursery, + "call to `HashSet::contains` followed by `HashSet::insert`" +} + +declare_lint_pass!(HashsetInsertAfterContains => [SET_CONTAINS_OR_INSERT]); + +impl<'tcx> LateLintPass<'tcx> for HashsetInsertAfterContains { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if !expr.span.from_expansion() + && let Some(higher::If { + cond: cond_expr, + then: then_expr, + .. + }) = higher::If::hir(expr) + && let Some(contains_expr) = try_parse_op_call(cx, cond_expr, sym!(contains))//try_parse_contains(cx, cond_expr) + && let Some(insert_expr) = find_insert_calls(cx, &contains_expr, then_expr) + { + span_lint( + cx, + SET_CONTAINS_OR_INSERT, + vec![contains_expr.span, insert_expr.span], + "usage of `HashSet::insert` after `HashSet::contains`", + ); + } + } +} + +struct OpExpr<'tcx> { + receiver: &'tcx Expr<'tcx>, + value: &'tcx Expr<'tcx>, + span: Span, +} + +fn try_parse_op_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, symbol: Symbol) -> Option> { + let expr = peel_hir_expr_while(expr, |e| { + if let ExprKind::Unary(UnOp::Not, e) = e.kind { + Some(e) + } else { + None + } + }); + + if let ExprKind::MethodCall(path, receiver, [value], span) = expr.kind { + let value = value.peel_borrows(); + let value = peel_hir_expr_while(value, |e| { + if let ExprKind::Unary(UnOp::Deref, e) = e.kind { + Some(e) + } else { + None + } + }); + let receiver = receiver.peel_borrows(); + let receiver_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); + if value.span.eq_ctxt(expr.span) + && is_type_diagnostic_item(cx, receiver_ty, sym::HashSet) + && path.ident.name == symbol + { + return Some(OpExpr { receiver, value, span }); + } + } + None +} + +fn find_insert_calls<'tcx>( + cx: &LateContext<'tcx>, + contains_expr: &OpExpr<'tcx>, + expr: &'tcx Expr<'_>, +) -> Option> { + for_each_expr(cx, expr, |e| { + if let Some(insert_expr) = try_parse_op_call(cx, e, sym!(insert)) + && SpanlessEq::new(cx).eq_expr(contains_expr.receiver, insert_expr.receiver) + && SpanlessEq::new(cx).eq_expr(contains_expr.value, insert_expr.value) + { + ControlFlow::Break(insert_expr) + } else { + ControlFlow::Continue(()) + } + }) +} diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 877a77fd6d24..1d294c2944b2 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,6 +1,5 @@ pub mod almost_standard_lint_formulation; pub mod collapsible_calls; -pub mod compiler_lint_functions; pub mod interning_defined_symbol; pub mod invalid_paths; pub mod lint_without_lint_pass; diff --git a/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs deleted file mode 100644 index 9b6b68718186..000000000000 --- a/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs +++ /dev/null @@ -1,73 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::match_type; -use clippy_utils::{is_lint_allowed, paths}; -use rustc_data_structures::fx::FxHashMap; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::impl_lint_pass; - -declare_clippy_lint! { - /// ### What it does - /// Checks for calls to `cx.span_lint*` and suggests to use the `utils::*` - /// variant of the function. - /// - /// ### Why is this bad? - /// The `utils::*` variants also add a link to the Clippy documentation to the - /// warning/error messages. - /// - /// ### Example - /// ```rust,ignore - /// cx.span_lint(LINT_NAME, "message"); - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// utils::span_lint(cx, LINT_NAME, "message"); - /// ``` - pub COMPILER_LINT_FUNCTIONS, - internal, - "usage of the lint functions of the compiler instead of the utils::* variant" -} - -impl_lint_pass!(CompilerLintFunctions => [COMPILER_LINT_FUNCTIONS]); - -#[derive(Clone, Default)] -pub struct CompilerLintFunctions { - map: FxHashMap<&'static str, &'static str>, -} - -impl CompilerLintFunctions { - #[must_use] - pub fn new() -> Self { - let mut map = FxHashMap::default(); - map.insert("span_lint", "utils::span_lint"); - map.insert("lint", "utils::span_lint"); - map.insert("span_lint_note", "utils::span_lint_and_note"); - map.insert("span_lint_help", "utils::span_lint_and_help"); - Self { map } - } -} - -impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if is_lint_allowed(cx, COMPILER_LINT_FUNCTIONS, expr.hir_id) { - return; - } - - if let ExprKind::MethodCall(path, self_arg, _, _) = &expr.kind - && let fn_name = path.ident - && let Some(sugg) = self.map.get(fn_name.as_str()) - && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs() - && (match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT)) - { - span_lint_and_help( - cx, - COMPILER_LINT_FUNCTIONS, - path.ident.span, - "usage of a compiler lint function", - None, - format!("please use the Clippy variant of this function: `{sugg}`"), - ); - } - } -} diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 436f0cb79fb2..a0a60ca88758 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_test_module_or_function; +use clippy_utils::is_in_test; use clippy_utils::source::{snippet, snippet_with_applicability}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -100,7 +100,6 @@ declare_clippy_lint! { #[derive(Default)] pub struct WildcardImports { warn_on_all: bool, - test_modules_deep: u32, allowed_segments: FxHashSet, } @@ -108,7 +107,6 @@ impl WildcardImports { pub fn new(warn_on_all: bool, allowed_wildcard_imports: FxHashSet) -> Self { Self { warn_on_all, - test_modules_deep: 0, allowed_segments: allowed_wildcard_imports, } } @@ -122,15 +120,12 @@ impl LateLintPass<'_> for WildcardImports { return; } - if is_test_module_or_function(cx.tcx, item) { - self.test_modules_deep = self.test_modules_deep.saturating_add(1); - } let module = cx.tcx.parent_module_from_def_id(item.owner_id.def_id); if cx.tcx.visibility(item.owner_id.def_id) != ty::Visibility::Restricted(module.to_def_id()) { return; } if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind - && (self.warn_on_all || !self.check_exceptions(item, use_path.segments)) + && (self.warn_on_all || !self.check_exceptions(cx, item, use_path.segments)) && let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id) && !used_imports.is_empty() // Already handled by `unused_imports` && !used_imports.contains(&kw::Underscore) @@ -180,20 +175,14 @@ impl LateLintPass<'_> for WildcardImports { span_lint_and_sugg(cx, lint, span, message, "try", sugg, applicability); } } - - fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - if is_test_module_or_function(cx.tcx, item) { - self.test_modules_deep = self.test_modules_deep.saturating_sub(1); - } - } } impl WildcardImports { - fn check_exceptions(&self, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool { + fn check_exceptions(&self, cx: &LateContext<'_>, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool { item.span.from_expansion() || is_prelude_import(segments) - || (is_super_only_import(segments) && self.test_modules_deep > 0) || is_allowed_via_config(segments, &self.allowed_segments) + || (is_super_only_import(segments) && is_in_test(cx.tcx, item.hir_id())) } } diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 652ce88bd951..96e53b7ef0ba 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::is_in_test; use clippy_utils::macros::{format_arg_removal_span, root_macro_call_first_node, FormatArgsStorage, MacroCall}; use clippy_utils::source::{expand_past_previous_comma, snippet_opt}; -use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_ast::token::LitKind; use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, @@ -297,8 +297,7 @@ impl<'tcx> LateLintPass<'tcx> for Write { .as_ref() .map_or(false, |crate_name| crate_name == "build_script_build"); - let allowed_in_tests = self.allow_print_in_tests - && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)); + let allowed_in_tests = self.allow_print_in_tests && is_in_test(cx.tcx, expr.hir_id); match diag_name { sym::print_macro | sym::println_macro if !allowed_in_tests => { if !is_build_script { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 935a25d79319..bdb3b5e45c48 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -102,10 +102,11 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ - self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, Destination, Expr, - ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item, - ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, - PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, + self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstContext, + Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, + ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat, + PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, + TyKind, UnOp, }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, Level, Lint, LintContext}; @@ -210,7 +211,10 @@ pub fn local_is_initialized(cx: &LateContext<'_>, local: HirId) -> bool { false } -/// Returns `true` if the given `NodeId` is inside a constant context +/// Returns `true` if the given `HirId` is inside a constant context. +/// +/// This is the same as `is_inside_always_const_context`, but also includes +/// `const fn`. /// /// # Example /// @@ -223,6 +227,24 @@ pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool { cx.tcx.hir().is_inside_const_context(id) } +/// Returns `true` if the given `HirId` is inside an always constant context. +/// +/// This context includes: +/// * const/static items +/// * const blocks (or inline consts) +/// * associated constants +pub fn is_inside_always_const_context(tcx: TyCtxt<'_>, hir_id: HirId) -> bool { + use ConstContext::{Const, ConstFn, Static}; + let hir = tcx.hir(); + let Some(ctx) = hir.body_const_context(hir.enclosing_body_owner(hir_id)) else { + return false; + }; + match ctx { + ConstFn => false, + Static(_) | Const { inline: _ } => true, + } +} + /// Checks if a `Res` refers to a constructor of a `LangItem` /// For example, use this to check whether a function call or a pattern is `Some(..)`. pub fn is_res_lang_ctor(cx: &LateContext<'_>, res: Res, lang_item: LangItem) -> bool { @@ -1904,8 +1926,18 @@ pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool false } -pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool { - any_parent_has_attr(tcx, node, sym::automatically_derived) +/// Checks if the given HIR node is inside an `impl` block with the `automatically_derived` +/// attribute. +pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool { + tcx.hir() + .parent_owner_iter(id) + .filter(|(_, node)| matches!(node, OwnerNode::Item(item) if matches!(item.kind, ItemKind::Impl(_)))) + .any(|(id, _)| { + has_attr( + tcx.hir().attrs(tcx.local_def_id_to_hir_id(id.def_id)), + sym::automatically_derived, + ) + }) } /// Matches a function call with the given path and returns the arguments. @@ -2472,6 +2504,17 @@ pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize) } } +/// Peels off all references on the type. Returns the underlying type and the number of references +/// removed. +pub fn peel_middle_ty_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) { + let mut count = 0; + while let rustc_ty::Ref(_, dest_ty, _) = ty.kind() { + ty = *dest_ty; + count += 1; + } + (ty, count) +} + /// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is /// dereferenced. An overloaded deref such as `Vec` to slice would not be removed. pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> { @@ -2594,16 +2637,6 @@ pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { .any(|attr| attr.has_name(sym::cfg)) } -/// Checks whether item either has `test` attribute applied, or -/// is a module with `test` in its name. -/// -/// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function -pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool { - is_in_test_function(tcx, item.hir_id()) - || matches!(item.kind, ItemKind::Mod(..)) - && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests") -} - /// Walks up the HIR tree from the given expression in an attempt to find where the value is /// consumed. /// diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 3f66813801dc..d5a3d8b9e5a2 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -88,6 +88,7 @@ pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern" pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"]; pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"]; pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; +pub const STRING_FROM_UTF8: [&str; 4] = ["alloc", "string", "String", "from_utf8"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_FILE_OPTIONS: [&str; 5] = ["tokio", "fs", "file", "File", "options"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index acaeb93f44a6..fc02b974ee12 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -96,11 +96,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' return false; } - for (predicate, _span) in cx - .tcx - .explicit_item_super_predicates(def_id) - .iter_identity_copied() - { + for (predicate, _span) in cx.tcx.explicit_item_super_predicates(def_id).iter_identity_copied() { match predicate.kind().skip_binder() { // For `impl Trait`, it will register a predicate of `T: Trait`, so we go through // and check substitutions to find `U`. @@ -1332,19 +1328,13 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl /// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`. pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<&'a AssocItem> { if let Some(ty_did) = ty.ty_adt_def().map(AdtDef::did) { - cx.tcx - .inherent_impls(ty_did) - .into_iter() - .flatten() - .map(|&did| { - cx.tcx - .associated_items(did) - .filter_by_name_unhygienic(method_name) - .next() - .filter(|item| item.kind == AssocKind::Fn) - }) - .next() - .flatten() + cx.tcx.inherent_impls(ty_did).into_iter().flatten().find_map(|&did| { + cx.tcx + .associated_items(did) + .filter_by_name_unhygienic(method_name) + .next() + .filter(|item| item.kind == AssocKind::Fn) + }) } else { None } diff --git a/lintcheck/Cargo.toml b/lintcheck/Cargo.toml index ae9e77b8eed0..3c86dfe324f4 100644 --- a/lintcheck/Cargo.toml +++ b/lintcheck/Cargo.toml @@ -16,6 +16,7 @@ clap = { version = "4.4", features = ["derive", "env"] } crossbeam-channel = "0.5.6" diff = "0.1.13" flate2 = "1.0" +itertools = "0.12" rayon = "1.5.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.85" diff --git a/lintcheck/README.md b/lintcheck/README.md index 2d6039caeef0..47a96e0a03c9 100644 --- a/lintcheck/README.md +++ b/lintcheck/README.md @@ -7,13 +7,13 @@ repo. We can then check the diff and spot new or disappearing warnings. From the repo root, run: ``` -cargo run --target-dir lintcheck/target --manifest-path lintcheck/Cargo.toml +cargo lintcheck ``` or ``` -cargo lintcheck +cargo run --target-dir lintcheck/target --manifest-path lintcheck/Cargo.toml ``` By default, the logs will be saved into @@ -33,6 +33,8 @@ the 200 recently most downloaded crates: cargo lintcheck popular -n 200 custom.toml ``` +> Note: Lintcheck isn't sandboxed. Only use it to check crates that you trust or +> sandbox it manually. ### Configuring the Crate Sources @@ -65,17 +67,11 @@ sources. #### Command Line Options (optional) ```toml -bitflags = {name = "bitflags", versions = ['1.2.1'], options = ['-Wclippy::pedantic', '-Wclippy::cargo']} +clap = {name = "clap", versions = ['4.5.8'], options = ['-Fderive']} ``` It is possible to specify command line options for each crate. This makes it -possible to only check a crate for certain lint groups. If no options are -specified, the lint groups `clippy::all`, `clippy::pedantic`, and -`clippy::cargo` are checked. If an empty array is specified only `clippy::all` -is checked. - -**Note:** `-Wclippy::all` is always enabled by default, unless `-Aclippy::all` -is explicitly specified in the options. +possible to enable or disable features. ### Fix mode You can run `cargo lintcheck --fix` which will run Clippy with `--fix` and diff --git a/lintcheck/lintcheck_crates.toml b/lintcheck/lintcheck_crates.toml index 52f7fee47b61..ff608e6f9359 100644 --- a/lintcheck/lintcheck_crates.toml +++ b/lintcheck/lintcheck_crates.toml @@ -1,38 +1,38 @@ [crates] # some of these are from cargotest -cargo = {name = "cargo", versions = ['0.64.0']} -iron = {name = "iron", versions = ['0.6.1']} -ripgrep = {name = "ripgrep", versions = ['12.1.1']} -xsv = {name = "xsv", versions = ['0.13.0']} +cargo = {name = "cargo", version = '0.64.0'} +iron = {name = "iron", version = '0.6.1'} +ripgrep = {name = "ripgrep", version = '12.1.1'} +xsv = {name = "xsv", version = '0.13.0'} # commented out because of 173K clippy::match_same_arms msgs in language_type.rs -#tokei = { name = "tokei", versions = ['12.0.4']} -rayon = {name = "rayon", versions = ['1.5.0']} -serde = {name = "serde", versions = ['1.0.118']} +#tokei = { name = "tokei", version = '12.0.4'} +rayon = {name = "rayon", version = '1.5.0'} +serde = {name = "serde", version = '1.0.118'} # top 10 crates.io dls -bitflags = {name = "bitflags", versions = ['1.2.1']} +bitflags = {name = "bitflags", version = '1.2.1'} # crash = {name = "clippy_crash", path = "/tmp/clippy_crash"} -libc = {name = "libc", versions = ['0.2.81']} -log = {name = "log", versions = ['0.4.11']} -proc-macro2 = {name = "proc-macro2", versions = ['1.0.24']} -quote = {name = "quote", versions = ['1.0.7']} -rand = {name = "rand", versions = ['0.7.3']} -rand_core = {name = "rand_core", versions = ['0.6.0']} -regex = {name = "regex", versions = ['1.3.2']} -syn = {name = "syn", versions = ['1.0.54']} -unicode-xid = {name = "unicode-xid", versions = ['0.2.1']} +libc = {name = "libc", version = '0.2.81'} +log = {name = "log", version = '0.4.11'} +proc-macro2 = {name = "proc-macro2", version = '1.0.24'} +quote = {name = "quote", version = '1.0.7'} +rand = {name = "rand", version = '0.7.3'} +rand_core = {name = "rand_core", version = '0.6.0'} +regex = {name = "regex", version = '1.3.2'} +syn = {name = "syn", version = '1.0.54'} +unicode-xid = {name = "unicode-xid", version = '0.2.1'} # some more of dtolnays crates -anyhow = {name = "anyhow", versions = ['1.0.38']} -async-trait = {name = "async-trait", versions = ['0.1.42']} -cxx = {name = "cxx", versions = ['1.0.32']} -ryu = {name = "ryu", versions = ['1.0.5']} -serde_yaml = {name = "serde_yaml", versions = ['0.8.17']} -thiserror = {name = "thiserror", versions = ['1.0.24']} +anyhow = {name = "anyhow", version = '1.0.38'} +async-trait = {name = "async-trait", version = '0.1.42'} +cxx = {name = "cxx", version = '1.0.32'} +ryu = {name = "ryu", version = '1.0.5'} +serde_yaml = {name = "serde_yaml", version = '0.8.17'} +thiserror = {name = "thiserror", version = '1.0.24'} # some embark crates, there are other interesting crates but # unfortunately adding them increases lintcheck runtime drastically -cfg-expr = {name = "cfg-expr", versions = ['0.7.1']} +cfg-expr = {name = "cfg-expr", version = '0.7.1'} puffin = {name = "puffin", git_url = "https://github.com/EmbarkStudios/puffin", git_hash = "02dd4a3"} -rpmalloc = {name = "rpmalloc", versions = ['0.2.0']} -tame-oidc = {name = "tame-oidc", versions = ['0.1.0']} +rpmalloc = {name = "rpmalloc", version = '0.2.0'} +tame-oidc = {name = "tame-oidc", version = '0.1.0'} [recursive] ignore = [ diff --git a/lintcheck/src/config.rs b/lintcheck/src/config.rs index e6cd7c9fdc2b..b35a62eed440 100644 --- a/lintcheck/src/config.rs +++ b/lintcheck/src/config.rs @@ -36,6 +36,10 @@ pub(crate) struct LintcheckConfig { /// Apply a filter to only collect specified lints, this also overrides `allow` attributes #[clap(long = "filter", value_name = "clippy_lint_name", use_value_delimiter = true)] pub lint_filter: Vec, + /// Set all lints to the "warn" lint level, even resitriction ones. Usually, + /// it's better to use `--filter` instead + #[clap(long, conflicts_with("lint_filter"))] + pub warn_all: bool, /// Set the output format of the log file #[clap(long, short, default_value = "text")] pub format: OutputFormat, diff --git a/lintcheck/src/driver.rs b/lintcheck/src/driver.rs index 47724a2fedb0..041be5081f28 100644 --- a/lintcheck/src/driver.rs +++ b/lintcheck/src/driver.rs @@ -11,8 +11,6 @@ use std::{env, mem}; fn run_clippy(addr: &str) -> Option { let driver_info = DriverInfo { package_name: env::var("CARGO_PKG_NAME").ok()?, - crate_name: env::var("CARGO_CRATE_NAME").ok()?, - version: env::var("CARGO_PKG_VERSION").ok()?, }; let mut stream = BufReader::new(TcpStream::connect(addr).unwrap()); diff --git a/lintcheck/src/input.rs b/lintcheck/src/input.rs new file mode 100644 index 000000000000..3d034391c280 --- /dev/null +++ b/lintcheck/src/input.rs @@ -0,0 +1,288 @@ +use std::collections::{HashMap, HashSet}; +use std::fs::{self}; +use std::io::{self, ErrorKind}; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::time::Duration; + +use serde::Deserialize; +use walkdir::{DirEntry, WalkDir}; + +use crate::{Crate, LINTCHECK_DOWNLOADS, LINTCHECK_SOURCES}; + +/// List of sources to check, loaded from a .toml file +#[derive(Debug, Deserialize)] +pub struct SourceList { + crates: HashMap, + #[serde(default)] + recursive: RecursiveOptions, +} + +#[derive(Debug, Deserialize, Default)] +pub struct RecursiveOptions { + pub ignore: HashSet, +} + +/// A crate source stored inside the .toml +/// will be translated into on one of the `CrateSource` variants +#[derive(Debug, Deserialize)] +struct TomlCrate { + name: String, + version: Option, + git_url: Option, + git_hash: Option, + path: Option, + options: Option>, +} + +/// Represents an archive we download from crates.io, or a git repo, or a local repo/folder +/// Once processed (downloaded/extracted/cloned/copied...), this will be translated into a `Crate` +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)] +pub enum CrateSource { + CratesIo { + name: String, + version: String, + options: Option>, + }, + Git { + name: String, + url: String, + commit: String, + options: Option>, + }, + Path { + name: String, + path: PathBuf, + options: Option>, + }, +} + +/// Read a `lintcheck_crates.toml` file +pub fn read_crates(toml_path: &Path) -> (Vec, RecursiveOptions) { + let toml_content: String = + fs::read_to_string(toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display())); + let crate_list: SourceList = + toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{e}", toml_path.display())); + // parse the hashmap of the toml file into a list of crates + let tomlcrates: Vec = crate_list.crates.into_values().collect(); + + // flatten TomlCrates into CrateSources (one TomlCrates may represent several versions of a crate => + // multiple Cratesources) + let mut crate_sources = Vec::new(); + for tk in tomlcrates { + if let Some(ref path) = tk.path { + crate_sources.push(CrateSource::Path { + name: tk.name.clone(), + path: PathBuf::from(path), + options: tk.options.clone(), + }); + } else if let Some(ref version) = tk.version { + crate_sources.push(CrateSource::CratesIo { + name: tk.name.clone(), + version: version.to_string(), + options: tk.options.clone(), + }); + } else if tk.git_url.is_some() && tk.git_hash.is_some() { + // otherwise, we should have a git source + crate_sources.push(CrateSource::Git { + name: tk.name.clone(), + url: tk.git_url.clone().unwrap(), + commit: tk.git_hash.clone().unwrap(), + options: tk.options.clone(), + }); + } else { + panic!("Invalid crate source: {tk:?}"); + } + + // if we have a version as well as a git data OR only one git data, something is funky + if tk.version.is_some() && (tk.git_url.is_some() || tk.git_hash.is_some()) + || tk.git_hash.is_some() != tk.git_url.is_some() + { + eprintln!("tomlkrate: {tk:?}"); + assert_eq!( + tk.git_hash.is_some(), + tk.git_url.is_some(), + "Error: Encountered TomlCrate with only one of git_hash and git_url!" + ); + assert!( + tk.path.is_none() || (tk.git_hash.is_none() && tk.version.is_none()), + "Error: TomlCrate can only have one of 'git_.*', 'version' or 'path' fields" + ); + unreachable!("Failed to translate TomlCrate into CrateSource!"); + } + } + // sort the crates + crate_sources.sort(); + + (crate_sources, crate_list.recursive) +} + +impl CrateSource { + /// Makes the sources available on the disk for clippy to check. + /// Clones a git repo and checks out the specified commit or downloads a crate from crates.io or + /// copies a local folder + #[expect(clippy::too_many_lines)] + pub fn download_and_extract(&self) -> Crate { + #[allow(clippy::result_large_err)] + fn get(path: &str) -> Result { + const MAX_RETRIES: u8 = 4; + let mut retries = 0; + loop { + match ureq::get(path).call() { + Ok(res) => return Ok(res), + Err(e) if retries >= MAX_RETRIES => return Err(e), + Err(ureq::Error::Transport(e)) => eprintln!("Error: {e}"), + Err(e) => return Err(e), + } + eprintln!("retrying in {retries} seconds..."); + std::thread::sleep(Duration::from_secs(u64::from(retries))); + retries += 1; + } + } + match self { + CrateSource::CratesIo { name, version, options } => { + let extract_dir = PathBuf::from(LINTCHECK_SOURCES); + let krate_download_dir = PathBuf::from(LINTCHECK_DOWNLOADS); + + // url to download the crate from crates.io + let url = format!("https://crates.io/api/v1/crates/{name}/{version}/download"); + println!("Downloading and extracting {name} {version} from {url}"); + create_dirs(&krate_download_dir, &extract_dir); + + let krate_file_path = krate_download_dir.join(format!("{name}-{version}.crate.tar.gz")); + // don't download/extract if we already have done so + if !krate_file_path.is_file() { + // create a file path to download and write the crate data into + let mut krate_dest = fs::File::create(&krate_file_path).unwrap(); + let mut krate_req = get(&url).unwrap().into_reader(); + // copy the crate into the file + io::copy(&mut krate_req, &mut krate_dest).unwrap(); + + // unzip the tarball + let ungz_tar = flate2::read::GzDecoder::new(fs::File::open(&krate_file_path).unwrap()); + // extract the tar archive + let mut archive = tar::Archive::new(ungz_tar); + archive.unpack(&extract_dir).expect("Failed to extract!"); + } + // crate is extracted, return a new Krate object which contains the path to the extracted + // sources that clippy can check + Crate { + version: version.clone(), + name: name.clone(), + path: extract_dir.join(format!("{name}-{version}/")), + options: options.clone(), + } + }, + CrateSource::Git { + name, + url, + commit, + options, + } => { + let repo_path = { + let mut repo_path = PathBuf::from(LINTCHECK_SOURCES); + // add a -git suffix in case we have the same crate from crates.io and a git repo + repo_path.push(format!("{name}-git")); + repo_path + }; + // clone the repo if we have not done so + if !repo_path.is_dir() { + println!("Cloning {url} and checking out {commit}"); + if !Command::new("git") + .arg("clone") + .arg(url) + .arg(&repo_path) + .status() + .expect("Failed to clone git repo!") + .success() + { + eprintln!("Failed to clone {url} into {}", repo_path.display()); + } + } + // check out the commit/branch/whatever + if !Command::new("git") + .args(["-c", "advice.detachedHead=false"]) + .arg("checkout") + .arg(commit) + .current_dir(&repo_path) + .status() + .expect("Failed to check out commit") + .success() + { + eprintln!("Failed to checkout {commit} of repo at {}", repo_path.display()); + } + + Crate { + version: commit.clone(), + name: name.clone(), + path: repo_path, + options: options.clone(), + } + }, + CrateSource::Path { name, path, options } => { + fn is_cache_dir(entry: &DirEntry) -> bool { + fs::read(entry.path().join("CACHEDIR.TAG")) + .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55")) + .unwrap_or(false) + } + + // copy path into the dest_crate_root but skip directories that contain a CACHEDIR.TAG file. + // The target/ directory contains a CACHEDIR.TAG file so it is the most commonly skipped directory + // as a result of this filter. + let dest_crate_root = PathBuf::from(LINTCHECK_SOURCES).join(name); + if dest_crate_root.exists() { + println!("Deleting existing directory at {dest_crate_root:?}"); + fs::remove_dir_all(&dest_crate_root).unwrap(); + } + + println!("Copying {path:?} to {dest_crate_root:?}"); + + for entry in WalkDir::new(path).into_iter().filter_entry(|e| !is_cache_dir(e)) { + let entry = entry.unwrap(); + let entry_path = entry.path(); + let relative_entry_path = entry_path.strip_prefix(path).unwrap(); + let dest_path = dest_crate_root.join(relative_entry_path); + let metadata = entry_path.symlink_metadata().unwrap(); + + if metadata.is_dir() { + fs::create_dir(dest_path).unwrap(); + } else if metadata.is_file() { + fs::copy(entry_path, dest_path).unwrap(); + } + } + + Crate { + version: String::from("local"), + name: name.clone(), + path: dest_crate_root, + options: options.clone(), + } + }, + } + } +} + +/// Create necessary directories to run the lintcheck tool. +/// +/// # Panics +/// +/// This function panics if creating one of the dirs fails. +fn create_dirs(krate_download_dir: &Path, extract_dir: &Path) { + fs::create_dir("target/lintcheck/").unwrap_or_else(|err| { + assert_eq!( + err.kind(), + ErrorKind::AlreadyExists, + "cannot create lintcheck target dir" + ); + }); + fs::create_dir(krate_download_dir).unwrap_or_else(|err| { + assert_eq!(err.kind(), ErrorKind::AlreadyExists, "cannot create crate download dir"); + }); + fs::create_dir(extract_dir).unwrap_or_else(|err| { + assert_eq!( + err.kind(), + ErrorKind::AlreadyExists, + "cannot create crate extraction dir" + ); + }); +} diff --git a/lintcheck/src/json.rs b/lintcheck/src/json.rs index 43d0413c7cee..1a652927988e 100644 --- a/lintcheck/src/json.rs +++ b/lintcheck/src/json.rs @@ -1,37 +1,50 @@ -use std::collections::HashMap; -use std::fmt::Write; use std::fs; -use std::hash::Hash; use std::path::Path; +use itertools::EitherOrBoth; +use serde::{Deserialize, Serialize}; + use crate::ClippyWarning; -/// Creates the log file output for [`crate::config::OutputFormat::Json`] -pub(crate) fn output(clippy_warnings: &[ClippyWarning]) -> String { - serde_json::to_string(&clippy_warnings).unwrap() +#[derive(Deserialize, Serialize)] +struct LintJson { + lint: String, + file_name: String, + byte_pos: (u32, u32), + rendered: String, } -fn load_warnings(path: &Path) -> Vec { +impl LintJson { + fn key(&self) -> impl Ord + '_ { + (self.file_name.as_str(), self.byte_pos, self.lint.as_str()) + } +} + +/// Creates the log file output for [`crate::config::OutputFormat::Json`] +pub(crate) fn output(clippy_warnings: Vec) -> String { + let mut lints: Vec = clippy_warnings + .into_iter() + .map(|warning| { + let span = warning.span(); + LintJson { + file_name: span.file_name.clone(), + byte_pos: (span.byte_start, span.byte_end), + lint: warning.lint, + rendered: warning.diag.rendered.unwrap(), + } + }) + .collect(); + lints.sort_by(|a, b| a.key().cmp(&b.key())); + serde_json::to_string(&lints).unwrap() +} + +fn load_warnings(path: &Path) -> Vec { let file = fs::read(path).unwrap_or_else(|e| panic!("failed to read {}: {e}", path.display())); serde_json::from_slice(&file).unwrap_or_else(|e| panic!("failed to deserialize {}: {e}", path.display())) } -/// Group warnings by their primary span location + lint name -fn create_map(warnings: &[ClippyWarning]) -> HashMap> { - let mut map = HashMap::<_, Vec<_>>::with_capacity(warnings.len()); - - for warning in warnings { - let span = warning.span(); - let key = (&warning.lint_type, &span.file_name, span.byte_start, span.byte_end); - - map.entry(key).or_default().push(warning); - } - - map -} - -fn print_warnings(title: &str, warnings: &[&ClippyWarning]) { +fn print_warnings(title: &str, warnings: &[LintJson]) { if warnings.is_empty() { return; } @@ -39,31 +52,20 @@ fn print_warnings(title: &str, warnings: &[&ClippyWarning]) { println!("### {title}"); println!("```"); for warning in warnings { - print!("{}", warning.diag); + print!("{}", warning.rendered); } println!("```"); } -fn print_changed_diff(changed: &[(&[&ClippyWarning], &[&ClippyWarning])]) { - fn render(warnings: &[&ClippyWarning]) -> String { - let mut rendered = String::new(); - for warning in warnings { - write!(&mut rendered, "{}", warning.diag).unwrap(); - } - rendered - } - +fn print_changed_diff(changed: &[(LintJson, LintJson)]) { if changed.is_empty() { return; } println!("### Changed"); println!("```diff"); - for &(old, new) in changed { - let old_rendered = render(old); - let new_rendered = render(new); - - for change in diff::lines(&old_rendered, &new_rendered) { + for (old, new) in changed { + for change in diff::lines(&old.rendered, &new.rendered) { use diff::Result::{Both, Left, Right}; match change { @@ -86,26 +88,19 @@ pub(crate) fn diff(old_path: &Path, new_path: &Path) { let old_warnings = load_warnings(old_path); let new_warnings = load_warnings(new_path); - let old_map = create_map(&old_warnings); - let new_map = create_map(&new_warnings); - let mut added = Vec::new(); let mut removed = Vec::new(); let mut changed = Vec::new(); - for (key, new) in &new_map { - if let Some(old) = old_map.get(key) { - if old != new { - changed.push((old.as_slice(), new.as_slice())); - } - } else { - added.extend(new); - } - } - - for (key, old) in &old_map { - if !new_map.contains_key(key) { - removed.extend(old); + for change in itertools::merge_join_by(old_warnings, new_warnings, |old, new| old.key().cmp(&new.key())) { + match change { + EitherOrBoth::Both(old, new) => { + if old.rendered != new.rendered { + changed.push((old, new)); + } + }, + EitherOrBoth::Left(old) => removed.push(old), + EitherOrBoth::Right(new) => added.push(new), } } diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index ec72e0eb5dcb..e37ffab13ac8 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -5,6 +5,7 @@ // When a new lint is introduced, we can search the results for new warnings and check for false // positives. +#![feature(iter_collect_into)] #![warn( trivial_casts, trivial_numeric_casts, @@ -12,84 +13,38 @@ unused_lifetimes, unused_qualifications )] -#![allow(clippy::collapsible_else_if, clippy::needless_borrows_for_generic_args)] +#![allow( + clippy::collapsible_else_if, + clippy::needless_borrows_for_generic_args, + clippy::module_name_repetitions +)] mod config; mod driver; +mod input; mod json; +mod output; mod popular_crates; mod recursive; use crate::config::{Commands, LintcheckConfig, OutputFormat}; use crate::recursive::LintcheckServer; -use std::collections::{HashMap, HashSet}; use std::env::consts::EXE_SUFFIX; -use std::fmt::{self, Display, Write as _}; -use std::hash::Hash; -use std::io::{self, ErrorKind}; +use std::io::{self}; use std::path::{Path, PathBuf}; -use std::process::{Command, ExitStatus, Stdio}; +use std::process::{Command, Stdio}; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::time::Duration; -use std::{env, fs, thread}; +use std::{env, fs}; -use cargo_metadata::diagnostic::{Diagnostic, DiagnosticSpan}; use cargo_metadata::Message; +use input::{read_crates, CrateSource}; +use output::{ClippyCheckOutput, ClippyWarning, RustcIce}; use rayon::prelude::*; -use serde::{Deserialize, Serialize}; -use walkdir::{DirEntry, WalkDir}; const LINTCHECK_DOWNLOADS: &str = "target/lintcheck/downloads"; const LINTCHECK_SOURCES: &str = "target/lintcheck/sources"; -/// List of sources to check, loaded from a .toml file -#[derive(Debug, Deserialize)] -struct SourceList { - crates: HashMap, - #[serde(default)] - recursive: RecursiveOptions, -} - -#[derive(Debug, Deserialize, Default)] -struct RecursiveOptions { - ignore: HashSet, -} - -/// A crate source stored inside the .toml -/// will be translated into on one of the `CrateSource` variants -#[derive(Debug, Deserialize)] -struct TomlCrate { - name: String, - versions: Option>, - git_url: Option, - git_hash: Option, - path: Option, - options: Option>, -} - -/// Represents an archive we download from crates.io, or a git repo, or a local repo/folder -/// Once processed (downloaded/extracted/cloned/copied...), this will be translated into a `Crate` -#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)] -enum CrateSource { - CratesIo { - name: String, - version: String, - options: Option>, - }, - Git { - name: String, - url: String, - commit: String, - options: Option>, - }, - Path { - name: String, - path: PathBuf, - options: Option>, - }, -} - /// Represents the actual source code of a crate that we ran "cargo clippy" on #[derive(Debug)] struct Crate { @@ -100,248 +55,6 @@ struct Crate { options: Option>, } -/// A single emitted output from clippy being executed on a crate. It may either be a -/// `ClippyWarning`, or a `RustcIce` caused by a panic within clippy. A crate may have many -/// `ClippyWarning`s but a maximum of one `RustcIce` (at which point clippy halts execution). -#[derive(Debug)] -enum ClippyCheckOutput { - ClippyWarning(ClippyWarning), - RustcIce(RustcIce), -} - -#[derive(Debug)] -struct RustcIce { - pub crate_name: String, - pub ice_content: String, -} - -impl Display for RustcIce { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}:\n{}\n========================================\n", - self.crate_name, self.ice_content - ) - } -} - -impl RustcIce { - pub fn from_stderr_and_status(crate_name: &str, status: ExitStatus, stderr: &str) -> Option { - if status.code().unwrap_or(0) == 101 - /* ice exit status */ - { - Some(Self { - crate_name: crate_name.to_owned(), - ice_content: stderr.to_owned(), - }) - } else { - None - } - } -} - -/// A single warning that clippy issued while checking a `Crate` -#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -struct ClippyWarning { - crate_name: String, - crate_version: String, - lint_type: String, - diag: Diagnostic, -} - -#[allow(unused)] -impl ClippyWarning { - fn new(mut diag: Diagnostic, crate_name: &str, crate_version: &str) -> Option { - let lint_type = diag.code.clone()?.code; - if !(lint_type.contains("clippy") || diag.message.contains("clippy")) - || diag.message.contains("could not read cargo metadata") - { - return None; - } - - // --recursive bypasses cargo so we have to strip the rendered output ourselves - let rendered = diag.rendered.as_mut().unwrap(); - *rendered = strip_ansi_escapes::strip_str(&rendered); - - Some(Self { - crate_name: crate_name.to_owned(), - crate_version: crate_version.to_owned(), - lint_type, - diag, - }) - } - - fn span(&self) -> &DiagnosticSpan { - self.diag.spans.iter().find(|span| span.is_primary).unwrap() - } - - fn to_output(&self, format: OutputFormat) -> String { - let span = self.span(); - let mut file = span.file_name.clone(); - let file_with_pos = format!("{file}:{}:{}", span.line_start, span.line_end); - match format { - OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.lint_type, self.diag.message), - OutputFormat::Markdown => { - if file.starts_with("target") { - file.insert_str(0, "../"); - } - - let mut output = String::from("| "); - write!(output, "[`{file_with_pos}`]({file}#L{})", span.line_start).unwrap(); - write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.diag.message).unwrap(); - output.push('\n'); - output - }, - OutputFormat::Json => unreachable!("JSON output is handled via serde"), - } - } -} - -#[allow(clippy::result_large_err)] -fn get(path: &str) -> Result { - const MAX_RETRIES: u8 = 4; - let mut retries = 0; - loop { - match ureq::get(path).call() { - Ok(res) => return Ok(res), - Err(e) if retries >= MAX_RETRIES => return Err(e), - Err(ureq::Error::Transport(e)) => eprintln!("Error: {e}"), - Err(e) => return Err(e), - } - eprintln!("retrying in {retries} seconds..."); - thread::sleep(Duration::from_secs(u64::from(retries))); - retries += 1; - } -} - -impl CrateSource { - /// Makes the sources available on the disk for clippy to check. - /// Clones a git repo and checks out the specified commit or downloads a crate from crates.io or - /// copies a local folder - fn download_and_extract(&self) -> Crate { - match self { - CrateSource::CratesIo { name, version, options } => { - let extract_dir = PathBuf::from(LINTCHECK_SOURCES); - let krate_download_dir = PathBuf::from(LINTCHECK_DOWNLOADS); - - // url to download the crate from crates.io - let url = format!("https://crates.io/api/v1/crates/{name}/{version}/download"); - println!("Downloading and extracting {name} {version} from {url}"); - create_dirs(&krate_download_dir, &extract_dir); - - let krate_file_path = krate_download_dir.join(format!("{name}-{version}.crate.tar.gz")); - // don't download/extract if we already have done so - if !krate_file_path.is_file() { - // create a file path to download and write the crate data into - let mut krate_dest = fs::File::create(&krate_file_path).unwrap(); - let mut krate_req = get(&url).unwrap().into_reader(); - // copy the crate into the file - io::copy(&mut krate_req, &mut krate_dest).unwrap(); - - // unzip the tarball - let ungz_tar = flate2::read::GzDecoder::new(fs::File::open(&krate_file_path).unwrap()); - // extract the tar archive - let mut archive = tar::Archive::new(ungz_tar); - archive.unpack(&extract_dir).expect("Failed to extract!"); - } - // crate is extracted, return a new Krate object which contains the path to the extracted - // sources that clippy can check - Crate { - version: version.clone(), - name: name.clone(), - path: extract_dir.join(format!("{name}-{version}/")), - options: options.clone(), - } - }, - CrateSource::Git { - name, - url, - commit, - options, - } => { - let repo_path = { - let mut repo_path = PathBuf::from(LINTCHECK_SOURCES); - // add a -git suffix in case we have the same crate from crates.io and a git repo - repo_path.push(format!("{name}-git")); - repo_path - }; - // clone the repo if we have not done so - if !repo_path.is_dir() { - println!("Cloning {url} and checking out {commit}"); - if !Command::new("git") - .arg("clone") - .arg(url) - .arg(&repo_path) - .status() - .expect("Failed to clone git repo!") - .success() - { - eprintln!("Failed to clone {url} into {}", repo_path.display()); - } - } - // check out the commit/branch/whatever - if !Command::new("git") - .args(["-c", "advice.detachedHead=false"]) - .arg("checkout") - .arg(commit) - .current_dir(&repo_path) - .status() - .expect("Failed to check out commit") - .success() - { - eprintln!("Failed to checkout {commit} of repo at {}", repo_path.display()); - } - - Crate { - version: commit.clone(), - name: name.clone(), - path: repo_path, - options: options.clone(), - } - }, - CrateSource::Path { name, path, options } => { - fn is_cache_dir(entry: &DirEntry) -> bool { - fs::read(entry.path().join("CACHEDIR.TAG")) - .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55")) - .unwrap_or(false) - } - - // copy path into the dest_crate_root but skip directories that contain a CACHEDIR.TAG file. - // The target/ directory contains a CACHEDIR.TAG file so it is the most commonly skipped directory - // as a result of this filter. - let dest_crate_root = PathBuf::from(LINTCHECK_SOURCES).join(name); - if dest_crate_root.exists() { - println!("Deleting existing directory at {dest_crate_root:?}"); - fs::remove_dir_all(&dest_crate_root).unwrap(); - } - - println!("Copying {path:?} to {dest_crate_root:?}"); - - for entry in WalkDir::new(path).into_iter().filter_entry(|e| !is_cache_dir(e)) { - let entry = entry.unwrap(); - let entry_path = entry.path(); - let relative_entry_path = entry_path.strip_prefix(path).unwrap(); - let dest_path = dest_crate_root.join(relative_entry_path); - let metadata = entry_path.symlink_metadata().unwrap(); - - if metadata.is_dir() { - fs::create_dir(dest_path).unwrap(); - } else if metadata.is_file() { - fs::copy(entry_path, dest_path).unwrap(); - } - } - - Crate { - version: String::from("local"), - name: name.clone(), - path: dest_crate_root, - options: options.clone(), - } - }, - } - } -} - impl Crate { /// Run `cargo clippy` on the `Crate` and collect and return all the lint warnings that clippy /// issued @@ -352,7 +65,7 @@ impl Crate { target_dir_index: &AtomicUsize, total_crates_to_lint: usize, config: &LintcheckConfig, - lint_filter: &[String], + lint_levels_args: &[String], server: &Option, ) -> Vec { // advance the atomic index by one @@ -398,16 +111,9 @@ impl Crate { for opt in options { clippy_args.push(opt); } - } else { - clippy_args.extend(["-Wclippy::pedantic", "-Wclippy::cargo"]); } - if lint_filter.is_empty() { - clippy_args.push("--cap-lints=warn"); - } else { - clippy_args.push("--cap-lints=allow"); - clippy_args.extend(lint_filter.iter().map(String::as_str)); - } + clippy_args.extend(lint_levels_args.iter().map(String::as_str)); let mut cmd = Command::new("cargo"); cmd.arg(if config.fix { "fix" } else { "check" }) @@ -479,7 +185,7 @@ impl Crate { // get all clippy warnings and ICEs let mut entries: Vec = Message::parse_stream(stdout.as_bytes()) .filter_map(|msg| match msg { - Ok(Message::CompilerMessage(message)) => ClippyWarning::new(message.message, &self.name, &self.version), + Ok(Message::CompilerMessage(message)) => ClippyWarning::new(message.message), _ => None, }) .map(ClippyCheckOutput::ClippyWarning) @@ -509,96 +215,6 @@ fn build_clippy() -> String { String::from_utf8_lossy(&output.stdout).into_owned() } -/// Read a `lintcheck_crates.toml` file -fn read_crates(toml_path: &Path) -> (Vec, RecursiveOptions) { - let toml_content: String = - fs::read_to_string(toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display())); - let crate_list: SourceList = - toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{e}", toml_path.display())); - // parse the hashmap of the toml file into a list of crates - let tomlcrates: Vec = crate_list.crates.into_values().collect(); - - // flatten TomlCrates into CrateSources (one TomlCrates may represent several versions of a crate => - // multiple Cratesources) - let mut crate_sources = Vec::new(); - for tk in tomlcrates { - if let Some(ref path) = tk.path { - crate_sources.push(CrateSource::Path { - name: tk.name.clone(), - path: PathBuf::from(path), - options: tk.options.clone(), - }); - } else if let Some(ref versions) = tk.versions { - // if we have multiple versions, save each one - for ver in versions { - crate_sources.push(CrateSource::CratesIo { - name: tk.name.clone(), - version: ver.to_string(), - options: tk.options.clone(), - }); - } - } else if tk.git_url.is_some() && tk.git_hash.is_some() { - // otherwise, we should have a git source - crate_sources.push(CrateSource::Git { - name: tk.name.clone(), - url: tk.git_url.clone().unwrap(), - commit: tk.git_hash.clone().unwrap(), - options: tk.options.clone(), - }); - } else { - panic!("Invalid crate source: {tk:?}"); - } - - // if we have a version as well as a git data OR only one git data, something is funky - if tk.versions.is_some() && (tk.git_url.is_some() || tk.git_hash.is_some()) - || tk.git_hash.is_some() != tk.git_url.is_some() - { - eprintln!("tomlkrate: {tk:?}"); - assert_eq!( - tk.git_hash.is_some(), - tk.git_url.is_some(), - "Error: Encountered TomlCrate with only one of git_hash and git_url!" - ); - assert!( - tk.path.is_none() || (tk.git_hash.is_none() && tk.versions.is_none()), - "Error: TomlCrate can only have one of 'git_.*', 'version' or 'path' fields" - ); - unreachable!("Failed to translate TomlCrate into CrateSource!"); - } - } - // sort the crates - crate_sources.sort(); - - (crate_sources, crate_list.recursive) -} - -/// Generate a short list of occurring lints-types and their count -fn gather_stats(warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) { - // count lint type occurrences - let mut counter: HashMap<&String, usize> = HashMap::new(); - warnings - .iter() - .for_each(|wrn| *counter.entry(&wrn.lint_type).or_insert(0) += 1); - - // collect into a tupled list for sorting - let mut stats: Vec<(&&String, &usize)> = counter.iter().collect(); - // sort by "000{count} {clippy::lintname}" - // to not have a lint with 200 and 2 warnings take the same spot - stats.sort_by_key(|(lint, count)| format!("{count:0>4}, {lint}")); - - let mut header = String::from("| lint | count |\n"); - header.push_str("| -------------------------------------------------- | ----- |\n"); - let stats_string = stats - .iter() - .map(|(lint, count)| format!("| {lint:<50} | {count:>4} |\n")) - .fold(header, |mut table, line| { - table.push_str(&line); - table - }); - - (stats_string, counter) -} - fn main() { // We're being executed as a `RUSTC_WRAPPER` as part of `--recursive` if let Ok(addr) = env::var("LINTCHECK_SERVER") { @@ -638,15 +254,39 @@ fn lintcheck(config: LintcheckConfig) { let (crates, recursive_options) = read_crates(&config.sources_toml_path); let counter = AtomicUsize::new(1); - let lint_filter: Vec = config - .lint_filter - .iter() - .map(|filter| { - let mut filter = filter.clone(); - filter.insert_str(0, "--force-warn="); - filter - }) - .collect(); + let mut lint_level_args: Vec = vec![]; + if config.lint_filter.is_empty() { + lint_level_args.push("--cap-lints=warn".to_string()); + + // Set allow-by-default to warn + if config.warn_all { + [ + "clippy::cargo", + "clippy::nursery", + "clippy::pedantic", + "clippy::restriction", + ] + .iter() + .map(|group| format!("--warn={group}")) + .collect_into(&mut lint_level_args); + } else { + ["clippy::cargo", "clippy::pedantic"] + .iter() + .map(|group| format!("--warn={group}")) + .collect_into(&mut lint_level_args); + } + } else { + lint_level_args.push("--cap-lints=allow".to_string()); + config + .lint_filter + .iter() + .map(|filter| { + let mut filter = filter.clone(); + filter.insert_str(0, "--force-warn="); + filter + }) + .collect_into(&mut lint_level_args); + }; let crates: Vec = crates .into_iter() @@ -698,7 +338,7 @@ fn lintcheck(config: LintcheckConfig) { &counter, crates.len(), &config, - &lint_filter, + &lint_level_args, &server, ) }) @@ -727,7 +367,9 @@ fn lintcheck(config: LintcheckConfig) { } let text = match config.format { - OutputFormat::Text | OutputFormat::Markdown => output(&warnings, &raw_ices, clippy_ver, &config), + OutputFormat::Text | OutputFormat::Markdown => { + output::summarize_and_print_changes(&warnings, &raw_ices, clippy_ver, &config) + }, OutputFormat::Json => { if !raw_ices.is_empty() { for ice in raw_ices { @@ -736,7 +378,7 @@ fn lintcheck(config: LintcheckConfig) { panic!("Some crates ICEd"); } - json::output(&warnings) + json::output(warnings) }, }; @@ -745,135 +387,6 @@ fn lintcheck(config: LintcheckConfig) { fs::write(&config.lintcheck_results_path, text).unwrap(); } -/// Creates the log file output for [`OutputFormat::Text`] and [`OutputFormat::Markdown`] -fn output(warnings: &[ClippyWarning], ices: &[RustcIce], clippy_ver: String, config: &LintcheckConfig) -> String { - // generate some stats - let (stats_formatted, new_stats) = gather_stats(warnings); - let old_stats = read_stats_from_file(&config.lintcheck_results_path); - - let mut all_msgs: Vec = warnings.iter().map(|warn| warn.to_output(config.format)).collect(); - all_msgs.sort(); - all_msgs.push("\n\n### Stats:\n\n".into()); - all_msgs.push(stats_formatted); - - let mut text = clippy_ver; // clippy version number on top - text.push_str("\n### Reports\n\n"); - if config.format == OutputFormat::Markdown { - text.push_str("| file | lint | message |\n"); - text.push_str("| --- | --- | --- |\n"); - } - write!(text, "{}", all_msgs.join("")).unwrap(); - text.push_str("\n\n### ICEs:\n"); - for ice in ices { - writeln!(text, "{ice}").unwrap(); - } - - print_stats(old_stats, new_stats, &config.lint_filter); - - text -} - -/// read the previous stats from the lintcheck-log file -fn read_stats_from_file(file_path: &Path) -> HashMap { - let file_content: String = match fs::read_to_string(file_path).ok() { - Some(content) => content, - None => { - return HashMap::new(); - }, - }; - - let lines: Vec = file_content.lines().map(ToString::to_string).collect(); - - lines - .iter() - .skip_while(|line| line.as_str() != "### Stats:") - // Skipping the table header and the `Stats:` label - .skip(4) - .take_while(|line| line.starts_with("| ")) - .filter_map(|line| { - let mut spl = line.split('|'); - // Skip the first `|` symbol - spl.next(); - if let (Some(lint), Some(count)) = (spl.next(), spl.next()) { - Some((lint.trim().to_string(), count.trim().parse::().unwrap())) - } else { - None - } - }) - .collect::>() -} - -/// print how lint counts changed between runs -fn print_stats(old_stats: HashMap, new_stats: HashMap<&String, usize>, lint_filter: &[String]) { - let same_in_both_hashmaps = old_stats - .iter() - .filter(|(old_key, old_val)| new_stats.get::<&String>(old_key) == Some(old_val)) - .map(|(k, v)| (k.to_string(), *v)) - .collect::>(); - - let mut old_stats_deduped = old_stats; - let mut new_stats_deduped = new_stats; - - // remove duplicates from both hashmaps - for (k, v) in &same_in_both_hashmaps { - assert!(old_stats_deduped.remove(k) == Some(*v)); - assert!(new_stats_deduped.remove(k) == Some(*v)); - } - - println!("\nStats:"); - - // list all new counts (key is in new stats but not in old stats) - new_stats_deduped - .iter() - .filter(|(new_key, _)| !old_stats_deduped.contains_key::(new_key)) - .for_each(|(new_key, new_value)| { - println!("{new_key} 0 => {new_value}"); - }); - - // list all changed counts (key is in both maps but value differs) - new_stats_deduped - .iter() - .filter(|(new_key, _new_val)| old_stats_deduped.contains_key::(new_key)) - .for_each(|(new_key, new_val)| { - let old_val = old_stats_deduped.get::(new_key).unwrap(); - println!("{new_key} {old_val} => {new_val}"); - }); - - // list all gone counts (key is in old status but not in new stats) - old_stats_deduped - .iter() - .filter(|(old_key, _)| !new_stats_deduped.contains_key::<&String>(old_key)) - .filter(|(old_key, _)| lint_filter.is_empty() || lint_filter.contains(old_key)) - .for_each(|(old_key, old_value)| { - println!("{old_key} {old_value} => 0"); - }); -} - -/// Create necessary directories to run the lintcheck tool. -/// -/// # Panics -/// -/// This function panics if creating one of the dirs fails. -fn create_dirs(krate_download_dir: &Path, extract_dir: &Path) { - fs::create_dir("target/lintcheck/").unwrap_or_else(|err| { - assert_eq!( - err.kind(), - ErrorKind::AlreadyExists, - "cannot create lintcheck target dir" - ); - }); - fs::create_dir(krate_download_dir).unwrap_or_else(|err| { - assert_eq!(err.kind(), ErrorKind::AlreadyExists, "cannot create crate download dir"); - }); - fs::create_dir(extract_dir).unwrap_or_else(|err| { - assert_eq!( - err.kind(), - ErrorKind::AlreadyExists, - "cannot create crate extraction dir" - ); - }); -} - /// Returns the path to the Clippy project directory #[must_use] fn clippy_project_root() -> &'static Path { diff --git a/lintcheck/src/output.rs b/lintcheck/src/output.rs new file mode 100644 index 000000000000..4bfc554ef9e6 --- /dev/null +++ b/lintcheck/src/output.rs @@ -0,0 +1,235 @@ +use cargo_metadata::diagnostic::{Diagnostic, DiagnosticSpan}; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::fmt::{self, Write as _}; +use std::fs; +use std::path::Path; +use std::process::ExitStatus; + +use crate::config::{LintcheckConfig, OutputFormat}; + +/// A single emitted output from clippy being executed on a crate. It may either be a +/// `ClippyWarning`, or a `RustcIce` caused by a panic within clippy. A crate may have many +/// `ClippyWarning`s but a maximum of one `RustcIce` (at which point clippy halts execution). +#[derive(Debug)] +pub enum ClippyCheckOutput { + ClippyWarning(ClippyWarning), + RustcIce(RustcIce), +} + +#[derive(Debug)] +pub struct RustcIce { + pub crate_name: String, + pub ice_content: String, +} + +impl fmt::Display for RustcIce { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}:\n{}\n========================================\n", + self.crate_name, self.ice_content + ) + } +} + +impl RustcIce { + pub fn from_stderr_and_status(crate_name: &str, status: ExitStatus, stderr: &str) -> Option { + if status.code().unwrap_or(0) == 101 + /* ice exit status */ + { + Some(Self { + crate_name: crate_name.to_owned(), + ice_content: stderr.to_owned(), + }) + } else { + None + } + } +} + +/// A single warning that clippy issued while checking a `Crate` +#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct ClippyWarning { + pub lint: String, + pub diag: Diagnostic, +} + +#[allow(unused)] +impl ClippyWarning { + pub fn new(mut diag: Diagnostic) -> Option { + let lint = diag.code.clone()?.code; + if !(lint.contains("clippy") || diag.message.contains("clippy")) + || diag.message.contains("could not read cargo metadata") + { + return None; + } + + // --recursive bypasses cargo so we have to strip the rendered output ourselves + let rendered = diag.rendered.as_mut().unwrap(); + *rendered = strip_ansi_escapes::strip_str(&rendered); + + Some(Self { lint, diag }) + } + + pub fn span(&self) -> &DiagnosticSpan { + self.diag.spans.iter().find(|span| span.is_primary).unwrap() + } + + pub fn to_output(&self, format: OutputFormat) -> String { + let span = self.span(); + let mut file = span.file_name.clone(); + let file_with_pos = format!("{file}:{}:{}", span.line_start, span.line_end); + match format { + OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.lint, self.diag.message), + OutputFormat::Markdown => { + if file.starts_with("target") { + file.insert_str(0, "../"); + } + + let mut output = String::from("| "); + write!(output, "[`{file_with_pos}`]({file}#L{})", span.line_start).unwrap(); + write!(output, r#" | `{:<50}` | "{}" |"#, self.lint, self.diag.message).unwrap(); + output.push('\n'); + output + }, + OutputFormat::Json => unreachable!("JSON output is handled via serde"), + } + } +} + +/// Creates the log file output for [`OutputFormat::Text`] and [`OutputFormat::Markdown`] +pub fn summarize_and_print_changes( + warnings: &[ClippyWarning], + ices: &[RustcIce], + clippy_ver: String, + config: &LintcheckConfig, +) -> String { + // generate some stats + let (stats_formatted, new_stats) = gather_stats(warnings); + let old_stats = read_stats_from_file(&config.lintcheck_results_path); + + let mut all_msgs: Vec = warnings.iter().map(|warn| warn.to_output(config.format)).collect(); + all_msgs.sort(); + all_msgs.push("\n\n### Stats:\n\n".into()); + all_msgs.push(stats_formatted); + + let mut text = clippy_ver; // clippy version number on top + text.push_str("\n### Reports\n\n"); + if config.format == OutputFormat::Markdown { + text.push_str("| file | lint | message |\n"); + text.push_str("| --- | --- | --- |\n"); + } + write!(text, "{}", all_msgs.join("")).unwrap(); + text.push_str("\n\n### ICEs:\n"); + for ice in ices { + writeln!(text, "{ice}").unwrap(); + } + + print_stats(old_stats, new_stats, &config.lint_filter); + + text +} + +/// Generate a short list of occurring lints-types and their count +fn gather_stats(warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) { + // count lint type occurrences + let mut counter: HashMap<&String, usize> = HashMap::new(); + warnings + .iter() + .for_each(|wrn| *counter.entry(&wrn.lint).or_insert(0) += 1); + + // collect into a tupled list for sorting + let mut stats: Vec<(&&String, &usize)> = counter.iter().collect(); + // sort by "000{count} {clippy::lintname}" + // to not have a lint with 200 and 2 warnings take the same spot + stats.sort_by_key(|(lint, count)| format!("{count:0>4}, {lint}")); + + let mut header = String::from("| lint | count |\n"); + header.push_str("| -------------------------------------------------- | ----- |\n"); + let stats_string = stats + .iter() + .map(|(lint, count)| format!("| {lint:<50} | {count:>4} |\n")) + .fold(header, |mut table, line| { + table.push_str(&line); + table + }); + + (stats_string, counter) +} + +/// read the previous stats from the lintcheck-log file +fn read_stats_from_file(file_path: &Path) -> HashMap { + let file_content: String = match fs::read_to_string(file_path).ok() { + Some(content) => content, + None => { + return HashMap::new(); + }, + }; + + let lines: Vec = file_content.lines().map(ToString::to_string).collect(); + + lines + .iter() + .skip_while(|line| line.as_str() != "### Stats:") + // Skipping the table header and the `Stats:` label + .skip(4) + .take_while(|line| line.starts_with("| ")) + .filter_map(|line| { + let mut spl = line.split('|'); + // Skip the first `|` symbol + spl.next(); + if let (Some(lint), Some(count)) = (spl.next(), spl.next()) { + Some((lint.trim().to_string(), count.trim().parse::().unwrap())) + } else { + None + } + }) + .collect::>() +} + +/// print how lint counts changed between runs +fn print_stats(old_stats: HashMap, new_stats: HashMap<&String, usize>, lint_filter: &[String]) { + let same_in_both_hashmaps = old_stats + .iter() + .filter(|(old_key, old_val)| new_stats.get::<&String>(old_key) == Some(old_val)) + .map(|(k, v)| (k.to_string(), *v)) + .collect::>(); + + let mut old_stats_deduped = old_stats; + let mut new_stats_deduped = new_stats; + + // remove duplicates from both hashmaps + for (k, v) in &same_in_both_hashmaps { + assert!(old_stats_deduped.remove(k) == Some(*v)); + assert!(new_stats_deduped.remove(k) == Some(*v)); + } + + println!("\nStats:"); + + // list all new counts (key is in new stats but not in old stats) + new_stats_deduped + .iter() + .filter(|(new_key, _)| !old_stats_deduped.contains_key::(new_key)) + .for_each(|(new_key, new_value)| { + println!("{new_key} 0 => {new_value}"); + }); + + // list all changed counts (key is in both maps but value differs) + new_stats_deduped + .iter() + .filter(|(new_key, _new_val)| old_stats_deduped.contains_key::(new_key)) + .for_each(|(new_key, new_val)| { + let old_val = old_stats_deduped.get::(new_key).unwrap(); + println!("{new_key} {old_val} => {new_val}"); + }); + + // list all gone counts (key is in old status but not in new stats) + old_stats_deduped + .iter() + .filter(|(old_key, _)| !new_stats_deduped.contains_key::<&String>(old_key)) + .filter(|(old_key, _)| lint_filter.is_empty() || lint_filter.contains(old_key)) + .for_each(|(old_key, old_value)| { + println!("{old_key} {old_value} => 0"); + }); +} diff --git a/lintcheck/src/popular_crates.rs b/lintcheck/src/popular_crates.rs index 880a8bd81f08..ad8fc440c424 100644 --- a/lintcheck/src/popular_crates.rs +++ b/lintcheck/src/popular_crates.rs @@ -44,7 +44,7 @@ pub(crate) fn fetch(output: PathBuf, number: usize) -> Result<(), Box let mut out = "[crates]\n".to_string(); for Crate { name, max_version } in crates { - writeln!(out, "{name} = {{ name = '{name}', versions = ['{max_version}'] }}").unwrap(); + writeln!(out, "{name} = {{ name = '{name}', version = '{max_version}' }}").unwrap(); } fs::write(output, out)?; diff --git a/lintcheck/src/recursive.rs b/lintcheck/src/recursive.rs index 994fa3c3b239..373ca6f99184 100644 --- a/lintcheck/src/recursive.rs +++ b/lintcheck/src/recursive.rs @@ -3,7 +3,8 @@ //! [`LintcheckServer`] to ask if it should be skipped, and if not sends the stderr of running //! clippy on the crate to the server -use crate::{ClippyWarning, RecursiveOptions}; +use crate::input::RecursiveOptions; +use crate::ClippyWarning; use std::collections::HashSet; use std::io::{BufRead, BufReader, Read, Write}; @@ -19,8 +20,6 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Eq, Hash, PartialEq, Clone, Serialize, Deserialize)] pub(crate) struct DriverInfo { pub package_name: String, - pub crate_name: String, - pub version: String, } pub(crate) fn serialize_line(value: &T, writer: &mut W) @@ -65,7 +64,7 @@ fn process_stream( let messages = stderr .lines() .filter_map(|json_msg| serde_json::from_str::(json_msg).ok()) - .filter_map(|diag| ClippyWarning::new(diag, &driver_info.package_name, &driver_info.version)); + .filter_map(ClippyWarning::new); for message in messages { sender.send(message).unwrap(); diff --git a/rust-toolchain b/rust-toolchain index 72b50d59f7e9..a61c22c59f98 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,4 @@ [toolchain] -channel = "nightly-2024-06-27" +channel = "nightly-2024-07-11" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] +profile = "minimal" diff --git a/tests/ui-internal/disallow_span_lint.stderr b/tests/ui-internal/disallow_span_lint.stderr index 1be4b665bcba..66eda44f7455 100644 --- a/tests/ui-internal/disallow_span_lint.stderr +++ b/tests/ui-internal/disallow_span_lint.stderr @@ -1,22 +1,18 @@ error: use of a disallowed method `rustc_lint::context::LintContext::span_lint` - --> tests/ui-internal/disallow_span_lint.rs:14:5 + --> tests/ui-internal/disallow_span_lint.rs:14:8 | -LL | / cx.span_lint(lint, span, |lint| { -LL | | lint.primary_message(msg); -LL | | }); - | |______^ +LL | cx.span_lint(lint, span, |lint| { + | ^^^^^^^^^ | = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead (from clippy.toml) = note: `-D clippy::disallowed-methods` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_lint` - --> tests/ui-internal/disallow_span_lint.rs:20:5 + --> tests/ui-internal/disallow_span_lint.rs:20:9 | -LL | / tcx.node_span_lint(lint, hir_id, span, |lint| { -LL | | lint.primary_message(msg); -LL | | }); - | |______^ +LL | tcx.node_span_lint(lint, hir_id, span, |lint| { + | ^^^^^^^^^^^^^^ | = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead (from clippy.toml) diff --git a/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr b/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr index a74d8757e4a5..016ee502c242 100644 --- a/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr +++ b/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr @@ -1,4 +1,4 @@ -error: `std::string::String` may not be held across an `await` point per `clippy.toml` +error: `std::string::String` may not be held across an await point per `clippy.toml` --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:5:9 | LL | let _x = String::from("hello"); @@ -8,13 +8,13 @@ LL | let _x = String::from("hello"); = note: `-D clippy::await-holding-invalid-type` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::await_holding_invalid_type)]` -error: `std::net::Ipv4Addr` may not be held across an `await` point per `clippy.toml` +error: `std::net::Ipv4Addr` may not be held across an await point per `clippy.toml` --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:10:9 | LL | let x = Ipv4Addr::new(127, 0, 0, 1); | ^ -error: `std::string::String` may not be held across an `await` point per `clippy.toml` +error: `std::string::String` may not be held across an await point per `clippy.toml` --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:33:13 | LL | let _x = String::from("hi!"); diff --git a/tests/ui-toml/needless_pass_by_ref_mut/clippy.toml b/tests/ui-toml/needless_pass_by_ref_mut/clippy.toml new file mode 100644 index 000000000000..cda8d17eed44 --- /dev/null +++ b/tests/ui-toml/needless_pass_by_ref_mut/clippy.toml @@ -0,0 +1 @@ +avoid-breaking-exported-api = false diff --git a/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed new file mode 100644 index 000000000000..40556ca5410f --- /dev/null +++ b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed @@ -0,0 +1,10 @@ +#![warn(clippy::needless_pass_by_ref_mut)] +#![allow(clippy::ptr_arg)] + +// Should warn +pub fn pub_foo(s: &Vec, b: &u32, x: &mut u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + *x += *b + s.len() as u32; +} + +fn main() {} diff --git a/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs new file mode 100644 index 000000000000..bbc63ceb15a3 --- /dev/null +++ b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs @@ -0,0 +1,10 @@ +#![warn(clippy::needless_pass_by_ref_mut)] +#![allow(clippy::ptr_arg)] + +// Should warn +pub fn pub_foo(s: &mut Vec, b: &u32, x: &mut u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + *x += *b + s.len() as u32; +} + +fn main() {} diff --git a/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr new file mode 100644 index 000000000000..c10607bf4bab --- /dev/null +++ b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr @@ -0,0 +1,12 @@ +error: this argument is a mutable reference, but not used mutably + --> tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs:5:19 + | +LL | pub fn pub_foo(s: &mut Vec, b: &u32, x: &mut u32) { + | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` + | + = warning: changing this function will impact semver compatibility + = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` + +error: aborting due to 1 previous error + diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr index 4afbbf5f8079..f661e76cc746 100644 --- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr +++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr @@ -2,36 +2,36 @@ error: use of a disallowed method `regex::Regex::new` --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:35:14 | LL | let re = Regex::new(r"ab.*c").unwrap(); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ | = note: `-D clippy::disallowed-methods` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` error: use of a disallowed method `regex::Regex::is_match` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:36:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:36:8 | LL | re.is_match("abc"); - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ | = note: no matching allowed (from clippy.toml) error: use of a disallowed method `std::iter::Iterator::sum` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:39:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:39:14 | LL | a.iter().sum::(); - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^ error: use of a disallowed method `slice::sort_unstable` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:41:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:41:7 | LL | a.sort_unstable(); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ error: use of a disallowed method `f32::clamp` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:44:13 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:44:20 | LL | let _ = 2.0f32.clamp(3.0f32, 4.0f32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ error: use of a disallowed method `regex::Regex::new` --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:47:61 @@ -55,37 +55,37 @@ error: use of a disallowed method `futures::stream::select_all` --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:54:31 | LL | let same_name_as_module = select_all(vec![empty::<()>()]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::local_fn` --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:56:5 | LL | local_fn(); - | ^^^^^^^^^^ + | ^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::local_mod::f` --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:57:5 | LL | local_mod::f(); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Struct::method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:7 | LL | s.method(); - | ^^^^^^^^^^ + | ^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Trait::provided_method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:7 | LL | s.provided_method(); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Trait::implemented_method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:61:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:61:7 | LL | s.implemented_method(); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: aborting due to 14 previous errors diff --git a/tests/ui/assertions_on_constants.rs b/tests/ui/assertions_on_constants.rs index 1309ae45d0ae..957154e60dec 100644 --- a/tests/ui/assertions_on_constants.rs +++ b/tests/ui/assertions_on_constants.rs @@ -1,4 +1,4 @@ -#![allow(non_fmt_panics, clippy::needless_bool)] +#![allow(non_fmt_panics, clippy::needless_bool, clippy::eq_op)] macro_rules! assert_const { ($len:expr) => { @@ -49,7 +49,16 @@ fn main() { const _: () = assert!(true); //~^ ERROR: `assert!(true)` will be optimized out by the compiler + assert!(8 == (7 + 1)); + //~^ ERROR: `assert!(true)` will be optimized out by the compiler + // Don't lint if the value is dependent on a defined constant: const N: usize = 1024; const _: () = assert!(N.is_power_of_two()); } + +const _: () = { + assert!(true); + //~^ ERROR: `assert!(true)` will be optimized out by the compiler + assert!(8 == (7 + 1)); +}; diff --git a/tests/ui/assertions_on_constants.stderr b/tests/ui/assertions_on_constants.stderr index 00f117c94920..e164a999c43e 100644 --- a/tests/ui/assertions_on_constants.stderr +++ b/tests/ui/assertions_on_constants.stderr @@ -80,5 +80,21 @@ LL | const _: () = assert!(true); | = help: remove it -error: aborting due to 10 previous errors +error: `assert!(true)` will be optimized out by the compiler + --> tests/ui/assertions_on_constants.rs:52:5 + | +LL | assert!(8 == (7 + 1)); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove it + +error: `assert!(true)` will be optimized out by the compiler + --> tests/ui/assertions_on_constants.rs:61:5 + | +LL | assert!(true); + | ^^^^^^^^^^^^^ + | + = help: remove it + +error: aborting due to 12 previous errors diff --git a/tests/ui/await_holding_lock.rs b/tests/ui/await_holding_lock.rs index 8e5510e6cd01..cecf00c934fe 100644 --- a/tests/ui/await_holding_lock.rs +++ b/tests/ui/await_holding_lock.rs @@ -8,7 +8,7 @@ mod std_mutex { pub async fn bad(x: &Mutex) -> u32 { let guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } @@ -24,13 +24,13 @@ mod std_mutex { pub async fn bad_rw(x: &RwLock) -> u32 { let guard = x.read().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } pub async fn bad_rw_write(x: &RwLock) -> u32 { let mut guard = x.write().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } @@ -52,7 +52,7 @@ mod std_mutex { let first = baz().await; let guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point let second = baz().await; @@ -66,7 +66,7 @@ mod std_mutex { let second = { let guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await }; @@ -79,7 +79,7 @@ mod std_mutex { pub fn block_bad(x: &Mutex) -> impl std::future::Future + '_ { async move { let guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } } @@ -92,7 +92,7 @@ mod parking_lot_mutex { pub async fn bad(x: &Mutex) -> u32 { let guard = x.lock(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } @@ -108,13 +108,13 @@ mod parking_lot_mutex { pub async fn bad_rw(x: &RwLock) -> u32 { let guard = x.read(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } pub async fn bad_rw_write(x: &RwLock) -> u32 { let mut guard = x.write(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } @@ -136,7 +136,7 @@ mod parking_lot_mutex { let first = baz().await; let guard = x.lock(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point let second = baz().await; @@ -150,7 +150,7 @@ mod parking_lot_mutex { let second = { let guard = x.lock(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await }; @@ -163,7 +163,7 @@ mod parking_lot_mutex { pub fn block_bad(x: &Mutex) -> impl std::future::Future + '_ { async move { let guard = x.lock(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } } @@ -184,7 +184,7 @@ async fn no_await(x: std::sync::Mutex) { // `*guard += 1` is removed it is picked up. async fn dropped_before_await(x: std::sync::Mutex) { let mut guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point *guard += 1; drop(guard); baz().await; diff --git a/tests/ui/await_holding_lock.stderr b/tests/ui/await_holding_lock.stderr index 0af48a36acca..af61d8939483 100644 --- a/tests/ui/await_holding_lock.stderr +++ b/tests/ui/await_holding_lock.stderr @@ -1,11 +1,11 @@ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:10:13 | LL | let guard = x.lock().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:12:15 | LL | baz().await @@ -13,40 +13,40 @@ LL | baz().await = note: `-D clippy::await-holding-lock` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::await_holding_lock)]` -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:26:13 | LL | let guard = x.read().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:28:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:32:13 | LL | let mut guard = x.write().unwrap(); | ^^^^^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:34:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:54:13 | LL | let guard = x.lock().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:57:28 | LL | let second = baz().await; @@ -55,79 +55,79 @@ LL | LL | let third = baz().await; | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:68:17 | LL | let guard = x.lock().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:70:19 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:81:17 | LL | let guard = x.lock().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:83:19 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:94:13 | LL | let guard = x.lock(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:96:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:110:13 | LL | let guard = x.read(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:112:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:116:13 | LL | let mut guard = x.write(); | ^^^^^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:118:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:138:13 | LL | let guard = x.lock(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:141:28 | LL | let second = baz().await; @@ -136,40 +136,40 @@ LL | LL | let third = baz().await; | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:152:17 | LL | let guard = x.lock(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:154:19 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:165:17 | LL | let guard = x.lock(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:167:19 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:186:9 | LL | let mut guard = x.lock().unwrap(); | ^^^^^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:190:11 | LL | baz().await; diff --git a/tests/ui/await_holding_refcell_ref.rs b/tests/ui/await_holding_refcell_ref.rs index 5bd26c628362..b0c92d8c1f6e 100644 --- a/tests/ui/await_holding_refcell_ref.rs +++ b/tests/ui/await_holding_refcell_ref.rs @@ -4,13 +4,13 @@ use std::cell::RefCell; async fn bad(x: &RefCell) -> u32 { let b = x.borrow(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point baz().await } async fn bad_mut(x: &RefCell) -> u32 { let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point baz().await } @@ -32,7 +32,7 @@ async fn also_bad(x: &RefCell) -> u32 { let first = baz().await; let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point let second = baz().await; @@ -45,7 +45,7 @@ async fn less_bad(x: &RefCell) -> u32 { let first = baz().await; let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point let second = baz().await; @@ -61,7 +61,7 @@ async fn not_good(x: &RefCell) -> u32 { let second = { let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point baz().await }; @@ -74,7 +74,7 @@ async fn not_good(x: &RefCell) -> u32 { fn block_bad(x: &RefCell) -> impl std::future::Future + '_ { async move { let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point baz().await } } diff --git a/tests/ui/await_holding_refcell_ref.stderr b/tests/ui/await_holding_refcell_ref.stderr index 6b474c27ddc1..6c7209c9ff9e 100644 --- a/tests/ui/await_holding_refcell_ref.stderr +++ b/tests/ui/await_holding_refcell_ref.stderr @@ -1,11 +1,11 @@ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:6:9 | LL | let b = x.borrow(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:8:11 | LL | baz().await @@ -13,27 +13,27 @@ LL | baz().await = note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::await_holding_refcell_ref)]` -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:12:9 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:14:11 | LL | baz().await | ^^^^^ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:34:9 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:37:24 | LL | let second = baz().await; @@ -42,40 +42,40 @@ LL | LL | let third = baz().await; | ^^^^^ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:47:9 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:50:24 | LL | let second = baz().await; | ^^^^^ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:63:13 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:65:15 | LL | baz().await | ^^^^^ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:76:13 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:78:15 | LL | baz().await diff --git a/tests/ui/byte_char_slices.fixed b/tests/ui/byte_char_slices.fixed new file mode 100644 index 000000000000..d1db58f9363e --- /dev/null +++ b/tests/ui/byte_char_slices.fixed @@ -0,0 +1,13 @@ +#![allow(unused)] +#![warn(clippy::byte_char_slices)] + +fn main() { + let bad = b"abc"; + let quotes = b"\"Hi"; + let quotes = b"'Sup"; + let escapes = b"\x42Esc"; + + let good = &[b'a', 0x42]; + let good = [b'a', b'a']; + let good: u8 = [b'a', b'c'].into_iter().sum(); +} diff --git a/tests/ui/byte_char_slices.rs b/tests/ui/byte_char_slices.rs new file mode 100644 index 000000000000..18648fffceb4 --- /dev/null +++ b/tests/ui/byte_char_slices.rs @@ -0,0 +1,13 @@ +#![allow(unused)] +#![warn(clippy::byte_char_slices)] + +fn main() { + let bad = &[b'a', b'b', b'c']; + let quotes = &[b'"', b'H', b'i']; + let quotes = &[b'\'', b'S', b'u', b'p']; + let escapes = &[b'\x42', b'E', b's', b'c']; + + let good = &[b'a', 0x42]; + let good = vec![b'a', b'a']; + let good: u8 = [b'a', b'c'].into_iter().sum(); +} diff --git a/tests/ui/byte_char_slices.stderr b/tests/ui/byte_char_slices.stderr new file mode 100644 index 000000000000..4e2b5d8a7329 --- /dev/null +++ b/tests/ui/byte_char_slices.stderr @@ -0,0 +1,38 @@ +error: can be more succinctly written as a byte str + --> tests/ui/byte_char_slices.rs:5:15 + | +LL | let bad = &[b'a', b'b', b'c']; + | ^^^^^^^^^^^^^^^^^^^ help: try: `b"abc"` + | + = note: `-D clippy::byte-char-slices` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::byte_char_slices)]` + +error: can be more succinctly written as a byte str + --> tests/ui/byte_char_slices.rs:6:18 + | +LL | let quotes = &[b'"', b'H', b'i']; + | ^^^^^^^^^^^^^^^^^^^ help: try: `b"\"Hi"` + +error: can be more succinctly written as a byte str + --> tests/ui/byte_char_slices.rs:7:18 + | +LL | let quotes = &[b'\'', b'S', b'u', b'p']; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b"'Sup"` + +error: can be more succinctly written as a byte str + --> tests/ui/byte_char_slices.rs:8:19 + | +LL | let escapes = &[b'\x42', b'E', b's', b'c']; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b"\x42Esc"` + +error: useless use of `vec!` + --> tests/ui/byte_char_slices.rs:11:16 + | +LL | let good = vec![b'a', b'a']; + | ^^^^^^^^^^^^^^^^ help: you can use an array directly: `[b'a', b'a']` + | + = note: `-D clippy::useless-vec` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]` + +error: aborting due to 5 previous errors + diff --git a/tests/ui/cfg_not_test.rs b/tests/ui/cfg_not_test.rs new file mode 100644 index 000000000000..da3e29d28966 --- /dev/null +++ b/tests/ui/cfg_not_test.rs @@ -0,0 +1,32 @@ +#![allow(unused)] +#![warn(clippy::cfg_not_test)] + +fn important_check() {} + +fn main() { + // Statement + #[cfg(not(test))] + let answer = 42; + + // Expression + #[cfg(not(test))] + important_check(); + + // Make sure only not(test) are checked, not other attributes + #[cfg(not(foo))] + important_check(); +} + +#[cfg(not(not(test)))] +struct CfgNotTest; + +// Deeply nested `not(test)` +#[cfg(not(test))] +fn foo() {} +#[cfg(all(debug_assertions, not(test)))] +fn bar() {} +#[cfg(not(any(not(debug_assertions), test)))] +fn baz() {} + +#[cfg(test)] +mod tests {} diff --git a/tests/ui/cfg_not_test.stderr b/tests/ui/cfg_not_test.stderr new file mode 100644 index 000000000000..c1bf626887af --- /dev/null +++ b/tests/ui/cfg_not_test.stderr @@ -0,0 +1,45 @@ +error: code is excluded from test builds + --> tests/ui/cfg_not_test.rs:8:5 + | +LL | #[cfg(not(test))] + | ^^^^^^^^^^^^^^^^^ + | + = help: consider not excluding any code from test builds + = note: this could increase code coverage despite not actually being tested + = note: `-D clippy::cfg-not-test` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cfg_not_test)]` + +error: code is excluded from test builds + --> tests/ui/cfg_not_test.rs:12:5 + | +LL | #[cfg(not(test))] + | ^^^^^^^^^^^^^^^^^ + | + = help: consider not excluding any code from test builds + +error: code is excluded from test builds + --> tests/ui/cfg_not_test.rs:24:1 + | +LL | #[cfg(not(test))] + | ^^^^^^^^^^^^^^^^^ + | + = help: consider not excluding any code from test builds + +error: code is excluded from test builds + --> tests/ui/cfg_not_test.rs:26:1 + | +LL | #[cfg(all(debug_assertions, not(test)))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider not excluding any code from test builds + +error: code is excluded from test builds + --> tests/ui/cfg_not_test.rs:28:1 + | +LL | #[cfg(not(any(not(debug_assertions), test)))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider not excluding any code from test builds + +error: aborting due to 5 previous errors + diff --git a/tests/ui/crashes/ice-12616.stderr b/tests/ui/crashes/ice-12616.stderr index c7cf5cf5483f..a84a945a429f 100644 --- a/tests/ui/crashes/ice-12616.stderr +++ b/tests/ui/crashes/ice-12616.stderr @@ -1,4 +1,4 @@ -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/crashes/ice-12616.rs:6:5 | LL | s() as *const (); diff --git a/tests/ui/disallowed_names.rs b/tests/ui/disallowed_names.rs index 13c883409bf6..96531bf8d88c 100644 --- a/tests/ui/disallowed_names.rs +++ b/tests/ui/disallowed_names.rs @@ -60,6 +60,7 @@ fn issue_1647_ref_mut() { //~^ ERROR: use of a disallowed/placeholder name `quux` } +#[cfg(test)] mod tests { fn issue_7305() { // `disallowed_names` lint should not be triggered inside of the test code. diff --git a/tests/ui/doc/doc_lazy_blank_line.fixed b/tests/ui/doc/doc_lazy_blank_line.fixed new file mode 100644 index 000000000000..1aaa26afe7f2 --- /dev/null +++ b/tests/ui/doc/doc_lazy_blank_line.fixed @@ -0,0 +1,47 @@ +// https://github.com/rust-lang/rust-clippy/issues/12917 +#![warn(clippy::doc_lazy_continuation)] + +/// This is a constant. +/// +/// The meaning of which should not be explained. +pub const A: i32 = 42; + +/// This is another constant, no longer used. +/// +/// This block of documentation has a long +/// explanation and derivation to explain +/// why it is what it is, and how it's used. +/// +/// It is left here for historical reasons, and +/// for reference. +/// +/// Reasons it's great: +/// - First reason +/// - Second reason +/// +//pub const B: i32 = 1337; + +/// This is yet another constant. +/// +/// This has a similar fate as `B`. +/// +/// Reasons it's useful: +/// 1. First reason +/// 2. Second reason +/// +//pub const C: i32 = 8008; + +/// This is still in use. +pub const D: i32 = 20; + +/// > blockquote code path +/// + +/// bottom text +pub const E: i32 = 20; + +/// > blockquote code path +/// +#[repr(C)] +/// bottom text +pub struct Foo(i32); diff --git a/tests/ui/doc/doc_lazy_blank_line.rs b/tests/ui/doc/doc_lazy_blank_line.rs new file mode 100644 index 000000000000..e1ab8fc83892 --- /dev/null +++ b/tests/ui/doc/doc_lazy_blank_line.rs @@ -0,0 +1,43 @@ +// https://github.com/rust-lang/rust-clippy/issues/12917 +#![warn(clippy::doc_lazy_continuation)] + +/// This is a constant. +/// +/// The meaning of which should not be explained. +pub const A: i32 = 42; + +/// This is another constant, no longer used. +/// +/// This block of documentation has a long +/// explanation and derivation to explain +/// why it is what it is, and how it's used. +/// +/// It is left here for historical reasons, and +/// for reference. +/// +/// Reasons it's great: +/// - First reason +/// - Second reason +//pub const B: i32 = 1337; + +/// This is yet another constant. +/// +/// This has a similar fate as `B`. +/// +/// Reasons it's useful: +/// 1. First reason +/// 2. Second reason +//pub const C: i32 = 8008; + +/// This is still in use. +pub const D: i32 = 20; + +/// > blockquote code path + +/// bottom text +pub const E: i32 = 20; + +/// > blockquote code path +#[repr(C)] +/// bottom text +pub struct Foo(i32); diff --git a/tests/ui/doc/doc_lazy_blank_line.stderr b/tests/ui/doc/doc_lazy_blank_line.stderr new file mode 100644 index 000000000000..854906a74741 --- /dev/null +++ b/tests/ui/doc/doc_lazy_blank_line.stderr @@ -0,0 +1,56 @@ +error: doc list item without indentation + --> tests/ui/doc/doc_lazy_blank_line.rs:23:5 + | +LL | /// This is yet another constant. + | ^ + | + = help: if this is intended to be part of the list, indent 3 spaces + = note: `-D clippy::doc-lazy-continuation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_lazy_continuation)]` +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// - Second reason +LL + /// + | + +error: doc list item without indentation + --> tests/ui/doc/doc_lazy_blank_line.rs:32:5 + | +LL | /// This is still in use. + | ^ + | + = help: if this is intended to be part of the list, indent 4 spaces +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// 2. Second reason +LL + /// + | + +error: doc quote line without `>` marker + --> tests/ui/doc/doc_lazy_blank_line.rs:37:5 + | +LL | /// bottom text + | ^ + | + = help: if this not intended to be a quote at all, escape it with `\>` +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// > blockquote code path +LL + /// + | + +error: doc quote line without `>` marker + --> tests/ui/doc/doc_lazy_blank_line.rs:42:5 + | +LL | /// bottom text + | ^ + | + = help: if this not intended to be a quote at all, escape it with `\>` +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// > blockquote code path +LL + /// + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui/doc/doc_lazy_blockquote.fixed b/tests/ui/doc/doc_lazy_blockquote.fixed index 9877991f183a..9d6e8637608f 100644 --- a/tests/ui/doc/doc_lazy_blockquote.fixed +++ b/tests/ui/doc/doc_lazy_blockquote.fixed @@ -2,7 +2,7 @@ /// > blockquote with /// > lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn first() {} /// > blockquote with no @@ -18,24 +18,24 @@ fn two_nowarn() {} /// > /// > > nest here /// > > lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn two() {} /// > nest here /// > /// > > nest here /// > > lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn three() {} /// > * > nest here /// > > lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn four() {} /// > * > nest here /// > > lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn four_point_1() {} /// * > nest here lazy continuation @@ -43,5 +43,5 @@ fn five() {} /// 1. > nest here /// > lazy continuation (this results in strange indentation, but still works) -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn six() {} diff --git a/tests/ui/doc/doc_lazy_blockquote.rs b/tests/ui/doc/doc_lazy_blockquote.rs index 587b2fdd533c..0323a1b44e7c 100644 --- a/tests/ui/doc/doc_lazy_blockquote.rs +++ b/tests/ui/doc/doc_lazy_blockquote.rs @@ -2,7 +2,7 @@ /// > blockquote with /// lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn first() {} /// > blockquote with no @@ -18,24 +18,24 @@ fn two_nowarn() {} /// > /// > > nest here /// > lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn two() {} /// > nest here /// > /// > > nest here /// lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn three() {} /// > * > nest here /// lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn four() {} /// > * > nest here /// lazy continuation -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn four_point_1() {} /// * > nest here lazy continuation @@ -43,5 +43,5 @@ fn five() {} /// 1. > nest here /// lazy continuation (this results in strange indentation, but still works) -//~^ ERROR: doc quote missing `>` marker +//~^ ERROR: doc quote line without `>` marker fn six() {} diff --git a/tests/ui/doc/doc_lazy_blockquote.stderr b/tests/ui/doc/doc_lazy_blockquote.stderr index 975184a01c3f..d3390efdff37 100644 --- a/tests/ui/doc/doc_lazy_blockquote.stderr +++ b/tests/ui/doc/doc_lazy_blockquote.stderr @@ -1,4 +1,4 @@ -error: doc quote missing `>` marker +error: doc quote line without `>` marker --> tests/ui/doc/doc_lazy_blockquote.rs:4:5 | LL | /// lazy continuation @@ -12,7 +12,7 @@ help: add markers to start of line LL | /// > lazy continuation | + -error: doc quote missing `>` marker +error: doc quote line without `>` marker --> tests/ui/doc/doc_lazy_blockquote.rs:20:5 | LL | /// > lazy continuation @@ -24,7 +24,7 @@ help: add markers to start of line LL | /// > > lazy continuation | + -error: doc quote missing `>` marker +error: doc quote line without `>` marker --> tests/ui/doc/doc_lazy_blockquote.rs:27:5 | LL | /// lazy continuation @@ -36,7 +36,7 @@ help: add markers to start of line LL | /// > > lazy continuation | +++ -error: doc quote missing `>` marker +error: doc quote line without `>` marker --> tests/ui/doc/doc_lazy_blockquote.rs:32:5 | LL | /// lazy continuation @@ -48,7 +48,7 @@ help: add markers to start of line LL | /// > > lazy continuation | +++++++ -error: doc quote missing `>` marker +error: doc quote line without `>` marker --> tests/ui/doc/doc_lazy_blockquote.rs:37:5 | LL | /// lazy continuation @@ -60,7 +60,7 @@ help: add markers to start of line LL | /// > > lazy continuation | +++++ -error: doc quote missing `>` marker +error: doc quote line without `>` marker --> tests/ui/doc/doc_lazy_blockquote.rs:45:5 | LL | /// lazy continuation (this results in strange indentation, but still works) diff --git a/tests/ui/doc/doc_lazy_list.fixed b/tests/ui/doc/doc_lazy_list.fixed index 409e6b0bc227..ea59ae4c01c9 100644 --- a/tests/ui/doc/doc_lazy_list.fixed +++ b/tests/ui/doc/doc_lazy_list.fixed @@ -2,38 +2,41 @@ /// 1. nest here /// lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn one() {} /// 1. first line /// lazy list continuations don't make warnings with this lint -//~^ ERROR: doc list item missing indentation -/// because they don't have the -//~^ ERROR: doc list item missing indentation +/// +//~^ ERROR: doc list item without indentation +/// because they don't have the +//~^ ERROR: doc list item without indentation fn two() {} /// - nest here /// lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn three() {} /// - first line /// lazy list continuations don't make warnings with this lint -//~^ ERROR: doc list item missing indentation -/// because they don't have the -//~^ ERROR: doc list item missing indentation +/// +//~^ ERROR: doc list item without indentation +/// because they don't have the +//~^ ERROR: doc list item without indentation fn four() {} /// - nest here /// lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn five() {} /// - - first line /// this will warn on the lazy continuation -//~^ ERROR: doc list item missing indentation -/// and so should this -//~^ ERROR: doc list item missing indentation +/// +//~^ ERROR: doc list item without indentation +/// and so should this +//~^ ERROR: doc list item without indentation fn six() {} /// - - first line @@ -54,7 +57,7 @@ fn seven() {} /// * `protocol_descriptors`: A Json Representation of the ProtocolDescriptors /// to set up. Example: /// 'protocol_descriptors': [ -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation /// { /// 'protocol': 25, # u64 Representation of ProtocolIdentifier::AVDTP /// 'params': [ @@ -73,5 +76,5 @@ fn seven() {} /// }] /// } /// ] -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn eight() {} diff --git a/tests/ui/doc/doc_lazy_list.rs b/tests/ui/doc/doc_lazy_list.rs index 30ab448a1130..3cc18e35780a 100644 --- a/tests/ui/doc/doc_lazy_list.rs +++ b/tests/ui/doc/doc_lazy_list.rs @@ -2,38 +2,38 @@ /// 1. nest here /// lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn one() {} /// 1. first line /// lazy list continuations don't make warnings with this lint -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation /// because they don't have the -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn two() {} /// - nest here /// lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn three() {} /// - first line /// lazy list continuations don't make warnings with this lint -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation /// because they don't have the -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn four() {} /// - nest here /// lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn five() {} /// - - first line /// this will warn on the lazy continuation -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation /// and so should this -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn six() {} /// - - first line @@ -54,7 +54,7 @@ fn seven() {} /// * `protocol_descriptors`: A Json Representation of the ProtocolDescriptors /// to set up. Example: /// 'protocol_descriptors': [ -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation /// { /// 'protocol': 25, # u64 Representation of ProtocolIdentifier::AVDTP /// 'params': [ @@ -73,5 +73,5 @@ fn seven() {} /// }] /// } /// ] -//~^ ERROR: doc list item missing indentation +//~^ ERROR: doc list item without indentation fn eight() {} diff --git a/tests/ui/doc/doc_lazy_list.stderr b/tests/ui/doc/doc_lazy_list.stderr index ddfdc49340c4..52aa74df8948 100644 --- a/tests/ui/doc/doc_lazy_list.stderr +++ b/tests/ui/doc/doc_lazy_list.stderr @@ -1,4 +1,4 @@ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:4:5 | LL | /// lazy continuation @@ -12,7 +12,7 @@ help: indent this line LL | /// lazy continuation | +++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:9:5 | LL | /// lazy list continuations don't make warnings with this lint @@ -24,19 +24,20 @@ help: indent this line LL | /// lazy list continuations don't make warnings with this lint | +++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:11:5 | LL | /// because they don't have the | ^ | - = help: if this is supposed to be its own paragraph, add a blank line -help: indent this line + = help: if this is intended to be part of the list, indent 3 spaces +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// lazy list continuations don't make warnings with this lint +LL + /// | -LL | /// because they don't have the - | +++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:16:5 | LL | /// lazy continuation @@ -48,7 +49,7 @@ help: indent this line LL | /// lazy continuation | ++++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:21:5 | LL | /// lazy list continuations don't make warnings with this lint @@ -60,19 +61,20 @@ help: indent this line LL | /// lazy list continuations don't make warnings with this lint | ++++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:23:5 | LL | /// because they don't have the | ^ | - = help: if this is supposed to be its own paragraph, add a blank line -help: indent this line + = help: if this is intended to be part of the list, indent 4 spaces +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// lazy list continuations don't make warnings with this lint +LL + /// | -LL | /// because they don't have the - | ++++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:28:5 | LL | /// lazy continuation @@ -84,7 +86,7 @@ help: indent this line LL | /// lazy continuation | ++++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:33:5 | LL | /// this will warn on the lazy continuation @@ -96,19 +98,20 @@ help: indent this line LL | /// this will warn on the lazy continuation | ++++++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:35:5 | LL | /// and so should this | ^^^^ | - = help: if this is supposed to be its own paragraph, add a blank line -help: indent this line + = help: if this is intended to be part of the list, indent 2 spaces +help: if this should be its own paragraph, add a blank doc comment line + | +LL ~ /// this will warn on the lazy continuation +LL + /// | -LL | /// and so should this - | ++ -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:56:5 | LL | /// 'protocol_descriptors': [ @@ -120,7 +123,7 @@ help: indent this line LL | /// 'protocol_descriptors': [ | + -error: doc list item missing indentation +error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:75:5 | LL | /// ] diff --git a/tests/ui/doc/unbalanced_ticks.rs b/tests/ui/doc/unbalanced_ticks.rs index 6f7bab72040c..04446787b6c2 100644 --- a/tests/ui/doc/unbalanced_ticks.rs +++ b/tests/ui/doc/unbalanced_ticks.rs @@ -49,3 +49,20 @@ fn other_markdown() {} /// pub struct Struct; /// ``` fn issue_7421() {} + +/// ` +//~^ ERROR: backticks are unbalanced +fn escape_0() {} + +/// Escaped \` backticks don't count. +fn escape_1() {} + +/// Escaped \` \` backticks don't count. +fn escape_2() {} + +/// Escaped \` ` backticks don't count, but unescaped backticks do. +//~^ ERROR: backticks are unbalanced +fn escape_3() {} + +/// Backslashes ` \` within code blocks don't count. +fn escape_4() {} diff --git a/tests/ui/doc/unbalanced_ticks.stderr b/tests/ui/doc/unbalanced_ticks.stderr index 56ef29136231..50324010e97f 100644 --- a/tests/ui/doc/unbalanced_ticks.stderr +++ b/tests/ui/doc/unbalanced_ticks.stderr @@ -78,5 +78,21 @@ help: try LL | /// - This item needs `backticks_here` | ~~~~~~~~~~~~~~~~ -error: aborting due to 8 previous errors +error: backticks are unbalanced + --> tests/ui/doc/unbalanced_ticks.rs:53:5 + | +LL | /// ` + | ^ + | + = help: a backtick may be missing a pair + +error: backticks are unbalanced + --> tests/ui/doc/unbalanced_ticks.rs:63:5 + | +LL | /// Escaped \` ` backticks don't count, but unescaped backticks do. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: a backtick may be missing a pair + +error: aborting due to 10 previous errors diff --git a/tests/ui/explicit_auto_deref.fixed b/tests/ui/explicit_auto_deref.fixed index e6ca4bb66ccd..255b2c5a220d 100644 --- a/tests/ui/explicit_auto_deref.fixed +++ b/tests/ui/explicit_auto_deref.fixed @@ -345,3 +345,39 @@ fn main() { let _ = &mut ({ *x.u }).x; } } + +mod issue_12969 { + use std::ops::Deref; + + struct Wrapper(T); + + impl Deref for Wrapper { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } + } + + fn foo(_bar: &str) {} + + fn bar() { + let wrapped_bar = Wrapper(""); + + foo(&wrapped_bar); + } +} + +mod issue_9841 { + fn takes_array_ref(array: &&[T; N]) { + takes_slice(*array) + } + + fn takes_array_ref_ref(array: &&&[T; N]) { + takes_slice(**array) + } + + fn takes_slice(slice: &[T]) { + todo!() + } +} diff --git a/tests/ui/explicit_auto_deref.rs b/tests/ui/explicit_auto_deref.rs index 7531e1f87b71..99906999f01d 100644 --- a/tests/ui/explicit_auto_deref.rs +++ b/tests/ui/explicit_auto_deref.rs @@ -345,3 +345,39 @@ fn main() { let _ = &mut ({ *x.u }).x; } } + +mod issue_12969 { + use std::ops::Deref; + + struct Wrapper(T); + + impl Deref for Wrapper { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } + } + + fn foo(_bar: &str) {} + + fn bar() { + let wrapped_bar = Wrapper(""); + + foo(&*wrapped_bar); + } +} + +mod issue_9841 { + fn takes_array_ref(array: &&[T; N]) { + takes_slice(*array) + } + + fn takes_array_ref_ref(array: &&&[T; N]) { + takes_slice(**array) + } + + fn takes_slice(slice: &[T]) { + todo!() + } +} diff --git a/tests/ui/explicit_auto_deref.stderr b/tests/ui/explicit_auto_deref.stderr index 56a183de3487..53784934f638 100644 --- a/tests/ui/explicit_auto_deref.stderr +++ b/tests/ui/explicit_auto_deref.stderr @@ -271,5 +271,11 @@ error: deref which would be done by auto-deref LL | let _ = &mut (*{ x.u }).x; | ^^^^^^^^^^ help: try: `{ x.u }` -error: aborting due to 45 previous errors +error: deref which would be done by auto-deref + --> tests/ui/explicit_auto_deref.rs:367:13 + | +LL | foo(&*wrapped_bar); + | ^^^^^^^^^^^^^ help: try: `&wrapped_bar` + +error: aborting due to 46 previous errors diff --git a/tests/ui/float_cmp.rs b/tests/ui/float_cmp.rs index 1923ad7c677e..78dd2c6c01c3 100644 --- a/tests/ui/float_cmp.rs +++ b/tests/ui/float_cmp.rs @@ -71,19 +71,16 @@ fn main() { twice(ONE) != ONE; ONE as f64 != 2.0; //~^ ERROR: strict comparison of `f32` or `f64` - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` ONE as f64 != 0.0; // no error, comparison with zero is ok let x: f64 = 1.0; x == 1.0; //~^ ERROR: strict comparison of `f32` or `f64` - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` x != 0f64; // no error, comparison with zero is ok twice(x) != twice(ONE as f64); //~^ ERROR: strict comparison of `f32` or `f64` - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` x < 0.0; // no errors, lower or greater comparisons need no fuzzyness x > 0.0; @@ -105,17 +102,14 @@ fn main() { ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; // ok, because lhs is zero regardless of i NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; //~^ ERROR: strict comparison of `f32` or `f64` - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` let a1: [f32; 1] = [0.0]; let a2: [f32; 1] = [1.1]; a1 == a2; //~^ ERROR: strict comparison of `f32` or `f64` arrays - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` a1[0] == a2[0]; //~^ ERROR: strict comparison of `f32` or `f64` - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` // no errors - comparing signums is ok let x32 = 3.21f32; diff --git a/tests/ui/float_cmp.stderr b/tests/ui/float_cmp.stderr index c8a0bde6e63a..d10da8a99a9d 100644 --- a/tests/ui/float_cmp.stderr +++ b/tests/ui/float_cmp.stderr @@ -4,49 +4,38 @@ error: strict comparison of `f32` or `f64` LL | ONE as f64 != 2.0; | ^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE as f64 - 2.0).abs() > error_margin` | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` = note: `-D clippy::float-cmp` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::float_cmp)]` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:79:5 + --> tests/ui/float_cmp.rs:78:5 | LL | x == 1.0; | ^^^^^^^^ help: consider comparing them within some margin of error: `(x - 1.0).abs() < error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:84:5 + --> tests/ui/float_cmp.rs:82:5 | LL | twice(x) != twice(ONE as f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(twice(x) - twice(ONE as f64)).abs() > error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:106:5 + --> tests/ui/float_cmp.rs:103:5 | LL | NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` arrays - --> tests/ui/float_cmp.rs:113:5 + --> tests/ui/float_cmp.rs:109:5 | LL | a1 == a2; | ^^^^^^^^ - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:116:5 + --> tests/ui/float_cmp.rs:111:5 | LL | a1[0] == a2[0]; | ^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(a1[0] - a2[0]).abs() < error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: aborting due to 6 previous errors diff --git a/tests/ui/float_cmp_const.rs b/tests/ui/float_cmp_const.rs index 47ea0e19c68b..081805564373 100644 --- a/tests/ui/float_cmp_const.rs +++ b/tests/ui/float_cmp_const.rs @@ -15,28 +15,21 @@ fn main() { // has errors 1f32 == ONE; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` TWO == ONE; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` TWO != ONE; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` ONE + ONE == TWO; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` let x = 1; x as f32 == ONE; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` let v = 0.9; v == ONE; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` v != ONE; //~^ ERROR: strict comparison of `f32` or `f64` constant - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` // no errors, lower than or greater than comparisons v < ONE; @@ -70,5 +63,4 @@ fn main() { // has errors NON_ZERO_ARRAY == NON_ZERO_ARRAY2; //~^ ERROR: strict comparison of `f32` or `f64` constant arrays - //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` } diff --git a/tests/ui/float_cmp_const.stderr b/tests/ui/float_cmp_const.stderr index bffd2acc2e04..4f88746e958e 100644 --- a/tests/ui/float_cmp_const.stderr +++ b/tests/ui/float_cmp_const.stderr @@ -4,65 +4,50 @@ error: strict comparison of `f32` or `f64` constant LL | 1f32 == ONE; | ^^^^^^^^^^^ help: consider comparing them within some margin of error: `(1f32 - ONE).abs() < error_margin` | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` = note: `-D clippy::float-cmp-const` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::float_cmp_const)]` error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:19:5 + --> tests/ui/float_cmp_const.rs:18:5 | LL | TWO == ONE; | ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() < error_margin` + +error: strict comparison of `f32` or `f64` constant + --> tests/ui/float_cmp_const.rs:20:5 | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` +LL | TWO != ONE; + | ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() > error_margin` error: strict comparison of `f32` or `f64` constant --> tests/ui/float_cmp_const.rs:22:5 | -LL | TWO != ONE; - | ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() > error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` +LL | ONE + ONE == TWO; + | ^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE + ONE - TWO).abs() < error_margin` error: strict comparison of `f32` or `f64` constant --> tests/ui/float_cmp_const.rs:25:5 | -LL | ONE + ONE == TWO; - | ^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE + ONE - TWO).abs() < error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` +LL | x as f32 == ONE; + | ^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(x as f32 - ONE).abs() < error_margin` error: strict comparison of `f32` or `f64` constant --> tests/ui/float_cmp_const.rs:29:5 | -LL | x as f32 == ONE; - | ^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(x as f32 - ONE).abs() < error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` - -error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:34:5 - | LL | v == ONE; | ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() < error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:37:5 + --> tests/ui/float_cmp_const.rs:31:5 | LL | v != ONE; | ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() > error_margin` - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: strict comparison of `f32` or `f64` constant arrays - --> tests/ui/float_cmp_const.rs:71:5 + --> tests/ui/float_cmp_const.rs:64:5 | LL | NON_ZERO_ARRAY == NON_ZERO_ARRAY2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` error: aborting due to 8 previous errors diff --git a/tests/ui/numbered_fields.fixed b/tests/ui/init_numbered_fields.fixed similarity index 82% rename from tests/ui/numbered_fields.fixed rename to tests/ui/init_numbered_fields.fixed index 108520eed38d..dca4e8da4d2f 100644 --- a/tests/ui/numbered_fields.fixed +++ b/tests/ui/init_numbered_fields.fixed @@ -39,4 +39,13 @@ fn main() { struct TupleStructVec(Vec); let _ = TupleStructVec(vec![0, 1, 2, 3]); + + { + struct S(i32, i32); + let mut iter = [1i32, 1i32].into_iter(); + let _ = S { + 1: iter.next().unwrap(), + 0: iter.next().unwrap(), + }; + } } diff --git a/tests/ui/numbered_fields.rs b/tests/ui/init_numbered_fields.rs similarity index 84% rename from tests/ui/numbered_fields.rs rename to tests/ui/init_numbered_fields.rs index c718661a6826..8cb34705b4f6 100644 --- a/tests/ui/numbered_fields.rs +++ b/tests/ui/init_numbered_fields.rs @@ -47,4 +47,13 @@ fn main() { struct TupleStructVec(Vec); let _ = TupleStructVec { 0: vec![0, 1, 2, 3] }; + + { + struct S(i32, i32); + let mut iter = [1i32, 1i32].into_iter(); + let _ = S { + 1: iter.next().unwrap(), + 0: iter.next().unwrap(), + }; + } } diff --git a/tests/ui/numbered_fields.stderr b/tests/ui/init_numbered_fields.stderr similarity index 63% rename from tests/ui/numbered_fields.stderr rename to tests/ui/init_numbered_fields.stderr index 9d3f59cd3769..f176e0c2ff30 100644 --- a/tests/ui/numbered_fields.stderr +++ b/tests/ui/init_numbered_fields.stderr @@ -1,5 +1,5 @@ error: used a field initializer for a tuple struct - --> tests/ui/numbered_fields.rs:17:13 + --> tests/ui/init_numbered_fields.rs:17:13 | LL | let _ = TupleStruct { | _____________^ @@ -7,13 +7,13 @@ LL | | 0: 1u32, LL | | 1: 42, LL | | 2: 23u8, LL | | }; - | |_____^ help: try: `TupleStruct(1u32, 42, 23u8)` + | |_____^ help: use tuple initialization: `TupleStruct(1u32, 42, 23u8)` | = note: `-D clippy::init-numbered-fields` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::init_numbered_fields)]` error: used a field initializer for a tuple struct - --> tests/ui/numbered_fields.rs:24:13 + --> tests/ui/init_numbered_fields.rs:24:13 | LL | let _ = TupleStruct { | _____________^ @@ -21,13 +21,13 @@ LL | | 0: 1u32, LL | | 2: 2u8, LL | | 1: 3u32, LL | | }; - | |_____^ help: try: `TupleStruct(1u32, 3u32, 2u8)` + | |_____^ help: use tuple initialization: `TupleStruct(1u32, 3u32, 2u8)` error: used a field initializer for a tuple struct - --> tests/ui/numbered_fields.rs:49:13 + --> tests/ui/init_numbered_fields.rs:49:13 | LL | let _ = TupleStructVec { 0: vec![0, 1, 2, 3] }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `TupleStructVec(vec![0, 1, 2, 3])` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use tuple initialization: `TupleStructVec(vec![0, 1, 2, 3])` error: aborting due to 3 previous errors diff --git a/tests/ui/into_iter_without_iter.rs b/tests/ui/into_iter_without_iter.rs index c8b9076041a3..109259d6975c 100644 --- a/tests/ui/into_iter_without_iter.rs +++ b/tests/ui/into_iter_without_iter.rs @@ -185,3 +185,42 @@ pub mod issue11635 { } } } + +pub mod issue12964 { + pub struct MyIter<'a, T: 'a> { + iter: std::slice::Iter<'a, T>, + } + + impl<'a, T> Iterator for MyIter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + self.iter.next() + } + } + + pub struct MyContainer { + inner: Vec, + } + + impl MyContainer {} + + impl MyContainer { + #[must_use] + pub fn iter(&self) -> MyIter<'_, T> { + <&Self as IntoIterator>::into_iter(self) + } + } + + impl<'a, T> IntoIterator for &'a MyContainer { + type Item = &'a T; + + type IntoIter = MyIter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + Self::IntoIter { + iter: self.inner.as_slice().iter(), + } + } + } +} diff --git a/tests/ui/iter_next_loop.rs b/tests/ui/iter_next_loop.rs index 548b799de44e..d425f4da0e81 100644 --- a/tests/ui/iter_next_loop.rs +++ b/tests/ui/iter_next_loop.rs @@ -3,7 +3,7 @@ fn main() { let x = [1, 2, 3, 4]; - for _ in vec.iter().next() {} + for _ in x.iter().next() {} struct Unrelated(&'static [u8]); impl Unrelated { diff --git a/tests/ui/iter_next_loop.stderr b/tests/ui/iter_next_loop.stderr index 85c23f4e7094..acc55031c3b2 100644 --- a/tests/ui/iter_next_loop.stderr +++ b/tests/ui/iter_next_loop.stderr @@ -1,9 +1,11 @@ -error[E0423]: expected value, found macro `vec` +error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want --> tests/ui/iter_next_loop.rs:6:14 | -LL | for _ in vec.iter().next() {} - | ^^^ not a value +LL | for _ in x.iter().next() {} + | ^^^^^^^^^^^^^^^ + | + = note: `-D clippy::iter-next-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_next_loop)]` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0423`. diff --git a/tests/ui/manual_inspect.stderr b/tests/ui/manual_inspect.stderr index 8548c0cd2942..0559b3bd6611 100644 --- a/tests/ui/manual_inspect.stderr +++ b/tests/ui/manual_inspect.stderr @@ -1,4 +1,4 @@ -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:5:21 | LL | let _ = Some(0).map(|x| { @@ -12,7 +12,7 @@ LL ~ let _ = Some(0).inspect(|&x| { LL ~ println!("{}", x); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:10:21 | LL | let _ = Some(0).map(|x| { @@ -24,7 +24,7 @@ LL ~ let _ = Some(0).inspect(|&x| { LL ~ println!("{x}"); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:15:21 | LL | let _ = Some(0).map(|x| { @@ -36,7 +36,7 @@ LL ~ let _ = Some(0).inspect(|&x| { LL ~ println!("{}", x * 5 + 1); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:20:21 | LL | let _ = Some(0).map(|x| { @@ -50,7 +50,7 @@ LL | panic!(); LL ~ } | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:27:21 | LL | let _ = Some(0).map(|x| { @@ -65,7 +65,7 @@ LL | panic!(); LL ~ } | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:78:41 | LL | let _ = Some((String::new(), 0u32)).map(|x| { @@ -80,7 +80,7 @@ LL | panic!(); LL ~ } | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:104:33 | LL | let _ = Some(String::new()).map(|x| { @@ -98,7 +98,7 @@ LL | } LL ~ println!("test"); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:115:21 | LL | let _ = Some(0).map(|x| { @@ -113,7 +113,7 @@ LL | panic!(); LL ~ } | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:130:46 | LL | let _ = Some(Cell2(Cell::new(0u32))).map(|x| { @@ -125,7 +125,7 @@ LL ~ let _ = Some(Cell2(Cell::new(0u32))).inspect(|x| { LL ~ x.0.set(1); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:146:34 | LL | let _: Result<_, ()> = Ok(0).map(|x| { @@ -137,7 +137,7 @@ LL ~ let _: Result<_, ()> = Ok(0).inspect(|&x| { LL ~ println!("{}", x); | -error: +error: using `map_err` over `inspect_err` --> tests/ui/manual_inspect.rs:151:35 | LL | let _: Result<(), _> = Err(0).map_err(|x| { @@ -166,7 +166,7 @@ LL | | .count(); = note: `-D clippy::suspicious-map` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::suspicious_map)]` -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:158:10 | LL | .map(|x| { diff --git a/tests/ui/manual_rotate.fixed b/tests/ui/manual_rotate.fixed new file mode 100644 index 000000000000..5d33838a3187 --- /dev/null +++ b/tests/ui/manual_rotate.fixed @@ -0,0 +1,31 @@ +#![warn(clippy::manual_rotate)] +#![allow(unused)] +fn main() { + let (x_u8, x_u16, x_u32, x_u64) = (1u8, 1u16, 1u32, 1u64); + let (x_i8, x_i16, x_i32, x_i64) = (1i8, 1i16, 1i32, 1i64); + let a_u32 = 1u32; + // True positives + let y_u8 = x_u8.rotate_right(3); + let y_u16 = x_u16.rotate_right(7); + let y_u32 = x_u32.rotate_right(8); + let y_u64 = x_u64.rotate_right(9); + let y_i8 = x_i8.rotate_right(3); + let y_i16 = x_i16.rotate_right(7); + let y_i32 = x_i32.rotate_right(8); + let y_i64 = x_i64.rotate_right(9); + // Plus also works instead of | + let y_u32_plus = x_u32.rotate_right(8); + // Complex expression + let y_u32_complex = (x_u32 | 3256).rotate_right(8); + let y_u64_as = (x_u32 as u64).rotate_right(8); + + // False positives - can't be replaced with a rotation + let y_u8_false = (x_u8 >> 6) | (x_u8 << 3); + let y_u32_false = (x_u32 >> 8) | (x_u32 >> 24); + let y_u64_false2 = (x_u64 >> 9) & (x_u64 << 55); + // Variable mismatch + let y_u32_wrong_vars = (x_u32 >> 8) | (a_u32 << 24); + // Has side effects and therefore should not be matched + let mut l = vec![12_u8, 34]; + let y = (l.pop().unwrap() << 3) + (l.pop().unwrap() >> 5); +} diff --git a/tests/ui/manual_rotate.rs b/tests/ui/manual_rotate.rs new file mode 100644 index 000000000000..5377491fb1a3 --- /dev/null +++ b/tests/ui/manual_rotate.rs @@ -0,0 +1,31 @@ +#![warn(clippy::manual_rotate)] +#![allow(unused)] +fn main() { + let (x_u8, x_u16, x_u32, x_u64) = (1u8, 1u16, 1u32, 1u64); + let (x_i8, x_i16, x_i32, x_i64) = (1i8, 1i16, 1i32, 1i64); + let a_u32 = 1u32; + // True positives + let y_u8 = (x_u8 >> 3) | (x_u8 << 5); + let y_u16 = (x_u16 >> 7) | (x_u16 << 9); + let y_u32 = (x_u32 >> 8) | (x_u32 << 24); + let y_u64 = (x_u64 >> 9) | (x_u64 << 55); + let y_i8 = (x_i8 >> 3) | (x_i8 << 5); + let y_i16 = (x_i16 >> 7) | (x_i16 << 9); + let y_i32 = (x_i32 >> 8) | (x_i32 << 24); + let y_i64 = (x_i64 >> 9) | (x_i64 << 55); + // Plus also works instead of | + let y_u32_plus = (x_u32 >> 8) + (x_u32 << 24); + // Complex expression + let y_u32_complex = ((x_u32 | 3256) >> 8) | ((x_u32 | 3256) << 24); + let y_u64_as = (x_u32 as u64 >> 8) | ((x_u32 as u64) << 56); + + // False positives - can't be replaced with a rotation + let y_u8_false = (x_u8 >> 6) | (x_u8 << 3); + let y_u32_false = (x_u32 >> 8) | (x_u32 >> 24); + let y_u64_false2 = (x_u64 >> 9) & (x_u64 << 55); + // Variable mismatch + let y_u32_wrong_vars = (x_u32 >> 8) | (a_u32 << 24); + // Has side effects and therefore should not be matched + let mut l = vec![12_u8, 34]; + let y = (l.pop().unwrap() << 3) + (l.pop().unwrap() >> 5); +} diff --git a/tests/ui/manual_rotate.stderr b/tests/ui/manual_rotate.stderr new file mode 100644 index 000000000000..52da0861f700 --- /dev/null +++ b/tests/ui/manual_rotate.stderr @@ -0,0 +1,71 @@ +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:8:16 + | +LL | let y_u8 = (x_u8 >> 3) | (x_u8 << 5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u8.rotate_right(3)` + | + = note: `-D clippy::manual-rotate` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_rotate)]` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:9:17 + | +LL | let y_u16 = (x_u16 >> 7) | (x_u16 << 9); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u16.rotate_right(7)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:10:17 + | +LL | let y_u32 = (x_u32 >> 8) | (x_u32 << 24); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u32.rotate_right(8)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:11:17 + | +LL | let y_u64 = (x_u64 >> 9) | (x_u64 << 55); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u64.rotate_right(9)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:12:16 + | +LL | let y_i8 = (x_i8 >> 3) | (x_i8 << 5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i8.rotate_right(3)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:13:17 + | +LL | let y_i16 = (x_i16 >> 7) | (x_i16 << 9); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i16.rotate_right(7)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:14:17 + | +LL | let y_i32 = (x_i32 >> 8) | (x_i32 << 24); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i32.rotate_right(8)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:15:17 + | +LL | let y_i64 = (x_i64 >> 9) | (x_i64 << 55); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i64.rotate_right(9)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:17:22 + | +LL | let y_u32_plus = (x_u32 >> 8) + (x_u32 << 24); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u32.rotate_right(8)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:19:25 + | +LL | let y_u32_complex = ((x_u32 | 3256) >> 8) | ((x_u32 | 3256) << 24); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `(x_u32 | 3256).rotate_right(8)` + +error: there is no need to manually implement bit rotation + --> tests/ui/manual_rotate.rs:20:20 + | +LL | let y_u64_as = (x_u32 as u64 >> 8) | ((x_u32 as u64) << 56); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `(x_u32 as u64).rotate_right(8)` + +error: aborting due to 11 previous errors + diff --git a/tests/ui/missing_const_for_fn/cant_be_const.rs b/tests/ui/missing_const_for_fn/cant_be_const.rs index 2750e0cdf3f7..2c6e1e92da02 100644 --- a/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -7,6 +7,7 @@ #![warn(clippy::missing_const_for_fn)] #![feature(start)] +#![feature(type_alias_impl_trait)] extern crate helper; extern crate proc_macros; @@ -180,4 +181,21 @@ mod msrv { unsafe { *self.1 as usize } } } + + #[clippy::msrv = "1.61"] + extern "C" fn c() {} +} + +mod with_extern { + extern "C-unwind" fn c_unwind() {} + extern "system" fn system() {} + extern "system-unwind" fn system_unwind() {} +} + +mod with_ty_alias { + type Foo = impl std::fmt::Debug; + + fn foo(_: Foo) { + let _: Foo = 1; + } } diff --git a/tests/ui/missing_const_for_fn/could_be_const.fixed b/tests/ui/missing_const_for_fn/could_be_const.fixed index f8fc935f3679..dbd739eee138 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.fixed +++ b/tests/ui/missing_const_for_fn/could_be_const.fixed @@ -143,6 +143,21 @@ mod msrv { let bar = Bar { val: 1 }; let _ = unsafe { bar.val }; } + + #[clippy::msrv = "1.62"] + mod with_extern { + const extern "C" fn c() {} + //~^ ERROR: this could be a `const fn` + + #[rustfmt::skip] + const extern fn implicit_c() {} + //~^ ERROR: this could be a `const fn` + + // any item functions in extern block won't trigger this lint + extern "C" { + fn c_in_block(); + } + } } mod issue12677 { @@ -174,3 +189,18 @@ mod issue12677 { } } } + +mod with_ty_alias { + trait FooTrait { + type Foo: std::fmt::Debug; + fn bar(_: Self::Foo) {} + } + impl FooTrait for () { + type Foo = i32; + } + // NOTE: When checking the type of a function param, make sure it is not an alias with + // `AliasTyKind::Projection` before calling `TyCtxt::type_of` to find out what the actual type + // is. Because the associate ty could have no default, therefore would cause ICE, as demostrated + // in this test. + const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} +} diff --git a/tests/ui/missing_const_for_fn/could_be_const.rs b/tests/ui/missing_const_for_fn/could_be_const.rs index 5e4e2c58e5a4..4ac56f4c8034 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/tests/ui/missing_const_for_fn/could_be_const.rs @@ -143,6 +143,21 @@ mod msrv { let bar = Bar { val: 1 }; let _ = unsafe { bar.val }; } + + #[clippy::msrv = "1.62"] + mod with_extern { + extern "C" fn c() {} + //~^ ERROR: this could be a `const fn` + + #[rustfmt::skip] + extern fn implicit_c() {} + //~^ ERROR: this could be a `const fn` + + // any item functions in extern block won't trigger this lint + extern "C" { + fn c_in_block(); + } + } } mod issue12677 { @@ -174,3 +189,18 @@ mod issue12677 { } } } + +mod with_ty_alias { + trait FooTrait { + type Foo: std::fmt::Debug; + fn bar(_: Self::Foo) {} + } + impl FooTrait for () { + type Foo = i32; + } + // NOTE: When checking the type of a function param, make sure it is not an alias with + // `AliasTyKind::Projection` before calling `TyCtxt::type_of` to find out what the actual type + // is. Because the associate ty could have no default, therefore would cause ICE, as demostrated + // in this test. + fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} +} diff --git a/tests/ui/missing_const_for_fn/could_be_const.stderr b/tests/ui/missing_const_for_fn/could_be_const.stderr index 8302b074127e..fb4db7031031 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -211,7 +211,29 @@ LL | const fn union_access_can_be_const() { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:155:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:149:9 + | +LL | extern "C" fn c() {} + | ^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const extern "C" fn c() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:153:9 + | +LL | extern fn implicit_c() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const extern fn implicit_c() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:170:9 | LL | / pub fn new(strings: Vec) -> Self { LL | | Self { strings } @@ -224,7 +246,7 @@ LL | pub const fn new(strings: Vec) -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:160:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:175:9 | LL | / pub fn empty() -> Self { LL | | Self { strings: Vec::new() } @@ -237,7 +259,7 @@ LL | pub const fn empty() -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:171:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:186:9 | LL | / pub fn new(text: String) -> Self { LL | | let vec = Vec::new(); @@ -250,5 +272,16 @@ help: make the function `const` LL | pub const fn new(text: String) -> Self { | +++++ -error: aborting due to 18 previous errors +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:205:5 + | +LL | fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} + | +++++ + +error: aborting due to 21 previous errors diff --git a/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed b/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed new file mode 100644 index 000000000000..c103db536ab5 --- /dev/null +++ b/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed @@ -0,0 +1,14 @@ +#![warn(clippy::missing_const_for_fn)] +#![allow(unsupported_calling_conventions)] +#![feature(const_extern_fn)] + +const extern "C-unwind" fn c_unwind() {} +//~^ ERROR: this could be a `const fn` +const extern "system" fn system() {} +//~^ ERROR: this could be a `const fn` +const extern "system-unwind" fn system_unwind() {} +//~^ ERROR: this could be a `const fn` +pub const extern "stdcall" fn std_call() {} +//~^ ERROR: this could be a `const fn` +pub const extern "stdcall-unwind" fn std_call_unwind() {} +//~^ ERROR: this could be a `const fn` diff --git a/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs b/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs new file mode 100644 index 000000000000..0f7020ae559a --- /dev/null +++ b/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs @@ -0,0 +1,14 @@ +#![warn(clippy::missing_const_for_fn)] +#![allow(unsupported_calling_conventions)] +#![feature(const_extern_fn)] + +extern "C-unwind" fn c_unwind() {} +//~^ ERROR: this could be a `const fn` +extern "system" fn system() {} +//~^ ERROR: this could be a `const fn` +extern "system-unwind" fn system_unwind() {} +//~^ ERROR: this could be a `const fn` +pub extern "stdcall" fn std_call() {} +//~^ ERROR: this could be a `const fn` +pub extern "stdcall-unwind" fn std_call_unwind() {} +//~^ ERROR: this could be a `const fn` diff --git a/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr b/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr new file mode 100644 index 000000000000..036094a367b2 --- /dev/null +++ b/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr @@ -0,0 +1,59 @@ +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:5:1 + | +LL | extern "C-unwind" fn c_unwind() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::missing-const-for-fn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_fn)]` +help: make the function `const` + | +LL | const extern "C-unwind" fn c_unwind() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:7:1 + | +LL | extern "system" fn system() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const extern "system" fn system() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:9:1 + | +LL | extern "system-unwind" fn system_unwind() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const extern "system-unwind" fn system_unwind() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:11:1 + | +LL | pub extern "stdcall" fn std_call() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | pub const extern "stdcall" fn std_call() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:13:1 + | +LL | pub extern "stdcall-unwind" fn std_call_unwind() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | pub const extern "stdcall-unwind" fn std_call_unwind() {} + | +++++ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/thread_local_initializer_can_be_made_const.fixed b/tests/ui/missing_const_for_thread_local.fixed similarity index 97% rename from tests/ui/thread_local_initializer_can_be_made_const.fixed rename to tests/ui/missing_const_for_thread_local.fixed index 4c9bd0bd8634..90b31b9b5d21 100644 --- a/tests/ui/thread_local_initializer_can_be_made_const.fixed +++ b/tests/ui/missing_const_for_thread_local.fixed @@ -1,4 +1,4 @@ -#![warn(clippy::thread_local_initializer_can_be_made_const)] +#![warn(clippy::missing_const_for_thread_local)] use std::cell::{Cell, RefCell}; diff --git a/tests/ui/thread_local_initializer_can_be_made_const.rs b/tests/ui/missing_const_for_thread_local.rs similarity index 97% rename from tests/ui/thread_local_initializer_can_be_made_const.rs rename to tests/ui/missing_const_for_thread_local.rs index eb336f0dd191..f97e4848fd7a 100644 --- a/tests/ui/thread_local_initializer_can_be_made_const.rs +++ b/tests/ui/missing_const_for_thread_local.rs @@ -1,4 +1,4 @@ -#![warn(clippy::thread_local_initializer_can_be_made_const)] +#![warn(clippy::missing_const_for_thread_local)] use std::cell::{Cell, RefCell}; diff --git a/tests/ui/thread_local_initializer_can_be_made_const.stderr b/tests/ui/missing_const_for_thread_local.stderr similarity index 72% rename from tests/ui/thread_local_initializer_can_be_made_const.stderr rename to tests/ui/missing_const_for_thread_local.stderr index b4f8bd822b0d..c143a37454f5 100644 --- a/tests/ui/thread_local_initializer_can_be_made_const.stderr +++ b/tests/ui/missing_const_for_thread_local.stderr @@ -1,38 +1,38 @@ error: initializer for `thread_local` value can be made `const` - --> tests/ui/thread_local_initializer_can_be_made_const.rs:8:41 + --> tests/ui/missing_const_for_thread_local.rs:8:41 | LL | static BUF_1: RefCell = RefCell::new(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }` | - = note: `-D clippy::thread-local-initializer-can-be-made-const` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::thread_local_initializer_can_be_made_const)]` + = note: `-D clippy::missing-const-for-thread-local` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_thread_local)]` error: initializer for `thread_local` value can be made `const` - --> tests/ui/thread_local_initializer_can_be_made_const.rs:18:29 + --> tests/ui/missing_const_for_thread_local.rs:18:29 | LL | static SIMPLE:i32 = 1; | ^ help: replace with: `const { 1 }` error: initializer for `thread_local` value can be made `const` - --> tests/ui/thread_local_initializer_can_be_made_const.rs:24:59 + --> tests/ui/missing_const_for_thread_local.rs:24:59 | LL | static BUF_3_CAN_BE_MADE_CONST: RefCell = RefCell::new(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }` error: initializer for `thread_local` value can be made `const` - --> tests/ui/thread_local_initializer_can_be_made_const.rs:26:59 + --> tests/ui/missing_const_for_thread_local.rs:26:59 | LL | static BUF_4_CAN_BE_MADE_CONST: RefCell = RefCell::new(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }` error: initializer for `thread_local` value can be made `const` - --> tests/ui/thread_local_initializer_can_be_made_const.rs:32:31 + --> tests/ui/missing_const_for_thread_local.rs:32:31 | LL | static PEEL_ME: i32 = { 1 }; | ^^^^^ help: replace with: `const { 1 }` error: initializer for `thread_local` value can be made `const` - --> tests/ui/thread_local_initializer_can_be_made_const.rs:34:36 + --> tests/ui/missing_const_for_thread_local.rs:34:36 | LL | static PEEL_ME_MANY: i32 = { let x = 1; x * x }; | ^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { { let x = 1; x * x } }` diff --git a/tests/ui/needless_pass_by_ref_mut.rs b/tests/ui/needless_pass_by_ref_mut.rs index eee62122fdfd..162ec82aeded 100644 --- a/tests/ui/needless_pass_by_ref_mut.rs +++ b/tests/ui/needless_pass_by_ref_mut.rs @@ -232,43 +232,48 @@ async fn async_vec2(b: &mut Vec) { } fn non_mut(n: &str) {} //Should warn -pub async fn call_in_closure1(n: &mut str) { +async fn call_in_closure1(n: &mut str) { (|| non_mut(n))() } fn str_mut(str: &mut String) -> bool { str.pop().is_some() } //Should not warn -pub async fn call_in_closure2(str: &mut String) { +async fn call_in_closure2(str: &mut String) { (|| str_mut(str))(); } // Should not warn. -pub async fn closure(n: &mut usize) -> impl '_ + FnMut() { +async fn closure(n: &mut usize) -> impl '_ + FnMut() { || { *n += 1; } } // Should warn. -pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { +fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { //~^ ERROR: this argument is a mutable reference, but not used mutably || *n + 1 } // Should not warn. -pub async fn closure3(n: &mut usize) { +async fn closure3(n: &mut usize) { (|| *n += 1)(); } // Should warn. -pub async fn closure4(n: &mut usize) { +async fn closure4(n: &mut usize) { //~^ ERROR: this argument is a mutable reference, but not used mutably (|| { let _x = *n + 1; })(); } +// Should not warn: pub +pub fn pub_foo(s: &mut Vec, b: &u32, x: &mut u32) { + *x += *b + s.len() as u32; +} + // Should not warn. async fn _f(v: &mut Vec<()>) { let x = || v.pop(); @@ -365,4 +370,5 @@ fn main() { used_as_path; let _: fn(&mut u32) = passed_as_local; let _ = if v[0] == 0 { ty_unify_1 } else { ty_unify_2 }; + pub_foo(&mut v, &0, &mut u); } diff --git a/tests/ui/needless_pass_by_ref_mut.stderr b/tests/ui/needless_pass_by_ref_mut.stderr index 51e3ba37dede..f462fa9099ed 100644 --- a/tests/ui/needless_pass_by_ref_mut.stderr +++ b/tests/ui/needless_pass_by_ref_mut.stderr @@ -108,109 +108,103 @@ LL | async fn inner_async3(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:235:34 + --> tests/ui/needless_pass_by_ref_mut.rs:235:30 | -LL | pub async fn call_in_closure1(n: &mut str) { - | ^^^^^^^^ help: consider changing to: `&str` - | - = warning: changing this function will impact semver compatibility +LL | async fn call_in_closure1(n: &mut str) { + | ^^^^^^^^ help: consider changing to: `&str` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:254:20 + --> tests/ui/needless_pass_by_ref_mut.rs:254:16 | -LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { - | ^^^^^^^^^^ help: consider changing to: `&usize` - | - = warning: changing this function will impact semver compatibility +LL | fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { + | ^^^^^^^^^^ help: consider changing to: `&usize` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:265:26 + --> tests/ui/needless_pass_by_ref_mut.rs:265:22 | -LL | pub async fn closure4(n: &mut usize) { - | ^^^^^^^^^^ help: consider changing to: `&usize` - | - = warning: changing this function will impact semver compatibility +LL | async fn closure4(n: &mut usize) { + | ^^^^^^^^^^ help: consider changing to: `&usize` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:314:12 + --> tests/ui/needless_pass_by_ref_mut.rs:319:12 | LL | fn bar(&mut self) {} | ^^^^^^^^^ help: consider changing to: `&self` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:316:18 + --> tests/ui/needless_pass_by_ref_mut.rs:321:18 | LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) { | ^^^^^^^^^ help: consider changing to: `&self` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:316:45 + --> tests/ui/needless_pass_by_ref_mut.rs:321:45 | LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:324:46 + --> tests/ui/needless_pass_by_ref_mut.rs:329:46 | LL | async fn foo2(&mut self, u: &mut i32, v: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:340:18 + --> tests/ui/needless_pass_by_ref_mut.rs:345:18 | LL | fn _empty_tup(x: &mut (())) {} | ^^^^^^^^^ help: consider changing to: `&()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:341:19 + --> tests/ui/needless_pass_by_ref_mut.rs:346:19 | LL | fn _single_tup(x: &mut ((i32,))) {} | ^^^^^^^^^^^^^ help: consider changing to: `&(i32,)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:342:18 + --> tests/ui/needless_pass_by_ref_mut.rs:347:18 | LL | fn _multi_tup(x: &mut ((i32, u32))) {} | ^^^^^^^^^^^^^^^^^ help: consider changing to: `&(i32, u32)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:343:11 + --> tests/ui/needless_pass_by_ref_mut.rs:348:11 | LL | fn _fn(x: &mut (fn())) {} | ^^^^^^^^^^^ help: consider changing to: `&fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:345:23 + --> tests/ui/needless_pass_by_ref_mut.rs:350:23 | LL | fn _extern_rust_fn(x: &mut extern "Rust" fn()) {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "Rust" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:346:20 + --> tests/ui/needless_pass_by_ref_mut.rs:351:20 | LL | fn _extern_c_fn(x: &mut extern "C" fn()) {} | ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "C" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:347:18 + --> tests/ui/needless_pass_by_ref_mut.rs:352:18 | LL | fn _unsafe_fn(x: &mut unsafe fn()) {} | ^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:348:25 + --> tests/ui/needless_pass_by_ref_mut.rs:353:25 | LL | fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:349:20 + --> tests/ui/needless_pass_by_ref_mut.rs:354:20 | LL | fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn(i32)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:350:20 + --> tests/ui/needless_pass_by_ref_mut.rs:355:20 | LL | fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn() -> (i32)` diff --git a/tests/ui/needless_pass_by_ref_mut2.fixed b/tests/ui/needless_pass_by_ref_mut2.fixed index 3c2576213cd7..f26b39ea6a16 100644 --- a/tests/ui/needless_pass_by_ref_mut2.fixed +++ b/tests/ui/needless_pass_by_ref_mut2.fixed @@ -5,7 +5,7 @@ #![allow(clippy::redundant_closure_call)] #![warn(clippy::needless_pass_by_ref_mut)] -pub async fn inner_async3(x: &i32, y: &mut u32) { +async fn inner_async3(x: &i32, y: &mut u32) { //~^ ERROR: this argument is a mutable reference, but not used mutably async { *y += 1; @@ -13,7 +13,7 @@ pub async fn inner_async3(x: &i32, y: &mut u32) { .await; } -pub async fn inner_async4(u: &mut i32, v: &u32) { +async fn inner_async4(u: &mut i32, v: &u32) { //~^ ERROR: this argument is a mutable reference, but not used mutably async { *u += 1; diff --git a/tests/ui/needless_pass_by_ref_mut2.rs b/tests/ui/needless_pass_by_ref_mut2.rs index 34b0b564deb8..4220215b1fe9 100644 --- a/tests/ui/needless_pass_by_ref_mut2.rs +++ b/tests/ui/needless_pass_by_ref_mut2.rs @@ -5,7 +5,7 @@ #![allow(clippy::redundant_closure_call)] #![warn(clippy::needless_pass_by_ref_mut)] -pub async fn inner_async3(x: &mut i32, y: &mut u32) { +async fn inner_async3(x: &mut i32, y: &mut u32) { //~^ ERROR: this argument is a mutable reference, but not used mutably async { *y += 1; @@ -13,7 +13,7 @@ pub async fn inner_async3(x: &mut i32, y: &mut u32) { .await; } -pub async fn inner_async4(u: &mut i32, v: &mut u32) { +async fn inner_async4(u: &mut i32, v: &mut u32) { //~^ ERROR: this argument is a mutable reference, but not used mutably async { *u += 1; diff --git a/tests/ui/needless_pass_by_ref_mut2.stderr b/tests/ui/needless_pass_by_ref_mut2.stderr index c87536032256..1c0136cf5d59 100644 --- a/tests/ui/needless_pass_by_ref_mut2.stderr +++ b/tests/ui/needless_pass_by_ref_mut2.stderr @@ -1,20 +1,17 @@ error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut2.rs:8:30 + --> tests/ui/needless_pass_by_ref_mut2.rs:8:26 | -LL | pub async fn inner_async3(x: &mut i32, y: &mut u32) { - | ^^^^^^^^ help: consider changing to: `&i32` +LL | async fn inner_async3(x: &mut i32, y: &mut u32) { + | ^^^^^^^^ help: consider changing to: `&i32` | - = warning: changing this function will impact semver compatibility = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut2.rs:16:43 + --> tests/ui/needless_pass_by_ref_mut2.rs:16:39 | -LL | pub async fn inner_async4(u: &mut i32, v: &mut u32) { - | ^^^^^^^^ help: consider changing to: `&u32` - | - = warning: changing this function will impact semver compatibility +LL | async fn inner_async4(u: &mut i32, v: &mut u32) { + | ^^^^^^^^ help: consider changing to: `&u32` error: aborting due to 2 previous errors diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 853f685f04c7..fc4129e1db84 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -228,12 +228,41 @@ fn needless_return_macro() -> String { format!("Hello {}", "world!") } -fn issue_9361() -> i32 { - let n = 1; - #[allow(clippy::arithmetic_side_effects)] +fn issue_9361(n: i32) -> i32 { + #[expect(clippy::arithmetic_side_effects)] return n + n; } +mod issue_12998 { + fn expect_lint() -> i32 { + let x = 1; + + #[expect(clippy::needless_return)] + return x; + } + + fn expect_group() -> i32 { + let x = 1; + + #[expect(clippy::style)] + return x; + } + + fn expect_all() -> i32 { + let x = 1; + + #[expect(clippy::all)] + return x; + } + + fn expect_warnings() -> i32 { + let x = 1; + + #[expect(warnings)] + return x; + } +} + fn issue8336(x: i32) -> bool { if x > 0 { println!("something"); diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index e9c1e0e8ae8e..61c7a02008f0 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -236,12 +236,41 @@ fn needless_return_macro() -> String { return format!("Hello {}", "world!"); } -fn issue_9361() -> i32 { - let n = 1; - #[allow(clippy::arithmetic_side_effects)] +fn issue_9361(n: i32) -> i32 { + #[expect(clippy::arithmetic_side_effects)] return n + n; } +mod issue_12998 { + fn expect_lint() -> i32 { + let x = 1; + + #[expect(clippy::needless_return)] + return x; + } + + fn expect_group() -> i32 { + let x = 1; + + #[expect(clippy::style)] + return x; + } + + fn expect_all() -> i32 { + let x = 1; + + #[expect(clippy::all)] + return x; + } + + fn expect_warnings() -> i32 { + let x = 1; + + #[expect(warnings)] + return x; + } +} + fn issue8336(x: i32) -> bool { if x > 0 { println!("something"); diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 6c891fe7ad3f..ea9c230eafd2 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -483,7 +483,7 @@ LL + format!("Hello {}", "world!") | error: unneeded `return` statement - --> tests/ui/needless_return.rs:248:9 + --> tests/ui/needless_return.rs:277:9 | LL | return true; | ^^^^^^^^^^^ @@ -497,7 +497,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:250:9 + --> tests/ui/needless_return.rs:279:9 | LL | return false; | ^^^^^^^^^^^^ @@ -509,7 +509,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:257:13 + --> tests/ui/needless_return.rs:286:13 | LL | return 10; | ^^^^^^^^^ @@ -524,7 +524,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:260:13 + --> tests/ui/needless_return.rs:289:13 | LL | return 100; | ^^^^^^^^^^ @@ -537,7 +537,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:268:9 + --> tests/ui/needless_return.rs:297:9 | LL | return 0; | ^^^^^^^^ @@ -549,7 +549,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:275:13 + --> tests/ui/needless_return.rs:304:13 | LL | return *(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -564,7 +564,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:277:13 + --> tests/ui/needless_return.rs:306:13 | LL | return !*(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -577,7 +577,7 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:284:20 + --> tests/ui/needless_return.rs:313:20 | LL | let _ = 42; | ____________________^ @@ -594,7 +594,7 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:291:20 + --> tests/ui/needless_return.rs:320:20 | LL | let _ = 42; return; | ^^^^^^^ @@ -606,7 +606,7 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:303:9 + --> tests/ui/needless_return.rs:332:9 | LL | return Ok(format!("ok!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -618,7 +618,7 @@ LL + Ok(format!("ok!")) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:305:9 + --> tests/ui/needless_return.rs:334:9 | LL | return Err(format!("err!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -630,7 +630,7 @@ LL + Err(format!("err!")) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:311:9 + --> tests/ui/needless_return.rs:340:9 | LL | return if true { 1 } else { 2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -642,7 +642,7 @@ LL + if true { 1 } else { 2 } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:315:9 + --> tests/ui/needless_return.rs:344:9 | LL | return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -654,7 +654,7 @@ LL + (if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else | error: unneeded `return` statement - --> tests/ui/needless_return.rs:336:5 + --> tests/ui/needless_return.rs:365:5 | LL | return { "a".to_string() } + "b" + { "c" }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/overflow_check_conditional.rs b/tests/ui/overflow_check_conditional.rs deleted file mode 100644 index a70bb3bc47bf..000000000000 --- a/tests/ui/overflow_check_conditional.rs +++ /dev/null @@ -1,36 +0,0 @@ -#![warn(clippy::overflow_check_conditional)] -#![allow(clippy::needless_if)] - -fn test(a: u32, b: u32, c: u32) { - if a + b < a {} - //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust - //~| NOTE: `-D clippy::overflow-check-conditional` implied by `-D warnings` - if a > a + b {} - //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust - if a + b < b {} - //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust - if b > a + b {} - //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust - if a - b > b {} - //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus - if b < a - b {} - //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus - if a - b > a {} - //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus - if a < a - b {} - //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus - if a + b < c {} - if c > a + b {} - if a - b < c {} - if c > a - b {} - let i = 1.1; - let j = 2.2; - if i + j < i {} - if i - j < i {} - if i > i + j {} - if i - j < i {} -} - -fn main() { - test(1, 2, 3) -} diff --git a/tests/ui/overflow_check_conditional.stderr b/tests/ui/overflow_check_conditional.stderr deleted file mode 100644 index c14532bad5ab..000000000000 --- a/tests/ui/overflow_check_conditional.stderr +++ /dev/null @@ -1,53 +0,0 @@ -error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:5:8 - | -LL | if a + b < a {} - | ^^^^^^^^^ - | - = note: `-D clippy::overflow-check-conditional` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::overflow_check_conditional)]` - -error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:8:8 - | -LL | if a > a + b {} - | ^^^^^^^^^ - -error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:10:8 - | -LL | if a + b < b {} - | ^^^^^^^^^ - -error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:12:8 - | -LL | if b > a + b {} - | ^^^^^^^^^ - -error: you are trying to use classic C underflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:14:8 - | -LL | if a - b > b {} - | ^^^^^^^^^ - -error: you are trying to use classic C underflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:16:8 - | -LL | if b < a - b {} - | ^^^^^^^^^ - -error: you are trying to use classic C underflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:18:8 - | -LL | if a - b > a {} - | ^^^^^^^^^ - -error: you are trying to use classic C underflow conditions that will fail in Rust - --> tests/ui/overflow_check_conditional.rs:20:8 - | -LL | if a < a - b {} - | ^^^^^^^^^ - -error: aborting due to 8 previous errors - diff --git a/tests/ui/panicking_overflow_checks.rs b/tests/ui/panicking_overflow_checks.rs new file mode 100644 index 000000000000..dc2ddeada1e9 --- /dev/null +++ b/tests/ui/panicking_overflow_checks.rs @@ -0,0 +1,27 @@ +#![warn(clippy::panicking_overflow_checks)] +#![allow(clippy::needless_if)] + +fn test(a: u32, b: u32, c: u32) { + if a + b < a {} //~ panicking_overflow_checks + if a > a + b {} //~ panicking_overflow_checks + if a + b < b {} //~ panicking_overflow_checks + if b > a + b {} //~ panicking_overflow_checks + if a - b > b {} + if b < a - b {} + if a - b > a {} //~ panicking_overflow_checks + if a < a - b {} //~ panicking_overflow_checks + if a + b < c {} + if c > a + b {} + if a - b < c {} + if c > a - b {} + let i = 1.1; + let j = 2.2; + if i + j < i {} + if i - j < i {} + if i > i + j {} + if i - j < i {} +} + +fn main() { + test(1, 2, 3) +} diff --git a/tests/ui/panicking_overflow_checks.stderr b/tests/ui/panicking_overflow_checks.stderr new file mode 100644 index 000000000000..1fae04578899 --- /dev/null +++ b/tests/ui/panicking_overflow_checks.stderr @@ -0,0 +1,41 @@ +error: you are trying to use classic C overflow conditions that will fail in Rust + --> tests/ui/panicking_overflow_checks.rs:5:8 + | +LL | if a + b < a {} + | ^^^^^^^^^ + | + = note: `-D clippy::panicking-overflow-checks` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::panicking_overflow_checks)]` + +error: you are trying to use classic C overflow conditions that will fail in Rust + --> tests/ui/panicking_overflow_checks.rs:6:8 + | +LL | if a > a + b {} + | ^^^^^^^^^ + +error: you are trying to use classic C overflow conditions that will fail in Rust + --> tests/ui/panicking_overflow_checks.rs:7:8 + | +LL | if a + b < b {} + | ^^^^^^^^^ + +error: you are trying to use classic C overflow conditions that will fail in Rust + --> tests/ui/panicking_overflow_checks.rs:8:8 + | +LL | if b > a + b {} + | ^^^^^^^^^ + +error: you are trying to use classic C overflow conditions that will fail in Rust + --> tests/ui/panicking_overflow_checks.rs:11:8 + | +LL | if a - b > a {} + | ^^^^^^^^^ + +error: you are trying to use classic C overflow conditions that will fail in Rust + --> tests/ui/panicking_overflow_checks.rs:12:8 + | +LL | if a < a - b {} + | ^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/ptr_as_ptr.stderr b/tests/ui/ptr_as_ptr.stderr index e162f35baf55..18462620b0a3 100644 --- a/tests/ui/ptr_as_ptr.stderr +++ b/tests/ui/ptr_as_ptr.stderr @@ -1,4 +1,4 @@ -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:18:33 | LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::issue_11278_a::T) } @@ -7,37 +7,37 @@ LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::i = note: `-D clippy::ptr-as-ptr` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:27:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:28:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:33:17 | LL | let _ = *ptr_ptr as *const i32; | ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:46:25 | LL | let _: *const i32 = ptr as *const _; | ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:47:23 | LL | let _: *mut i32 = mut_ptr as _; | ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:50:21 | LL | let _ = inline!($ptr as *const i32); @@ -45,157 +45,157 @@ LL | let _ = inline!($ptr as *const i32); | = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:71:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:72:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:79:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:83:9 | LL | std::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:88:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:92:9 | LL | core::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:97:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:101:9 | LL | std::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:106:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:110:9 | LL | core::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:117:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:121:9 | LL | std::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:126:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:130:9 | LL | core::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:135:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:139:9 | LL | std::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:144:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:148:9 | LL | core::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:155:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:159:9 | LL | std::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:164:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:168:9 | LL | core::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:173:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:177:9 | LL | std::ptr::null() as _ | ^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:182:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:186:9 | LL | core::ptr::null() as _ diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 24d0f7975428..d70c9f8d06c0 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -24,9 +24,11 @@ #![allow(clippy::expect_used)] #![allow(clippy::map_unwrap_or)] #![allow(clippy::unwrap_used)] +#![allow(clippy::panicking_overflow_checks)] #![allow(clippy::needless_borrow)] #![allow(clippy::single_char_add_str)] #![allow(clippy::module_name_repetitions)] +#![allow(clippy::missing_const_for_thread_local)] #![allow(clippy::recursive_format_impl)] #![allow(clippy::unwrap_or_default)] #![allow(clippy::invisible_characters)] @@ -77,12 +79,14 @@ #![warn(clippy::map_unwrap_or)] #![warn(clippy::map_unwrap_or)] #![warn(clippy::unwrap_used)] +#![warn(clippy::panicking_overflow_checks)] #![warn(clippy::needless_borrow)] #![warn(clippy::expect_used)] #![warn(clippy::map_unwrap_or)] #![warn(clippy::unwrap_used)] #![warn(clippy::single_char_add_str)] #![warn(clippy::module_name_repetitions)] +#![warn(clippy::missing_const_for_thread_local)] #![warn(clippy::recursive_format_impl)] #![warn(clippy::unwrap_or_default)] #![warn(clippy::invisible_characters)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index be8da2fa1a38..8d0ac3c8f955 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -24,9 +24,11 @@ #![allow(clippy::expect_used)] #![allow(clippy::map_unwrap_or)] #![allow(clippy::unwrap_used)] +#![allow(clippy::panicking_overflow_checks)] #![allow(clippy::needless_borrow)] #![allow(clippy::single_char_add_str)] #![allow(clippy::module_name_repetitions)] +#![allow(clippy::missing_const_for_thread_local)] #![allow(clippy::recursive_format_impl)] #![allow(clippy::unwrap_or_default)] #![allow(clippy::invisible_characters)] @@ -77,12 +79,14 @@ #![warn(clippy::option_map_unwrap_or)] #![warn(clippy::option_map_unwrap_or_else)] #![warn(clippy::option_unwrap_used)] +#![warn(clippy::overflow_check_conditional)] #![warn(clippy::ref_in_deref)] #![warn(clippy::result_expect_used)] #![warn(clippy::result_map_unwrap_or_else)] #![warn(clippy::result_unwrap_used)] #![warn(clippy::single_char_push_str)] #![warn(clippy::stutter)] +#![warn(clippy::thread_local_initializer_can_be_made_const)] #![warn(clippy::to_string_in_display)] #![warn(clippy::unwrap_or_else_default)] #![warn(clippy::zero_width_space)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index 777ac20153da..d6637324a030 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> tests/ui/rename.rs:56:9 + --> tests/ui/rename.rs:58:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -8,346 +8,358 @@ LL | #![warn(clippy::almost_complete_letter_range)] = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> tests/ui/rename.rs:57:9 + --> tests/ui/rename.rs:59:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_conditions` - --> tests/ui/rename.rs:58:9 + --> tests/ui/rename.rs:60:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_conditions` - --> tests/ui/rename.rs:59:9 + --> tests/ui/rename.rs:61:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` error: lint `clippy::blocks_in_if_conditions` has been renamed to `clippy::blocks_in_conditions` - --> tests/ui/rename.rs:60:9 + --> tests/ui/rename.rs:62:9 | LL | #![warn(clippy::blocks_in_if_conditions)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> tests/ui/rename.rs:61:9 + --> tests/ui/rename.rs:63:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> tests/ui/rename.rs:62:9 + --> tests/ui/rename.rs:64:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> tests/ui/rename.rs:63:9 + --> tests/ui/rename.rs:65:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> tests/ui/rename.rs:64:9 + --> tests/ui/rename.rs:66:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> tests/ui/rename.rs:65:9 + --> tests/ui/rename.rs:67:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> tests/ui/rename.rs:66:9 + --> tests/ui/rename.rs:68:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> tests/ui/rename.rs:67:9 + --> tests/ui/rename.rs:69:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> tests/ui/rename.rs:68:9 + --> tests/ui/rename.rs:70:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> tests/ui/rename.rs:69:9 + --> tests/ui/rename.rs:71:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl` - --> tests/ui/rename.rs:70:9 + --> tests/ui/rename.rs:72:9 | LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl` error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl` - --> tests/ui/rename.rs:71:9 + --> tests/ui/rename.rs:73:9 | LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl` error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` - --> tests/ui/rename.rs:72:9 + --> tests/ui/rename.rs:74:9 | LL | #![warn(clippy::integer_arithmetic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> tests/ui/rename.rs:73:9 + --> tests/ui/rename.rs:75:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> tests/ui/rename.rs:74:9 + --> tests/ui/rename.rs:76:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> tests/ui/rename.rs:75:9 + --> tests/ui/rename.rs:77:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> tests/ui/rename.rs:76:9 + --> tests/ui/rename.rs:78:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> tests/ui/rename.rs:77:9 + --> tests/ui/rename.rs:79:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> tests/ui/rename.rs:78:9 + --> tests/ui/rename.rs:80:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> tests/ui/rename.rs:79:9 + --> tests/ui/rename.rs:81:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` +error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks` + --> tests/ui/rename.rs:82:9 + | +LL | #![warn(clippy::overflow_check_conditional)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks` + error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> tests/ui/rename.rs:80:9 + --> tests/ui/rename.rs:83:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> tests/ui/rename.rs:81:9 + --> tests/ui/rename.rs:84:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> tests/ui/rename.rs:82:9 + --> tests/ui/rename.rs:85:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> tests/ui/rename.rs:83:9 + --> tests/ui/rename.rs:86:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> tests/ui/rename.rs:84:9 + --> tests/ui/rename.rs:87:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> tests/ui/rename.rs:85:9 + --> tests/ui/rename.rs:88:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` +error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local` + --> tests/ui/rename.rs:89:9 + | +LL | #![warn(clippy::thread_local_initializer_can_be_made_const)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local` + error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> tests/ui/rename.rs:86:9 + --> tests/ui/rename.rs:90:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default` - --> tests/ui/rename.rs:87:9 + --> tests/ui/rename.rs:91:9 | LL | #![warn(clippy::unwrap_or_else_default)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> tests/ui/rename.rs:88:9 + --> tests/ui/rename.rs:92:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting` - --> tests/ui/rename.rs:89:9 + --> tests/ui/rename.rs:93:9 | LL | #![warn(clippy::cast_ref_to_mut)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting` error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` - --> tests/ui/rename.rs:90:9 + --> tests/ui/rename.rs:94:9 | LL | #![warn(clippy::clone_double_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons` - --> tests/ui/rename.rs:91:9 + --> tests/ui/rename.rs:95:9 | LL | #![warn(clippy::cmp_nan)] | ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> tests/ui/rename.rs:92:9 + --> tests/ui/rename.rs:96:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` - --> tests/ui/rename.rs:93:9 + --> tests/ui/rename.rs:97:9 | LL | #![warn(clippy::drop_copy)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` error: lint `clippy::drop_ref` has been renamed to `dropping_references` - --> tests/ui/rename.rs:94:9 + --> tests/ui/rename.rs:98:9 | LL | #![warn(clippy::drop_ref)] | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks` - --> tests/ui/rename.rs:95:9 + --> tests/ui/rename.rs:99:9 | LL | #![warn(clippy::fn_null_check)] | ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> tests/ui/rename.rs:96:9 + --> tests/ui/rename.rs:100:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> tests/ui/rename.rs:97:9 + --> tests/ui/rename.rs:101:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> tests/ui/rename.rs:98:9 + --> tests/ui/rename.rs:102:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` - --> tests/ui/rename.rs:99:9 + --> tests/ui/rename.rs:103:9 | LL | #![warn(clippy::forget_copy)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` error: lint `clippy::forget_ref` has been renamed to `forgetting_references` - --> tests/ui/rename.rs:100:9 + --> tests/ui/rename.rs:104:9 | LL | #![warn(clippy::forget_ref)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> tests/ui/rename.rs:101:9 + --> tests/ui/rename.rs:105:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> tests/ui/rename.rs:102:9 + --> tests/ui/rename.rs:106:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> tests/ui/rename.rs:103:9 + --> tests/ui/rename.rs:107:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` - --> tests/ui/rename.rs:104:9 + --> tests/ui/rename.rs:108:9 | LL | #![warn(clippy::invalid_utf8_in_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> tests/ui/rename.rs:105:9 + --> tests/ui/rename.rs:109:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> tests/ui/rename.rs:106:9 + --> tests/ui/rename.rs:110:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> tests/ui/rename.rs:107:9 + --> tests/ui/rename.rs:111:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> tests/ui/rename.rs:108:9 + --> tests/ui/rename.rs:112:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> tests/ui/rename.rs:109:9 + --> tests/ui/rename.rs:113:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` - --> tests/ui/rename.rs:110:9 + --> tests/ui/rename.rs:114:9 | LL | #![warn(clippy::undropped_manually_drops)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> tests/ui/rename.rs:111:9 + --> tests/ui/rename.rs:115:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> tests/ui/rename.rs:112:9 + --> tests/ui/rename.rs:116:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons` - --> tests/ui/rename.rs:113:9 + --> tests/ui/rename.rs:117:9 | LL | #![warn(clippy::vtable_address_comparisons)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons` -error: aborting due to 58 previous errors +error: aborting due to 60 previous errors diff --git a/tests/ui/set_contains_or_insert.rs b/tests/ui/set_contains_or_insert.rs new file mode 100644 index 000000000000..8465007402ab --- /dev/null +++ b/tests/ui/set_contains_or_insert.rs @@ -0,0 +1,83 @@ +#![allow(unused)] +#![allow(clippy::nonminimal_bool)] +#![allow(clippy::needless_borrow)] +#![warn(clippy::set_contains_or_insert)] + +use std::collections::HashSet; + +fn main() { + should_warn_cases(); + + should_not_warn_cases(); +} + +fn should_warn_cases() { + let mut set = HashSet::new(); + let value = 5; + + if !set.contains(&value) { + set.insert(value); + println!("Just a comment"); + } + + if set.contains(&value) { + set.insert(value); + println!("Just a comment"); + } + + if !set.contains(&value) { + set.insert(value); + } + + if !!set.contains(&value) { + set.insert(value); + println!("Just a comment"); + } + + if (&set).contains(&value) { + set.insert(value); + } + + let borrow_value = &6; + if !set.contains(borrow_value) { + set.insert(*borrow_value); + } + + let borrow_set = &mut set; + if !borrow_set.contains(&value) { + borrow_set.insert(value); + } +} + +fn should_not_warn_cases() { + let mut set = HashSet::new(); + let value = 5; + let another_value = 6; + + if !set.contains(&value) { + set.insert(another_value); + } + + if !set.contains(&value) { + println!("Just a comment"); + } + + if simply_true() { + set.insert(value); + } + + if !set.contains(&value) { + set.replace(value); //it is not insert + println!("Just a comment"); + } + + if set.contains(&value) { + println!("value is already in set"); + } else { + set.insert(value); + } +} + +fn simply_true() -> bool { + true +} diff --git a/tests/ui/set_contains_or_insert.stderr b/tests/ui/set_contains_or_insert.stderr new file mode 100644 index 000000000000..507e20964fc2 --- /dev/null +++ b/tests/ui/set_contains_or_insert.stderr @@ -0,0 +1,61 @@ +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:18:13 + | +LL | if !set.contains(&value) { + | ^^^^^^^^^^^^^^^^ +LL | set.insert(value); + | ^^^^^^^^^^^^^ + | + = note: `-D clippy::set-contains-or-insert` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::set_contains_or_insert)]` + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:23:12 + | +LL | if set.contains(&value) { + | ^^^^^^^^^^^^^^^^ +LL | set.insert(value); + | ^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:28:13 + | +LL | if !set.contains(&value) { + | ^^^^^^^^^^^^^^^^ +LL | set.insert(value); + | ^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:32:14 + | +LL | if !!set.contains(&value) { + | ^^^^^^^^^^^^^^^^ +LL | set.insert(value); + | ^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:37:15 + | +LL | if (&set).contains(&value) { + | ^^^^^^^^^^^^^^^^ +LL | set.insert(value); + | ^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:42:13 + | +LL | if !set.contains(borrow_value) { + | ^^^^^^^^^^^^^^^^^^^^^^ +LL | set.insert(*borrow_value); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:47:20 + | +LL | if !borrow_set.contains(&value) { + | ^^^^^^^^^^^^^^^^ +LL | borrow_set.insert(value); + | ^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors + diff --git a/tests/ui/significant_drop_in_scrutinee.rs b/tests/ui/significant_drop_in_scrutinee.rs index 8ee15440ccf0..0db6fbfb7be9 100644 --- a/tests/ui/significant_drop_in_scrutinee.rs +++ b/tests/ui/significant_drop_in_scrutinee.rs @@ -801,4 +801,30 @@ fn should_not_trigger_lint_with_explicit_drop() { } } +fn should_trigger_lint_in_if_let() { + let mutex = Mutex::new(vec![1]); + + if let Some(val) = mutex.lock().unwrap().first().copied() { + //~^ ERROR: temporary with significant `Drop` in `if let` scrutinee will live until the + //~| NOTE: this might lead to deadlocks or other unexpected behavior + println!("{}", val); + } + + // Should not trigger lint without the final `copied()`, because we actually hold a reference + // (i.e., the `val`) to the locked data. + if let Some(val) = mutex.lock().unwrap().first() { + println!("{}", val); + }; +} + +fn should_trigger_lint_in_while_let() { + let mutex = Mutex::new(vec![1]); + + while let Some(val) = mutex.lock().unwrap().pop() { + //~^ ERROR: temporary with significant `Drop` in `while let` scrutinee will live until the + //~| NOTE: this might lead to deadlocks or other unexpected behavior + println!("{}", val); + } +} + fn main() {} diff --git a/tests/ui/significant_drop_in_scrutinee.stderr b/tests/ui/significant_drop_in_scrutinee.stderr index 4a483e79d8ad..c0c93cd10c02 100644 --- a/tests/ui/significant_drop_in_scrutinee.stderr +++ b/tests/ui/significant_drop_in_scrutinee.stderr @@ -541,5 +541,32 @@ LL ~ let value = mutex.lock().unwrap()[0]; LL ~ for val in [value, 2] { | -error: aborting due to 27 previous errors +error: temporary with significant `Drop` in `if let` scrutinee will live until the end of the `if let` expression + --> tests/ui/significant_drop_in_scrutinee.rs:807:24 + | +LL | if let Some(val) = mutex.lock().unwrap().first().copied() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | } + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior +help: try moving the temporary above the match + | +LL ~ let value = mutex.lock().unwrap().first().copied(); +LL ~ if let Some(val) = value { + | + +error: temporary with significant `Drop` in `while let` scrutinee will live until the end of the `while let` expression + --> tests/ui/significant_drop_in_scrutinee.rs:823:27 + | +LL | while let Some(val) = mutex.lock().unwrap().pop() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | } + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior + +error: aborting due to 29 previous errors diff --git a/tests/ui/unnecessary_operation.fixed b/tests/ui/unnecessary_operation.fixed index 11761c6c90e3..006f123cbcdf 100644 --- a/tests/ui/unnecessary_operation.fixed +++ b/tests/ui/unnecessary_operation.fixed @@ -43,7 +43,7 @@ fn get_number() -> i32 { 0 } -fn get_usize() -> usize { +const fn get_usize() -> usize { 0 } fn get_struct() -> Struct { @@ -113,4 +113,16 @@ fn main() { 'label: { break 'label }; + let () = const { + [42, 55][get_usize()]; + }; +} + +const _: () = { + [42, 55][get_usize()]; +}; + +const fn foo() { + assert!([42, 55].len() > get_usize()); + //~^ ERROR: unnecessary operation } diff --git a/tests/ui/unnecessary_operation.rs b/tests/ui/unnecessary_operation.rs index de0081289ac3..b4067c740741 100644 --- a/tests/ui/unnecessary_operation.rs +++ b/tests/ui/unnecessary_operation.rs @@ -43,7 +43,7 @@ fn get_number() -> i32 { 0 } -fn get_usize() -> usize { +const fn get_usize() -> usize { 0 } fn get_struct() -> Struct { @@ -117,4 +117,16 @@ fn main() { 'label: { break 'label }; + let () = const { + [42, 55][get_usize()]; + }; +} + +const _: () = { + [42, 55][get_usize()]; +}; + +const fn foo() { + [42, 55][get_usize()]; + //~^ ERROR: unnecessary operation } diff --git a/tests/ui/unnecessary_operation.stderr b/tests/ui/unnecessary_operation.stderr index 27be5e6f4b92..036a9a44bbad 100644 --- a/tests/ui/unnecessary_operation.stderr +++ b/tests/ui/unnecessary_operation.stderr @@ -119,5 +119,11 @@ LL | | s: String::from("blah"), LL | | }; | |______^ help: statement can be reduced to: `String::from("blah");` -error: aborting due to 19 previous errors +error: unnecessary operation + --> tests/ui/unnecessary_operation.rs:130:5 + | +LL | [42, 55][get_usize()]; + | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());` + +error: aborting due to 20 previous errors diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index 1afa5ab54c46..fdcac8fb08dc 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -157,6 +157,25 @@ fn main() { require_path(&std::path::PathBuf::from("x")); require_str(&String::from("x")); require_slice(&[String::from("x")]); + + let slice = [0u8; 1024]; + let _ref_str: &str = core::str::from_utf8(&slice).expect("not UTF-8"); + let _ref_str: &str = core::str::from_utf8(b"foo").unwrap(); + let _ref_str: &str = core::str::from_utf8(b"foo".as_slice()).unwrap(); + // Expression is of type `&String`, can't suggest `str::from_utf8` here + let _ref_string = &String::from_utf8(b"foo".to_vec()).unwrap(); + macro_rules! arg_from_macro { + () => { + b"foo".to_vec() + }; + } + macro_rules! string_from_utf8_from_macro { + () => { + &String::from_utf8(b"foo".to_vec()).unwrap() + }; + } + let _ref_str: &str = &String::from_utf8(arg_from_macro!()).unwrap(); + let _ref_str: &str = string_from_utf8_from_macro!(); } fn require_c_str(_: &CStr) {} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index aa88dde43bf6..10a9727a9a79 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -157,6 +157,25 @@ fn main() { require_path(&std::path::PathBuf::from("x").to_path_buf()); require_str(&String::from("x").to_string()); require_slice(&[String::from("x")].to_owned()); + + let slice = [0u8; 1024]; + let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8"); + let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap(); + let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap(); + // Expression is of type `&String`, can't suggest `str::from_utf8` here + let _ref_string = &String::from_utf8(b"foo".to_vec()).unwrap(); + macro_rules! arg_from_macro { + () => { + b"foo".to_vec() + }; + } + macro_rules! string_from_utf8_from_macro { + () => { + &String::from_utf8(b"foo".to_vec()).unwrap() + }; + } + let _ref_str: &str = &String::from_utf8(arg_from_macro!()).unwrap(); + let _ref_str: &str = string_from_utf8_from_macro!(); } fn require_c_str(_: &CStr) {} diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index 2829f3cd6e98..511b4ae119f8 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -477,8 +477,44 @@ error: unnecessary use of `to_owned` LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` +error: allocating a new `String` only to create a temporary `&str` from it + --> tests/ui/unnecessary_to_owned.rs:162:26 + | +LL | let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert from `&[u8]` to `&str` directly + | +LL - let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8"); +LL + let _ref_str: &str = core::str::from_utf8(&slice).expect("not UTF-8"); + | + +error: allocating a new `String` only to create a temporary `&str` from it + --> tests/ui/unnecessary_to_owned.rs:163:26 + | +LL | let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert from `&[u8]` to `&str` directly + | +LL - let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap(); +LL + let _ref_str: &str = core::str::from_utf8(b"foo").unwrap(); + | + +error: allocating a new `String` only to create a temporary `&str` from it + --> tests/ui/unnecessary_to_owned.rs:164:26 + | +LL | let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert from `&[u8]` to `&str` directly + | +LL - let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap(); +LL + let _ref_str: &str = core::str::from_utf8(b"foo".as_slice()).unwrap(); + | + error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:202:14 + --> tests/ui/unnecessary_to_owned.rs:221:14 | LL | for t in file_types.to_vec() { | ^^^^^^^^^^^^^^^^^^^ @@ -494,64 +530,64 @@ LL + let path = match get_file_path(t) { | error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:225:14 + --> tests/ui/unnecessary_to_owned.rs:244:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().cloned()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:230:14 + --> tests/ui/unnecessary_to_owned.rs:249:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().copied()` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:278:24 + --> tests/ui/unnecessary_to_owned.rs:297:24 | LL | Box::new(build(y.to_string())) | ^^^^^^^^^^^^^ help: use: `y` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:387:12 + --> tests/ui/unnecessary_to_owned.rs:406:12 | LL | id("abc".to_string()) | ^^^^^^^^^^^^^^^^^ help: use: `"abc"` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:530:37 + --> tests/ui/unnecessary_to_owned.rs:549:37 | LL | IntoFuture::into_future(foo([].to_vec(), &0)); | ^^^^^^^^^^^ help: use: `[]` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:540:18 + --> tests/ui/unnecessary_to_owned.rs:559:18 | LL | s.remove(&a.to_vec()); | ^^^^^^^^^^^ help: replace it with: `a` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:544:14 + --> tests/ui/unnecessary_to_owned.rs:563:14 | LL | s.remove(&"b".to_owned()); | ^^^^^^^^^^^^^^^ help: replace it with: `"b"` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:545:14 + --> tests/ui/unnecessary_to_owned.rs:564:14 | LL | s.remove(&"b".to_string()); | ^^^^^^^^^^^^^^^^ help: replace it with: `"b"` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:550:14 + --> tests/ui/unnecessary_to_owned.rs:569:14 | LL | s.remove(&["b"].to_vec()); | ^^^^^^^^^^^^^^^ help: replace it with: `["b"].as_slice()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:551:14 + --> tests/ui/unnecessary_to_owned.rs:570:14 | LL | s.remove(&(&["b"]).to_vec()); | ^^^^^^^^^^^^^^^^^^ help: replace it with: `(&["b"]).as_slice()` -error: aborting due to 85 previous errors +error: aborting due to 88 previous errors diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index 6fdd728b9b72..46890ee9213f 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -204,6 +204,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass { use super::*; @@ -212,6 +213,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_inside_function { fn with_super_inside_function() { use super::*; @@ -219,6 +221,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_further_inside { fn insidefoo() {} mod inner { diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index 20e06d4b3664..1a5586cbb88d 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -205,6 +205,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass { use super::*; @@ -213,6 +214,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_inside_function { fn with_super_inside_function() { use super::*; @@ -220,6 +222,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_further_inside { fn insidefoo() {} mod inner { diff --git a/tests/ui/wildcard_imports.stderr b/tests/ui/wildcard_imports.stderr index 0c69d5262c26..8e88f216394d 100644 --- a/tests/ui/wildcard_imports.stderr +++ b/tests/ui/wildcard_imports.stderr @@ -106,31 +106,31 @@ LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:236:17 + --> tests/ui/wildcard_imports.rs:239:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:244:13 + --> tests/ui/wildcard_imports.rs:247:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:253:17 + --> tests/ui/wildcard_imports.rs:256:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:262:13 + --> tests/ui/wildcard_imports.rs:265:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:270:13 + --> tests/ui/wildcard_imports.rs:273:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/tests/ui/wildcard_imports_2021.edition2018.fixed b/tests/ui/wildcard_imports_2021.edition2018.fixed index 6a9fe007d654..197dd3b94df0 100644 --- a/tests/ui/wildcard_imports_2021.edition2018.fixed +++ b/tests/ui/wildcard_imports_2021.edition2018.fixed @@ -198,6 +198,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass { use super::*; @@ -206,6 +207,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_inside_function { fn with_super_inside_function() { use super::*; @@ -213,6 +215,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_further_inside { fn insidefoo() {} mod inner { diff --git a/tests/ui/wildcard_imports_2021.edition2018.stderr b/tests/ui/wildcard_imports_2021.edition2018.stderr index 11e0bd377692..66adacd95dcc 100644 --- a/tests/ui/wildcard_imports_2021.edition2018.stderr +++ b/tests/ui/wildcard_imports_2021.edition2018.stderr @@ -106,31 +106,31 @@ LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:230:17 + --> tests/ui/wildcard_imports_2021.rs:233:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:238:13 + --> tests/ui/wildcard_imports_2021.rs:241:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:247:17 + --> tests/ui/wildcard_imports_2021.rs:250:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:256:13 + --> tests/ui/wildcard_imports_2021.rs:259:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:264:13 + --> tests/ui/wildcard_imports_2021.rs:267:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/tests/ui/wildcard_imports_2021.edition2021.fixed b/tests/ui/wildcard_imports_2021.edition2021.fixed index 6a9fe007d654..197dd3b94df0 100644 --- a/tests/ui/wildcard_imports_2021.edition2021.fixed +++ b/tests/ui/wildcard_imports_2021.edition2021.fixed @@ -198,6 +198,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass { use super::*; @@ -206,6 +207,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_inside_function { fn with_super_inside_function() { use super::*; @@ -213,6 +215,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_further_inside { fn insidefoo() {} mod inner { diff --git a/tests/ui/wildcard_imports_2021.edition2021.stderr b/tests/ui/wildcard_imports_2021.edition2021.stderr index 11e0bd377692..66adacd95dcc 100644 --- a/tests/ui/wildcard_imports_2021.edition2021.stderr +++ b/tests/ui/wildcard_imports_2021.edition2021.stderr @@ -106,31 +106,31 @@ LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:230:17 + --> tests/ui/wildcard_imports_2021.rs:233:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:238:13 + --> tests/ui/wildcard_imports_2021.rs:241:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:247:17 + --> tests/ui/wildcard_imports_2021.rs:250:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:256:13 + --> tests/ui/wildcard_imports_2021.rs:259:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:264:13 + --> tests/ui/wildcard_imports_2021.rs:267:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/tests/ui/wildcard_imports_2021.rs b/tests/ui/wildcard_imports_2021.rs index 18ebc0f51274..606ff080e774 100644 --- a/tests/ui/wildcard_imports_2021.rs +++ b/tests/ui/wildcard_imports_2021.rs @@ -199,6 +199,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass { use super::*; @@ -207,6 +208,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_inside_function { fn with_super_inside_function() { use super::*; @@ -214,6 +216,7 @@ mod super_imports { } } + #[cfg(test)] mod test_should_pass_further_inside { fn insidefoo() {} mod inner { From d5e1acae82b68e6437e8ed4972328f8e6d6dc7ea Mon Sep 17 00:00:00 2001 From: Spencer Will Date: Thu, 4 Apr 2024 17:47:05 -0400 Subject: [PATCH 106/734] Add Expand All and Collapse All --- util/gh-pages/index.html | 18 +++++++++++------- util/gh-pages/script.js | 6 ++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/util/gh-pages/index.html b/util/gh-pages/index.html index 8de36fc40051..d4cec81bcd98 100644 --- a/util/gh-pages/index.html +++ b/util/gh-pages/index.html @@ -57,20 +57,17 @@ Otherwise, have a great day =^.^= background-color: var(--theme-hover); } - div.panel div.panel-body button.dropdown-toggle { + div.panel div.panel-body button { background: var(--searchbar-bg); color: var(--searchbar-fg); border-color: var(--theme-popup-border); } - div.panel div.panel-body button.dropdown-toggle:hover { + div.panel div.panel-body button:hover { box-shadow: 0 0 3px var(--searchbar-shadow-color); } - div.panel div.panel-body .open button.dropdown-toggle { - background: var(--searchbar-bg); - color: var(--searchbar-fg); - border-color: var(--theme-popup-border); + div.panel div.panel-body button.open { filter: brightness(90%); } @@ -96,7 +93,6 @@ Otherwise, have a great day =^.^= @media (min-width: 992px) { .search-control { margin-top: 0; - float: right; } } @@ -537,6 +533,14 @@ Otherwise, have a great day =^.^= +

+ + +
diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index 921bb0376f6c..661f80a6d346 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -469,6 +469,12 @@ $location.path(lint.id); }; + $scope.toggleExpansion = function(lints, isExpanded) { + lints.forEach(lint => { + $scope.open[lint.id] = isExpanded; + }); + } + $scope.copyToClipboard = function (lint) { const clipboard = document.getElementById("clipboard-" + lint.id); if (clipboard) { From 8bfd992953937be4ba71833a5e64687b900701fb Mon Sep 17 00:00:00 2001 From: Spencer Will Date: Tue, 9 Apr 2024 15:32:46 -0400 Subject: [PATCH 107/734] Fix button styling on desktop and mobile views. --- util/gh-pages/index.html | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/util/gh-pages/index.html b/util/gh-pages/index.html index d4cec81bcd98..9c82dafb2309 100644 --- a/util/gh-pages/index.html +++ b/util/gh-pages/index.html @@ -357,6 +357,24 @@ Otherwise, have a great day =^.^= opacity: 30%; } + .expansion-group { + margin-top: 15px; + padding: 0px 8px; + display: flex; + flex-wrap: nowrap; + } + + @media (min-width: 992px) { + .expansion-group { + margin-top: 0; + padding: 0px 15px; + } + } + + .expansion-control { + width: 50%; + } + :not(pre) > code { color: var(--inline-code-color); background-color: var(--inline-code-bg); @@ -533,7 +551,7 @@ Otherwise, have a great day =^.^= -
+
From 6ae5fd958fdcef7232c7b349370a6fa58600ef4c Mon Sep 17 00:00:00 2001 From: Spencer Will Date: Sun, 7 Jul 2024 18:53:53 -0400 Subject: [PATCH 108/734] Remove event propagation calls. Adjust column spacing for filter panel to give more space for buttons on smaller screens. --- util/gh-pages/index.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util/gh-pages/index.html b/util/gh-pages/index.html index 9c82dafb2309..0c0f28e4fbd3 100644 --- a/util/gh-pages/index.html +++ b/util/gh-pages/index.html @@ -419,7 +419,7 @@ Otherwise, have a great day =^.^=
-
+
-
+
- -
From 79d1ac66a8317083bb801a5b09ed180dacc8f70c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 11 Jul 2024 21:59:28 -0400 Subject: [PATCH 109/734] Remove rustdoc tests which no longer parse --- src/tools/rustfmt/tests/source/type.rs | 2 -- src/tools/rustfmt/tests/target/negative-bounds.rs | 6 ------ src/tools/rustfmt/tests/target/type.rs | 2 -- 3 files changed, 10 deletions(-) diff --git a/src/tools/rustfmt/tests/source/type.rs b/src/tools/rustfmt/tests/source/type.rs index 61ef73a3cab1..7a232f85198a 100644 --- a/src/tools/rustfmt/tests/source/type.rs +++ b/src/tools/rustfmt/tests/source/type.rs @@ -146,8 +146,6 @@ trait T: ~ const Super {} const fn not_quite_const() -> i32 { ::CONST } -struct S(std::marker::PhantomData); - impl ~ const T {} fn apit(_: impl ~ const T) {} diff --git a/src/tools/rustfmt/tests/target/negative-bounds.rs b/src/tools/rustfmt/tests/target/negative-bounds.rs index 4fb35cccf668..9fcb86ef4a42 100644 --- a/src/tools/rustfmt/tests/target/negative-bounds.rs +++ b/src/tools/rustfmt/tests/target/negative-bounds.rs @@ -3,9 +3,3 @@ where i32: !Copy, { } - -fn maybe_const_negative() -where - i32: ~const !Copy, -{ -} diff --git a/src/tools/rustfmt/tests/target/type.rs b/src/tools/rustfmt/tests/target/type.rs index c789ecb055a7..325adb52f3f9 100644 --- a/src/tools/rustfmt/tests/target/type.rs +++ b/src/tools/rustfmt/tests/target/type.rs @@ -153,8 +153,6 @@ const fn not_quite_const() -> i32 { ::CONST } -struct S(std::marker::PhantomData); - impl ~const T {} fn apit(_: impl ~const T) {} From edeb0fcddc80f600f7854abf2b421f3f8c799240 Mon Sep 17 00:00:00 2001 From: Florian Bartels Date: Fri, 12 Jul 2024 11:12:01 +0200 Subject: [PATCH 110/734] Fix syntax errors in example code --- clippy_lints/src/casts/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 54f0c7c46871..e9f9084af073 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -658,11 +658,11 @@ declare_clippy_lint! { /// /// ### Example /// ```rust,ignore - /// let _: (0.0_f32 / 0.0) as u64; + /// let _ = (0.0_f32 / 0.0) as u64; /// ``` /// Use instead: /// ```rust,ignore - /// let _: = 0_u64; + /// let _ = 0_u64; /// ``` #[clippy::version = "1.66.0"] pub CAST_NAN_TO_INT, From 983b4c37203e841c1a362e1cf3a16ef388269499 Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Fri, 12 Jul 2024 17:23:08 +0800 Subject: [PATCH 111/734] [`unwrap_or_default`]: skip warning when calling inside of suggested method's implementation --- clippy_lints/src/methods/or_fun_call.rs | 23 ++++++++++++++++++----- tests/ui/or_fun_call.fixed | 12 ++++++++++++ tests/ui/or_fun_call.rs | 12 ++++++++++++ 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 583e04fb4b18..baa60454419b 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -70,18 +70,31 @@ pub(super) fn check<'tcx>( }; let receiver_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs(); - let has_suggested_method = receiver_ty.ty_adt_def().is_some_and(|adt_def| { + let Some(suggested_method_def_id) = receiver_ty.ty_adt_def().and_then(|adt_def| { cx.tcx .inherent_impls(adt_def.did()) .into_iter() .flatten() .flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg)) - .any(|assoc| { - assoc.fn_has_self_parameter + .find_map(|assoc| { + if assoc.fn_has_self_parameter && cx.tcx.fn_sig(assoc.def_id).skip_binder().inputs().skip_binder().len() == 1 + { + Some(assoc.def_id) + } else { + None + } }) - }); - if !has_suggested_method { + }) else { + return false; + }; + let in_sugg_method_implementation = { + matches!( + suggested_method_def_id.as_local(), + Some(local_def_id) if local_def_id == cx.tcx.hir().get_parent_item(receiver.hir_id).def_id + ) + }; + if in_sugg_method_implementation { return false; } diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index c76f7a81843b..350155929718 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -318,4 +318,16 @@ fn host_effect() { Add::::add(1, 1).add(i32::MIN); } +mod issue_10228 { + struct Entry; + + impl Entry { + fn or_insert(self, _default: i32) {} + fn or_default(self) { + // Don't lint, suggested code is an infinite recursion + self.or_insert(Default::default()) + } + } +} + fn main() {} diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 97cf496d3ac7..3dcf657d7435 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -318,4 +318,16 @@ fn host_effect() { Add::::add(1, 1).add(i32::MIN); } +mod issue_10228 { + struct Entry; + + impl Entry { + fn or_insert(self, _default: i32) {} + fn or_default(self) { + // Don't lint, suggested code is an infinite recursion + self.or_insert(Default::default()) + } + } +} + fn main() {} From fd16a0efeb3ae37960daeb9d5bd3600a1632c16f Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Thu, 27 Jun 2024 01:29:49 +0300 Subject: [PATCH 112/734] rustc_middle: derivative -> derive-where --- Cargo.lock | 13 ++++++++++++- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_middle/src/mir/query.rs | 13 ++++--------- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eba4eed3686b..66007b2b6fef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1057,6 +1057,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive-where" +version = "1.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", +] + [[package]] name = "derive_builder" version = "0.20.0" @@ -4348,7 +4359,7 @@ name = "rustc_middle" version = "0.0.0" dependencies = [ "bitflags 2.5.0", - "derivative", + "derive-where", "either", "field-offset", "gsgdt", diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 3dc592980fdb..30f26d563ad3 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -derivative = "2.2.0" +derive-where = "1.2.7" either = "1.5.0" field-offset = "0.3.5" gsgdt = "0.1.2" diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index cd8e28522ecf..acf4414c4d6f 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -2,6 +2,7 @@ use crate::mir; use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty, TyCtxt}; +use derive_where::derive_where; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::LocalDefId; @@ -224,13 +225,7 @@ rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16); /// See also `rustc_const_eval::borrow_check::constraints`. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] #[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)] -#[derive(derivative::Derivative)] -#[derivative( - PartialOrd, - Ord, - PartialOrd = "feature_allow_slow_enum", - Ord = "feature_allow_slow_enum" -)] +#[derive_where(PartialOrd, Ord)] pub enum ConstraintCategory<'tcx> { Return(ReturnConstraint), Yield, @@ -240,7 +235,7 @@ pub enum ConstraintCategory<'tcx> { Cast { /// Whether this is an unsizing cast and if yes, this contains the target type. /// Region variables are erased to ReErased. - #[derivative(PartialOrd = "ignore", Ord = "ignore")] + #[derive_where(skip)] unsize_to: Option>, }, @@ -250,7 +245,7 @@ pub enum ConstraintCategory<'tcx> { ClosureBounds, /// Contains the function type if available. - CallArgument(#[derivative(PartialOrd = "ignore", Ord = "ignore")] Option>), + CallArgument(#[derive_where(skip)] Option>), CopyBound, SizedBound, Assignment, From 35ba700d5e091f7f36e1961792c9582ca384d622 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Thu, 27 Jun 2024 01:39:48 +0300 Subject: [PATCH 113/734] rustc_span: derivative -> derive-where --- Cargo.lock | 2 +- compiler/rustc_span/Cargo.toml | 2 +- compiler/rustc_span/src/lib.rs | 9 +++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 66007b2b6fef..43010908fb01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4738,7 +4738,7 @@ dependencies = [ name = "rustc_span" version = "0.0.0" dependencies = [ - "derivative", + "derive-where", "indexmap", "itoa", "md-5", diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index 83a554fe31de..3fdfe77ead97 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -derivative = "2.2.0" +derive-where = "1.2.7" indexmap = { version = "2.0.0" } itoa = "1.0" md5 = { package = "md-5", version = "0.10.0" } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 266956d63d71..ba3ddab98429 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -38,6 +38,7 @@ // this crate without this line making `rustc_span` available. extern crate self as rustc_span; +use derive_where::derive_where; use rustc_data_structures::{outline, AtomicRef}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_serialize::opaque::{FileEncoder, MemDecoder}; @@ -467,18 +468,18 @@ impl FileName { /// `SpanData` is public because `Span` uses a thread-local interner and can't be /// sent to other threads, but some pieces of performance infra run in a separate thread. /// Using `Span` is generally preferred. -#[derive(Clone, Copy, Hash, PartialEq, Eq, derivative::Derivative)] -#[derivative(PartialOrd, Ord)] +#[derive(Clone, Copy, Hash, PartialEq, Eq)] +#[derive_where(PartialOrd, Ord)] pub struct SpanData { pub lo: BytePos, pub hi: BytePos, /// Information about where the macro came from, if this piece of /// code was created by a macro expansion. - #[derivative(PartialOrd = "ignore", Ord = "ignore")] + #[derive_where(skip)] // `SyntaxContext` does not implement `Ord`. // The other fields are enough to determine in-file order. pub ctxt: SyntaxContext, - #[derivative(PartialOrd = "ignore", Ord = "ignore")] + #[derive_where(skip)] // `LocalDefId` does not implement `Ord`. // The other fields are enough to determine in-file order. pub parent: Option, From 70a11c7ba9d486fdf429dc50770db2dbc37b9eed Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Thu, 27 Jun 2024 01:59:30 +0300 Subject: [PATCH 114/734] rustc_next_trait_solver: derivative -> derive-where --- Cargo.lock | 2 +- compiler/rustc_next_trait_solver/Cargo.toml | 2 +- .../rustc_next_trait_solver/src/coherence.rs | 7 +++--- .../src/solve/assembly/mod.rs | 4 ++-- .../src/solve/assembly/structural_traits.rs | 4 ++-- .../src/solve/eval_ctxt/mod.rs | 4 ++-- .../src/solve/inspect/build.rs | 22 +++++++------------ 7 files changed, 19 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 43010908fb01..e5b19ed5b557 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4488,7 +4488,7 @@ name = "rustc_next_trait_solver" version = "0.0.0" dependencies = [ "bitflags 2.5.0", - "derivative", + "derive-where", "rustc_ast_ir", "rustc_data_structures", "rustc_index", diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 07cd4ae68d9a..cb0730e86739 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -derivative = "2.2.0" +derive-where = "1.2.7" rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_index = { path = "../rustc_index", default-features = false } diff --git a/compiler/rustc_next_trait_solver/src/coherence.rs b/compiler/rustc_next_trait_solver/src/coherence.rs index 55f602d907bb..f22ea41c5122 100644 --- a/compiler/rustc_next_trait_solver/src/coherence.rs +++ b/compiler/rustc_next_trait_solver/src/coherence.rs @@ -1,6 +1,7 @@ use std::fmt::Debug; use std::ops::ControlFlow; +use derive_where::derive_where; use rustc_type_ir::inherent::*; use rustc_type_ir::visit::{TypeVisitable, TypeVisitableExt, TypeVisitor}; use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; @@ -108,15 +109,13 @@ impl From for IsFirstInputType { } } -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = "T: Debug"))] +#[derive_where(Debug; I: Interner, T: Debug)] pub enum OrphanCheckErr { NonLocalInputType(Vec<(I::Ty, IsFirstInputType)>), UncoveredTyParams(UncoveredTyParams), } -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = "T: Debug"))] +#[derive_where(Debug; I: Interner, T: Debug)] pub struct UncoveredTyParams { pub uncovered: T, pub local_ty: Option, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 01dde9ca587c..f74597fcb391 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -2,6 +2,7 @@ pub(super) mod structural_traits; +use derive_where::derive_where; use rustc_type_ir::elaborate; use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::inherent::*; @@ -21,8 +22,7 @@ use crate::solve::{ /// /// It consists of both the `source`, which describes how that goal would be proven, /// and the `result` when using the given `source`. -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""), Clone(bound = ""))] +#[derive_where(Clone, Debug; I: Interner)] pub(super) struct Candidate { pub(super) source: CandidateSource, pub(super) result: CanonicalResponse, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 7df14e81ab5d..770ac9a929ea 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -1,6 +1,7 @@ //! Code which is used by built-in goals that match "structurally", such a auto //! traits, `Copy`/`Clone`. +use derive_where::derive_where; use rustc_ast_ir::{Movability, Mutability}; use rustc_type_ir::data_structures::HashMap; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; @@ -384,8 +385,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable { pub tupled_inputs_ty: I::Ty, diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index c23bc8f09ad1..e328284c0010 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1,5 +1,6 @@ use std::ops::ControlFlow; +use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_type_ir::data_structures::ensure_sufficient_stack; @@ -87,8 +88,7 @@ where pub(super) inspect: ProofTreeBuilder, } -#[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Debug(bound = ""), Default(bound = ""))] +#[derive_where(Clone, Debug, Default; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] // FIXME: This can be made crate-private once `EvalCtxt` also lives in this crate. diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index 3e266ddac71f..36e13cc97d64 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -7,6 +7,7 @@ use std::marker::PhantomData; use std::mem; +use derive_where::derive_where; use rustc_type_ir::inherent::*; use rustc_type_ir::{self as ty, search_graph, Interner}; @@ -51,8 +52,7 @@ where /// in the code, only one or two variants are actually possible. /// /// We simply ICE in case that assumption is broken. -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""))] +#[derive_where(Debug; I: Interner)] enum DebugSolver { Root, GoalEvaluation(WipGoalEvaluation), @@ -78,8 +78,7 @@ impl From> for DebugSolver { } } -#[derive(derivative::Derivative)] -#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +#[derive_where(PartialEq, Eq, Debug; I: Interner)] struct WipGoalEvaluation { pub uncanonicalized_goal: Goal, pub orig_values: Vec, @@ -96,8 +95,7 @@ impl WipGoalEvaluation { } } -#[derive(derivative::Derivative)] -#[derivative(PartialEq(bound = ""), Eq(bound = ""))] +#[derive_where(PartialEq, Eq; I: Interner)] pub(in crate::solve) enum WipCanonicalGoalEvaluationKind { Overflow, CycleInStack, @@ -118,8 +116,7 @@ impl std::fmt::Debug for WipCanonicalGoalEvaluationKind { } } -#[derive(derivative::Derivative)] -#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +#[derive_where(PartialEq, Eq, Debug; I: Interner)] struct WipCanonicalGoalEvaluation { goal: CanonicalInput, kind: Option>, @@ -153,8 +150,7 @@ impl WipCanonicalGoalEvaluation { } } -#[derive(derivative::Derivative)] -#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +#[derive_where(PartialEq, Eq, Debug; I: Interner)] struct WipCanonicalGoalEvaluationStep { /// Unlike `EvalCtxt::var_values`, we append a new /// generic arg here whenever we create a new inference @@ -193,8 +189,7 @@ impl WipCanonicalGoalEvaluationStep { } } -#[derive(derivative::Derivative)] -#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +#[derive_where(PartialEq, Eq, Debug; I: Interner)] struct WipProbe { initial_num_var_values: usize, steps: Vec>, @@ -212,8 +207,7 @@ impl WipProbe { } } -#[derive(derivative::Derivative)] -#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +#[derive_where(PartialEq, Eq, Debug; I: Interner)] enum WipProbeStep { AddGoal(GoalSource, inspect::CanonicalState>), NestedProbe(WipProbe), From 168096f663c3268e462c7b9cbe4dd243eb1ded37 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Thu, 27 Jun 2024 14:55:44 +0300 Subject: [PATCH 115/734] rustc_type_ir: derivative -> derive-where --- Cargo.lock | 13 +- compiler/rustc_type_ir/Cargo.toml | 2 +- compiler/rustc_type_ir/src/binder.rs | 37 +++--- compiler/rustc_type_ir/src/canonical.rs | 39 ++---- compiler/rustc_type_ir/src/const_kind.rs | 13 +- compiler/rustc_type_ir/src/error.rs | 10 +- compiler/rustc_type_ir/src/generic_arg.rs | 19 +-- compiler/rustc_type_ir/src/opaque_ty.rs | 11 +- compiler/rustc_type_ir/src/outlives.rs | 4 +- compiler/rustc_type_ir/src/predicate.rs | 112 +++--------------- compiler/rustc_type_ir/src/predicate_kind.rs | 13 +- compiler/rustc_type_ir/src/region_kind.rs | 4 +- compiler/rustc_type_ir/src/relate.rs | 13 +- .../src/search_graph/global_cache.rs | 15 +-- .../rustc_type_ir/src/search_graph/mod.rs | 7 +- compiler/rustc_type_ir/src/solve/inspect.rs | 44 +++---- compiler/rustc_type_ir/src/solve/mod.rs | 84 +++---------- compiler/rustc_type_ir/src/ty_kind.rs | 36 ++---- compiler/rustc_type_ir/src/ty_kind/closure.rs | 51 +------- tests/ui/attributes/dump-preds.stderr | 2 +- .../occurs-check/associated-type.next.stderr | 8 +- .../occurs-check/associated-type.old.stderr | 16 +-- .../structually-relate-aliases.stderr | 4 +- .../issue-118950-root-region.stderr | 8 +- 24 files changed, 140 insertions(+), 425 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5b19ed5b557..3f3daa6e103b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1046,17 +1046,6 @@ dependencies = [ "powerfmt", ] -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "derive-where" version = "1.2.7" @@ -4878,7 +4867,7 @@ name = "rustc_type_ir" version = "0.0.0" dependencies = [ "bitflags 2.5.0", - "derivative", + "derive-where", "indexmap", "rustc_ast_ir", "rustc_data_structures", diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index e4bf6069caf3..e20a9e27bbe5 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -derivative = "2.2.0" +derive-where = "1.2.7" indexmap = "2.0.0" rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } rustc_data_structures = { path = "../rustc_data_structures", optional = true } diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 2531219baecc..20600fce4c39 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -3,6 +3,7 @@ use std::hash::Hash; use std::marker::PhantomData; use std::ops::{ControlFlow, Deref}; +use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; #[cfg(feature = "nightly")] @@ -25,15 +26,12 @@ use crate::{self as ty, Interner}; /// e.g., `liberate_late_bound_regions`). /// /// `Decodable` and `Encodable` are implemented for `Binder` using the `impl_binder_encode_decode!` macro. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = "T: Clone"), - Copy(bound = "T: Copy"), - Hash(bound = "T: Hash"), - PartialEq(bound = "T: PartialEq"), - Eq(bound = "T: Eq"), - Debug(bound = "T: Debug") -)] +#[derive_where(Clone; I: Interner, T: Clone)] +#[derive_where(Copy; I: Interner, T: Copy)] +#[derive_where(Hash; I: Interner, T: Hash)] +#[derive_where(PartialEq; I: Interner, T: PartialEq)] +#[derive_where(Eq; I: Interner, T: Eq)] +#[derive_where(Debug; I: Interner, T: Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub struct Binder { value: T, @@ -351,21 +349,18 @@ impl TypeVisitor for ValidateBoundVars { /// /// If you don't have anything to `instantiate`, you may be looking for /// [`instantiate_identity`](EarlyBinder::instantiate_identity) or [`skip_binder`](EarlyBinder::skip_binder). -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = "T: Clone"), - Copy(bound = "T: Copy"), - PartialEq(bound = "T: PartialEq"), - Eq(bound = "T: Eq"), - Ord(bound = "T: Ord"), - PartialOrd(bound = "T: Ord"), - Hash(bound = "T: Hash"), - Debug(bound = "T: Debug") -)] +#[derive_where(Clone; I: Interner, T: Clone)] +#[derive_where(Copy; I: Interner, T: Copy)] +#[derive_where(PartialEq; I: Interner, T: PartialEq)] +#[derive_where(Eq; I: Interner, T: Eq)] +#[derive_where(Ord; I: Interner, T: Ord)] +#[derive_where(PartialOrd; I: Interner, T: Ord)] +#[derive_where(Hash; I: Interner, T: Hash)] +#[derive_where(Debug; I: Interner, T: Debug)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub struct EarlyBinder { value: T, - #[derivative(Debug = "ignore")] + #[derive_where(skip(Debug))] _tcx: PhantomData, } diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 7b114f565f29..4e46a3a13aa5 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -1,3 +1,4 @@ +use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; @@ -11,15 +12,12 @@ use crate::{self as ty, Interner, UniverseIndex}; /// A "canonicalized" type `V` is one where all free inference /// variables have been rewritten to "canonical vars". These are /// numbered starting from 0 in order of first appearance. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = "V: Clone"), - Hash(bound = "V: Hash"), - PartialEq(bound = "V: PartialEq"), - Eq(bound = "V: Eq"), - Debug(bound = "V: fmt::Debug"), - Copy(bound = "V: Copy") -)] +#[derive_where(Clone; I: Interner, V: Clone)] +#[derive_where(Hash; I: Interner, V: Hash)] +#[derive_where(PartialEq; I: Interner, V: PartialEq)] +#[derive_where(Eq; I: Interner, V: Eq)] +#[derive_where(Debug; I: Interner, V: fmt::Debug)] +#[derive_where(Copy; I: Interner, V: Copy)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub struct Canonical { @@ -84,15 +82,7 @@ impl fmt::Display for Canonical { /// canonical value. This is sufficient information for code to create /// a copy of the canonical value in some other inference context, /// with fresh inference variables replacing the canonical values. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - Debug(bound = ""), - Eq(bound = ""), - PartialEq(bound = "") -)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct CanonicalVarInfo { @@ -149,8 +139,7 @@ impl CanonicalVarInfo { /// Describes the "kind" of the canonical variable. This is a "kind" /// in the type-theory sense of the term -- i.e., a "meta" type system /// that analyzes type-like values. -#[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Debug(bound = ""))] +#[derive_where(Clone, Copy, Hash, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub enum CanonicalVarKind { @@ -266,15 +255,7 @@ pub enum CanonicalTyVarKind { /// vectors with the original values that were replaced by canonical /// variables. You will need to supply it later to instantiate the /// canonicalized query response. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Hash(bound = ""), - Debug(bound = "") -)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] pub struct CanonicalVarValues { diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index f1683f5449f5..dab2d3bf695c 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -1,3 +1,4 @@ +use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; #[cfg(feature = "nightly")] @@ -10,8 +11,7 @@ use crate::{self as ty, DebruijnIndex, Interner}; use self::ConstKind::*; /// Represents a constant in Rust. -#[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))] +#[derive_where(Clone, Copy, Hash, Eq; I: Interner)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum ConstKind { /// A const generic parameter. @@ -79,14 +79,7 @@ impl fmt::Debug for ConstKind { } /// An unevaluated (potentially generic) constant used in the type-system. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = "") -)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct UnevaluatedConst { diff --git a/compiler/rustc_type_ir/src/error.rs b/compiler/rustc_type_ir/src/error.rs index 8b59e9a6f481..8a6d37b7d23f 100644 --- a/compiler/rustc_type_ir/src/error.rs +++ b/compiler/rustc_type_ir/src/error.rs @@ -1,3 +1,4 @@ +use derive_where::derive_where; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use crate::solve::NoSolution; @@ -21,14 +22,7 @@ impl ExpectedFound { } // Data structures used in type unification -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Debug(bound = "") -)] +#[derive_where(Clone, Copy, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic)] #[cfg_attr(feature = "nightly", rustc_pass_by_value)] pub enum TypeError { diff --git a/compiler/rustc_type_ir/src/generic_arg.rs b/compiler/rustc_type_ir/src/generic_arg.rs index b158f0f5eee9..008268c3bffa 100644 --- a/compiler/rustc_type_ir/src/generic_arg.rs +++ b/compiler/rustc_type_ir/src/generic_arg.rs @@ -1,16 +1,10 @@ +use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use crate::Interner; -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Debug(bound = ""), - Eq(bound = ""), - PartialEq(bound = "") -)] +#[derive_where(Clone, Copy, PartialEq, Eq, Debug; I: Interner)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub enum GenericArgKind { Lifetime(I::Region), @@ -18,14 +12,7 @@ pub enum GenericArgKind { Const(I::Const), } -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Debug(bound = ""), - Eq(bound = ""), - PartialEq(bound = "") -)] +#[derive_where(Clone, Copy, PartialEq, Eq, Debug; I: Interner)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub enum TermKind { Ty(I::Ty), diff --git a/compiler/rustc_type_ir/src/opaque_ty.rs b/compiler/rustc_type_ir/src/opaque_ty.rs index d8ed4770e2dc..8fcb9e508a2b 100644 --- a/compiler/rustc_type_ir/src/opaque_ty.rs +++ b/compiler/rustc_type_ir/src/opaque_ty.rs @@ -1,3 +1,4 @@ +use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; @@ -5,15 +6,7 @@ use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use crate::inherent::*; use crate::{self as ty, Interner}; -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Debug(bound = ""), - Copy(bound = "") -)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub struct OpaqueTypeKey { diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs index 10b6f3355d92..1dd37377085c 100644 --- a/compiler/rustc_type_ir/src/outlives.rs +++ b/compiler/rustc_type_ir/src/outlives.rs @@ -2,6 +2,7 @@ //! refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that //! RFC for reference. +use derive_where::derive_where; use smallvec::{smallvec, SmallVec}; use crate::data_structures::SsoHashSet; @@ -9,8 +10,7 @@ use crate::inherent::*; use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt as _, TypeVisitor}; use crate::{self as ty, Interner}; -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""))] +#[derive_where(Debug; I: Interner)] pub enum Component { Region(I::Region), Param(I::ParamTy), diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index e5bcbc67f946..93b6512acc50 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -1,6 +1,7 @@ use std::fmt; use std::hash::Hash; +use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; @@ -12,15 +13,12 @@ use crate::visit::TypeVisitableExt as _; use crate::{self as ty, Interner}; /// `A: 'region` -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = "A: Clone"), - Copy(bound = "A: Copy"), - Hash(bound = "A: Hash"), - PartialEq(bound = "A: PartialEq"), - Eq(bound = "A: Eq"), - Debug(bound = "A: fmt::Debug") -)] +#[derive_where(Clone; I: Interner, A: Clone)] +#[derive_where(Copy; I: Interner, A: Copy)] +#[derive_where(Hash; I: Interner, A: Hash)] +#[derive_where(PartialEq; I: Interner, A: PartialEq)] +#[derive_where(Eq; I: Interner, A: Eq)] +#[derive_where(Debug; I: Interner, A: fmt::Debug)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct OutlivesPredicate(pub A, pub I::Region); @@ -50,14 +48,7 @@ where /// /// Trait references also appear in object types like `Foo`, but in /// that case the `Self` parameter is absent from the generic parameters. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = "") -)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct TraitRef { @@ -122,14 +113,7 @@ impl ty::Binder> { } } -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = "") -)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct TraitPredicate { @@ -243,15 +227,7 @@ impl fmt::Display for PredicatePolarity { } } -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Debug(bound = "") -)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub enum ExistentialPredicate { @@ -298,14 +274,7 @@ impl ty::Binder> { /// ``` /// The generic parameters don't include the erased `Self`, only trait /// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above). -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = "") -)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct ExistentialTraitRef { @@ -351,14 +320,7 @@ impl ty::Binder> { } /// A `ProjectionPredicate` for an `ExistentialTraitRef`. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = "") -)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct ExistentialProjection { @@ -454,15 +416,7 @@ impl AliasTermKind { /// * For a projection, this would be `>::N<...>`. /// * For an inherent projection, this would be `Ty::N<...>`. /// * For an opaque type, there is no explicit syntax. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Debug(bound = "") -)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct AliasTerm { @@ -491,7 +445,7 @@ pub struct AliasTerm { pub def_id: I::DefId, /// This field exists to prevent the creation of `AliasTerm` without using [`AliasTerm::new_from_args`]. - #[derivative(Debug = "ignore")] + #[derive_where(skip(Debug))] _use_alias_term_new_instead: (), } @@ -633,14 +587,7 @@ impl From> for AliasTerm { /// equality between arbitrary types. Processing an instance of /// Form #2 eventually yields one of these `ProjectionPredicate` /// instances to normalize the LHS. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = "") -)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct ProjectionPredicate { @@ -708,14 +655,7 @@ impl fmt::Debug for ProjectionPredicate { /// Used by the new solver. Unlike a `ProjectionPredicate` this can only be /// proven by actually normalizing `alias`. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = "") -)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct NormalizesTo { @@ -750,15 +690,7 @@ impl fmt::Debug for NormalizesTo { /// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates /// whether the `a` type is the type that we should label as "expected" when /// presenting user diagnostics. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Debug(bound = "") -)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct SubtypePredicate { @@ -768,15 +700,7 @@ pub struct SubtypePredicate { } /// Encodes that we have to coerce *from* the `a` type to the `b` type. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Debug(bound = "") -)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct CoercePredicate { diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index b1d0f8d19b39..5b8b22244ba6 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -1,3 +1,4 @@ +use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; @@ -7,8 +8,7 @@ use crate::{self as ty, Interner}; /// A clause is something that can appear in where bounds or be inferred /// by implied bounds. -#[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))] +#[derive_where(Clone, Copy, Hash, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum ClauseKind { @@ -53,14 +53,7 @@ impl PartialEq for ClauseKind { } } -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = "") -)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum PredicateKind { diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index 7abcc370c886..d56700f52eb8 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -1,3 +1,4 @@ +use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; #[cfg(feature = "nightly")] @@ -124,8 +125,7 @@ rustc_index::newtype_index! { /// [1]: https://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/ /// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html -#[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))] +#[derive_where(Clone, Copy, Hash, Eq; I: Interner)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))] pub enum RegionKind { /// A region parameter; for example `'a` in `impl<'a> Trait for &'a ()`. diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 0439e7f857fe..745ee9d54d91 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -1,5 +1,6 @@ use std::iter; +use derive_where::derive_where; use rustc_ast_ir::Mutability; use tracing::{debug, instrument}; @@ -17,19 +18,11 @@ pub type RelateResult = Result>; /// a miscompilation or unsoundness. /// /// When in doubt, use `VarianceDiagInfo::default()` -#[derive(derivative::Derivative)] -#[derivative( - Copy(bound = ""), - Clone(bound = ""), - Debug(bound = ""), - Default(bound = ""), - PartialEq(bound = ""), - Eq(bound = "") -)] +#[derive_where(Clone, Copy, PartialEq, Eq, Debug, Default; I: Interner)] pub enum VarianceDiagInfo { /// No additional information - this is the default. /// We will not add any additional information to error messages. - #[derivative(Default)] + #[derive_where(default)] None, /// We switched our variance because a generic argument occurs inside /// the invariant generic argument of another type. diff --git a/compiler/rustc_type_ir/src/search_graph/global_cache.rs b/compiler/rustc_type_ir/src/search_graph/global_cache.rs index 5ccda931f9c5..be4f1069cd16 100644 --- a/compiler/rustc_type_ir/src/search_graph/global_cache.rs +++ b/compiler/rustc_type_ir/src/search_graph/global_cache.rs @@ -1,10 +1,10 @@ +use derive_where::derive_where; use rustc_index::IndexVec; use super::{AvailableDepth, Cx, StackDepth, StackEntry}; use crate::data_structures::{HashMap, HashSet}; -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""), Clone(bound = ""), Copy(bound = ""))] +#[derive_where(Debug, Clone, Copy; X: Cx)] struct QueryData { result: X::Result, proof_tree: X::ProofTree, @@ -20,8 +20,7 @@ struct Success { /// This contains results whose computation never hit the /// recursion limit in `success`, and all results which hit /// the recursion limit in `with_overflow`. -#[derive(derivative::Derivative)] -#[derivative(Default(bound = ""))] +#[derive_where(Default; X: Cx)] struct CacheEntry { success: Option>, /// We have to be careful when caching roots of cycles. @@ -32,8 +31,7 @@ struct CacheEntry { with_overflow: HashMap>>, } -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""))] +#[derive_where(Debug; X: Cx)] pub(super) struct CacheData<'a, X: Cx> { pub(super) result: X::Result, pub(super) proof_tree: X::ProofTree, @@ -41,11 +39,10 @@ pub(super) struct CacheData<'a, X: Cx> { pub(super) encountered_overflow: bool, // FIXME: This is currently unused, but impacts the design // by requiring a closure for `Cx::with_global_cache`. + #[allow(dead_code)] pub(super) nested_goals: &'a HashSet, } - -#[derive(derivative::Derivative)] -#[derivative(Default(bound = ""))] +#[derive_where(Default; X: Cx)] pub struct GlobalCache { map: HashMap>, } diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index c2204becdfd7..4abf99b1ded8 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -3,6 +3,7 @@ use std::hash::Hash; use std::marker::PhantomData; use std::mem; +use derive_where::derive_where; use rustc_index::{Idx, IndexVec}; use tracing::debug; @@ -153,8 +154,7 @@ rustc_index::newtype_index! { pub struct StackDepth {} } -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""))] +#[derive_where(Debug; X: Cx)] struct StackEntry { input: X::Input, @@ -226,8 +226,7 @@ struct DetachedEntry { /// /// The provisional cache can theoretically result in changes to the observable behavior, /// see tests/ui/traits/next-solver/cycles/provisional-cache-impacts-behavior.rs. -#[derive(derivative::Derivative)] -#[derivative(Default(bound = ""))] +#[derive_where(Default; X: Cx)] struct ProvisionalCacheEntry { stack_depth: Option, with_inductive_stack: Option>, diff --git a/compiler/rustc_type_ir/src/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs index 0733c730064b..e25df7a0f604 100644 --- a/compiler/rustc_type_ir/src/solve/inspect.rs +++ b/compiler/rustc_type_ir/src/solve/inspect.rs @@ -21,6 +21,7 @@ use crate::solve::{ CandidateSource, CanonicalInput, Certainty, Goal, GoalSource, QueryInput, QueryResult, }; use crate::{Canonical, CanonicalVarValues, Interner}; +use derive_where::derive_where; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use std::fmt::Debug; use std::hash::Hash; @@ -31,15 +32,12 @@ use std::hash::Hash; /// This is only ever used as [CanonicalState]. Any type information in proof /// trees used mechanically has to be canonicalized as we otherwise leak /// inference variables from a nested `InferCtxt`. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = "T: Clone"), - Copy(bound = "T: Copy"), - PartialEq(bound = "T: PartialEq"), - Eq(bound = "T: Eq"), - Hash(bound = "T: Hash"), - Debug(bound = "T: Debug") -)] +#[derive_where(Clone; I: Interner, T: Clone)] +#[derive_where(Copy; I: Interner, T: Copy)] +#[derive_where(PartialEq; I: Interner, T: PartialEq)] +#[derive_where(Eq; I: Interner, T: Eq)] +#[derive_where(Hash; I: Interner, T: Hash)] +#[derive_where(Debug; I: Interner, T: Debug)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] pub struct State { pub var_values: CanonicalVarValues, @@ -52,24 +50,21 @@ pub type CanonicalState = Canonical>; /// for the `CanonicalVarValues` of the canonicalized goal. /// We use this to map any [CanonicalState] from the local `InferCtxt` /// of the solver query to the `InferCtxt` of the caller. -#[derive(derivative::Derivative)] -#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""))] +#[derive_where(PartialEq, Eq, Hash; I: Interner)] pub struct GoalEvaluation { pub uncanonicalized_goal: Goal, pub orig_values: Vec, pub evaluation: CanonicalGoalEvaluation, } -#[derive(derivative::Derivative)] -#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))] +#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)] pub struct CanonicalGoalEvaluation { pub goal: CanonicalInput, pub kind: CanonicalGoalEvaluationKind, pub result: QueryResult, } -#[derive(derivative::Derivative)] -#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))] +#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)] pub enum CanonicalGoalEvaluationKind { Overflow, CycleInStack, @@ -77,8 +72,7 @@ pub enum CanonicalGoalEvaluationKind { Evaluation { final_revision: I::CanonicalGoalEvaluationStepRef }, } -#[derive(derivative::Derivative)] -#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))] +#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)] pub struct CanonicalGoalEvaluationStep { pub instantiated_goal: QueryInput, @@ -89,8 +83,7 @@ pub struct CanonicalGoalEvaluationStep { /// A self-contained computation during trait solving. This either /// corresponds to a `EvalCtxt::probe(_X)` call or the root evaluation /// of a goal. -#[derive(derivative::Derivative)] -#[derivative(Debug(bound = ""), PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""))] +#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)] pub struct Probe { /// What happened inside of this probe in chronological order. pub steps: Vec>, @@ -98,8 +91,7 @@ pub struct Probe { pub final_state: CanonicalState, } -#[derive(derivative::Derivative)] -#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))] +#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)] pub enum ProbeStep { /// We added a goal to the `EvalCtxt` which will get proven /// the next time `EvalCtxt::try_evaluate_added_goals` is called. @@ -121,15 +113,7 @@ pub enum ProbeStep { /// What kind of probe we're in. In case the probe represents a candidate, or /// the final result of the current goal - via [ProbeKind::Root] - we also /// store the [QueryResult]. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Hash(bound = ""), - Debug(bound = "") -)] +#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] pub enum ProbeKind { /// The root inference context while proving a goal. diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 7934f996f0bd..7ac13755f5ff 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -3,6 +3,7 @@ pub mod inspect; use std::fmt; use std::hash::Hash; +use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; @@ -89,15 +90,12 @@ pub struct NoSolution; /// /// Most of the time the `param_env` contains the `where`-bounds of the function /// we're currently typechecking while the `predicate` is some trait bound. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = "P: Clone"), - Copy(bound = "P: Copy"), - Hash(bound = "P: Hash"), - PartialEq(bound = "P: PartialEq"), - Eq(bound = "P: Eq"), - Debug(bound = "P: fmt::Debug") -)] +#[derive_where(Clone; I: Interner, P: Clone)] +#[derive_where(Copy; I: Interner, P: Copy)] +#[derive_where(Hash; I: Interner, P: Hash)] +#[derive_where(PartialEq; I: Interner, P: PartialEq)] +#[derive_where(Eq; I: Interner, P: Eq)] +#[derive_where(Debug; I: Interner, P: fmt::Debug)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct Goal { @@ -140,15 +138,12 @@ pub enum GoalSource { InstantiateHigherRanked, } -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = "Goal: Clone"), - Copy(bound = "Goal: Copy"), - Hash(bound = "Goal: Hash"), - PartialEq(bound = "Goal: PartialEq"), - Eq(bound = "Goal: Eq"), - Debug(bound = "Goal: fmt::Debug") -)] +#[derive_where(Clone; I: Interner, Goal: Clone)] +#[derive_where(Copy; I: Interner, Goal: Copy)] +#[derive_where(Hash; I: Interner, Goal: Hash)] +#[derive_where(PartialEq; I: Interner, Goal: PartialEq)] +#[derive_where(Eq; I: Interner, Goal: Eq)] +#[derive_where(Debug; I: Interner, Goal: fmt::Debug)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct QueryInput { @@ -157,15 +152,7 @@ pub struct QueryInput { } /// Opaques that are defined in the inference context before a query is called. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Debug(bound = ""), - Default(bound = "") -)] +#[derive_where(Clone, Hash, PartialEq, Eq, Debug, Default; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct PredefinedOpaquesData { @@ -173,15 +160,7 @@ pub struct PredefinedOpaquesData { } /// Possible ways the given goal can be proven. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Debug(bound = "") -)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] pub enum CandidateSource { /// A user written impl. /// @@ -265,15 +244,7 @@ pub enum BuiltinImplSource { TupleUnsizing, } -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Debug(bound = "") -)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub struct Response { @@ -284,15 +255,7 @@ pub struct Response { } /// Additional constraints returned on success. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Debug(bound = ""), - Default(bound = "") -)] +#[derive_where(Clone, Hash, PartialEq, Eq, Debug, Default; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub struct ExternalConstraintsData { @@ -301,15 +264,7 @@ pub struct ExternalConstraintsData { pub normalization_nested_goals: NestedNormalizationGoals, } -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Debug(bound = ""), - Default(bound = "") -)] +#[derive_where(Clone, Hash, PartialEq, Eq, Debug, Default; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub struct NestedNormalizationGoals(pub Vec<(GoalSource, Goal)>); @@ -386,8 +341,7 @@ impl MaybeCause { } } -#[derive(derivative::Derivative)] -#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +#[derive_where(PartialEq, Eq, Debug; I: Interner)] pub struct CacheData { pub result: QueryResult, pub proof_tree: Option, diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 4ffebef9f1f9..29993a50aeea 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -1,3 +1,5 @@ +use derive_where::derive_where; + #[cfg(feature = "nightly")] use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; #[cfg(feature = "nightly")] @@ -64,8 +66,7 @@ impl AliasTyKind { /// Types written by the user start out as `hir::TyKind` and get /// converted to this representation using `::lower_ty`. #[cfg_attr(feature = "nightly", rustc_diagnostic_item = "IrTyKind")] -#[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))] +#[derive_where(Clone, Copy, Hash, Eq; I: Interner)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum TyKind { /// The primitive boolean type. Written as `bool`. @@ -416,15 +417,7 @@ impl fmt::Debug for TyKind { /// * For a projection, this would be `>::N<...>`. /// * For an inherent projection, this would be `Ty::N<...>`. /// * For an opaque type, there is no explicit syntax. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Debug(bound = "") -)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct AliasTy { @@ -453,7 +446,7 @@ pub struct AliasTy { pub def_id: I::DefId, /// This field exists to prevent the creation of `AliasTy` without using [`AliasTy::new_from_args`]. - #[derivative(Debug = "ignore")] + #[derive_where(skip(Debug))] pub(crate) _use_alias_ty_new_instead: (), } @@ -944,15 +937,7 @@ impl fmt::Debug for InferTy { } } -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Hash(bound = ""), - Debug(bound = "") -)] +#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] pub struct TypeAndMut { @@ -960,14 +945,7 @@ pub struct TypeAndMut { pub mutbl: Mutability, } -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Hash(bound = "") -)] +#[derive_where(Clone, Copy, PartialEq, Eq, Hash; I: Interner)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] pub struct FnSig { diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs index 24a7c0c67e90..36f02704de95 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -1,5 +1,6 @@ use std::ops::ControlFlow; +use derive_where::derive_where; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use crate::fold::{shift_region, TypeFoldable, TypeFolder, TypeSuperFoldable}; @@ -100,15 +101,7 @@ use crate::{self as ty, Interner}; /// * `GR`: The "return type", which is the type of value returned upon /// completion of the coroutine. /// * `GW`: The "coroutine witness". -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Debug(bound = "") -)] +#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] pub struct ClosureArgs { /// Lifetime and type parameters from the enclosing function, @@ -210,15 +203,7 @@ impl ClosureArgs { } } -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Debug(bound = "") -)] +#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] pub struct CoroutineClosureArgs { pub args: I::GenericArgs, @@ -370,15 +355,7 @@ impl TypeVisitor for HasRegionsBoundAt { } } -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Debug(bound = "") -)] +#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] pub struct CoroutineClosureSignature { pub interior: I::Ty, @@ -552,15 +529,7 @@ impl TypeFolder for FoldEscapingRegions { } } -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Debug(bound = "") -)] +#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] pub struct GenSig { pub resume_ty: I::Ty, @@ -569,15 +538,7 @@ pub struct GenSig { } /// Similar to `ClosureArgs`; see the above documentation for more. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - Hash(bound = ""), - PartialEq(bound = ""), - Eq(bound = ""), - Debug(bound = "") -)] +#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] pub struct CoroutineArgs { pub args: I::GenericArgs, diff --git a/tests/ui/attributes/dump-preds.stderr b/tests/ui/attributes/dump-preds.stderr index 26834376e761..bdfcbed71e9a 100644 --- a/tests/ui/attributes/dump-preds.stderr +++ b/tests/ui/attributes/dump-preds.stderr @@ -31,7 +31,7 @@ error: rustc_dump_item_bounds LL | type Assoc: std::ops::Deref | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: Binder { value: ProjectionPredicate(AliasTerm { args: [Alias(Projection, AliasTy { args: [Self/#0, T/#1, P/#2], def_id: DefId(..) })], def_id: DefId(..) }, Term::Ty(())), bound_vars: [] } + = note: Binder { value: ProjectionPredicate(AliasTerm { args: [Alias(Projection, AliasTy { args: [Self/#0, T/#1, P/#2], def_id: DefId(..), .. })], def_id: DefId(..), .. }, Term::Ty(())), bound_vars: [] } = note: Binder { value: TraitPredicate(<>::Assoc

as std::ops::Deref>, polarity:Positive), bound_vars: [] } = note: Binder { value: TraitPredicate(<>::Assoc

as std::marker::Sized>, polarity:Positive), bound_vars: [] } diff --git a/tests/ui/coherence/occurs-check/associated-type.next.stderr b/tests/ui/coherence/occurs-check/associated-type.next.stderr index 4f15be4c7c88..9544bdbb468d 100644 --- a/tests/ui/coherence/occurs-check/associated-type.next.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.next.stderr @@ -1,7 +1,7 @@ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } error[E0119]: conflicting implementations of trait `Overlap fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` --> $DIR/associated-type.rs:31:1 | diff --git a/tests/ui/coherence/occurs-check/associated-type.old.stderr b/tests/ui/coherence/occurs-check/associated-type.old.stderr index 329086ab7dfd..ccc7f30fa6fd 100644 --- a/tests/ui/coherence/occurs-check/associated-type.old.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.old.stderr @@ -1,11 +1,11 @@ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. } error[E0119]: conflicting implementations of trait `Overlap fn(&'a (), _)>` for type `for<'a> fn(&'a (), _)` --> $DIR/associated-type.rs:31:1 | diff --git a/tests/ui/higher-ranked/structually-relate-aliases.stderr b/tests/ui/higher-ranked/structually-relate-aliases.stderr index 2f1dfd19c483..7de30efae1cd 100644 --- a/tests/ui/higher-ranked/structually-relate-aliases.stderr +++ b/tests/ui/higher-ranked/structually-relate-aliases.stderr @@ -1,5 +1,5 @@ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, !2_0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, !2_0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), .. } error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied --> $DIR/structually-relate-aliases.rs:13:36 | diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr index 17da1f524796..d14b9d217da2 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr +++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr @@ -25,10 +25,10 @@ help: this trait has no implementations, consider adding one LL | trait ToUnit<'a> { | ^^^^^^^^^^^^^^^^ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), .. } error[E0119]: conflicting implementations of trait `Overlap` for type `fn(_)` --> $DIR/issue-118950-root-region.rs:19:1 | From 17c4e4a923d8a5db4a67bd42e18f8116eee78dfd Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Thu, 27 Jun 2024 14:56:27 +0300 Subject: [PATCH 116/734] derivative -> derive-where --- src/tools/tidy/src/deps.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 3c72fae0881e..0e51441bf3f5 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -254,7 +254,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "darling_macro", "datafrog", "deranged", - "derivative", + "derive-where", "derive_more", "derive_setters", "digest", From 59f88d3db92cddc209b15a4edf26216f5ec9daaa Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Wed, 10 Jul 2024 01:25:57 +0300 Subject: [PATCH 117/734] Silence clippy::derived_hash_with_manual_eq for now --- compiler/rustc_type_ir/src/canonical.rs | 3 +++ compiler/rustc_type_ir/src/const_kind.rs | 3 +++ compiler/rustc_type_ir/src/predicate_kind.rs | 3 +++ compiler/rustc_type_ir/src/region_kind.rs | 3 +++ compiler/rustc_type_ir/src/ty_kind.rs | 3 +++ 5 files changed, 15 insertions(+) diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 4e46a3a13aa5..f02ada152a44 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -1,3 +1,5 @@ +#![allow(clippy::derived_hash_with_manual_eq)] + use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; @@ -167,6 +169,7 @@ pub enum CanonicalVarKind { PlaceholderConst(I::PlaceholderConst), } +// FIXME(GrigorenkoPV): consider not implementing PartialEq manually impl PartialEq for CanonicalVarKind { fn eq(&self, other: &Self) -> bool { match (self, other) { diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index dab2d3bf695c..685bb5f9a8bf 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -1,3 +1,5 @@ +#![allow(clippy::derived_hash_with_manual_eq)] + use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -43,6 +45,7 @@ pub enum ConstKind { Expr(I::ExprConst), } +// FIXME(GrigorenkoPV): consider not implementing PartialEq manually impl PartialEq for ConstKind { fn eq(&self, other: &Self) -> bool { match (self, other) { diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index 5b8b22244ba6..70b7c29bdfcc 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -1,3 +1,5 @@ +#![allow(clippy::derived_hash_with_manual_eq)] + use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable}; @@ -38,6 +40,7 @@ pub enum ClauseKind { ConstEvaluatable(I::Const), } +// FIXME(GrigorenkoPV): consider not implementing PartialEq manually impl PartialEq for ClauseKind { fn eq(&self, other: &Self) -> bool { match (self, other) { diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index d56700f52eb8..61ac83fcc98c 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -1,3 +1,5 @@ +#![allow(clippy::derived_hash_with_manual_eq)] + use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -193,6 +195,7 @@ const fn regionkind_discriminant(value: &RegionKind) -> usize { } } +// FIXME(GrigorenkoPV): consider not implementing PartialEq manually // This is manually implemented because a derive would require `I: PartialEq` impl PartialEq for RegionKind { #[inline] diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 29993a50aeea..db883511d75a 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -1,3 +1,5 @@ +#![allow(clippy::derived_hash_with_manual_eq)] + use derive_where::derive_where; #[cfg(feature = "nightly")] @@ -293,6 +295,7 @@ const fn tykind_discriminant(value: &TyKind) -> usize { } } +// FIXME(GrigorenkoPV): consider not implementing PartialEq manually // This is manually implemented because a derive would require `I: PartialEq` impl PartialEq for TyKind { #[inline] From cf09cba20c317c1d2cfa78820a699ac5ee684bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 12 Jul 2024 18:52:52 +0000 Subject: [PATCH 118/734] When finding item gated behind a `cfg` flat, point at it Previously we would only mention that the item was gated out, and opportunisitically mention the feature flag name when possible. We now point to the place where the item was gated, which can be behind layers of macro indirection, or in different modules. ``` error[E0433]: failed to resolve: could not find `doesnt_exist` in `inner` --> $DIR/diagnostics-cross-crate.rs:18:23 | LL | cfged_out::inner::doesnt_exist::hello(); | ^^^^^^^^^^^^ could not find `doesnt_exist` in `inner` | note: found an item that was configured out --> $DIR/auxiliary/cfged_out.rs:6:13 | LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ note: the item is gated here --> $DIR/auxiliary/cfged_out.rs:5:5 | LL | #[cfg(FALSE)] | ^^^^^^^^^^^^^ ``` --- compiler/rustc_resolve/messages.ftl | 2 + compiler/rustc_resolve/src/diagnostics.rs | 8 +++- compiler/rustc_resolve/src/errors.rs | 9 ++++ tests/ui/cfg/diagnostics-cross-crate.rs | 3 ++ tests/ui/cfg/diagnostics-cross-crate.stderr | 27 +++++++++-- tests/ui/cfg/diagnostics-reexport.rs | 8 ++-- tests/ui/cfg/diagnostics-reexport.stderr | 20 ++++++++ tests/ui/cfg/diagnostics-same-crate.rs | 9 ++-- tests/ui/cfg/diagnostics-same-crate.stderr | 48 ++++++++++++++----- tests/ui/macros/builtin-std-paths-fail.stderr | 2 + tests/ui/macros/macro-outer-attributes.stderr | 11 +++++ 11 files changed, 122 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 4b9c36ad39fb..73d1a2ea49a1 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -232,6 +232,8 @@ resolve_is_private = resolve_item_was_behind_feature = the item is gated behind the `{$feature}` feature +resolve_item_was_cfg_out = the item is gated here + resolve_items_in_traits_are_not_importable = items in traits are not importable diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 09221041031a..3ce500866bde 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2530,7 +2530,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { && let NestedMetaItem::MetaItem(meta_item) = &nested[0] && let MetaItemKind::NameValue(feature_name) = &meta_item.kind { - let note = errors::ItemWasBehindFeature { feature: feature_name.symbol }; + let note = errors::ItemWasBehindFeature { + feature: feature_name.symbol, + span: meta_item.span, + }; + err.subdiagnostic(note); + } else { + let note = errors::ItemWasCfgOut { span: cfg.span }; err.subdiagnostic(note); } } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 097f4af05c30..0a68231c6fee 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1228,6 +1228,15 @@ pub(crate) struct FoundItemConfigureOut { #[note(resolve_item_was_behind_feature)] pub(crate) struct ItemWasBehindFeature { pub(crate) feature: Symbol, + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Subdiagnostic)] +#[note(resolve_item_was_cfg_out)] +pub(crate) struct ItemWasCfgOut { + #[primary_span] + pub(crate) span: Span, } #[derive(Diagnostic)] diff --git a/tests/ui/cfg/diagnostics-cross-crate.rs b/tests/ui/cfg/diagnostics-cross-crate.rs index 77dd91d6c282..00ac7e2fd080 100644 --- a/tests/ui/cfg/diagnostics-cross-crate.rs +++ b/tests/ui/cfg/diagnostics-cross-crate.rs @@ -11,12 +11,14 @@ fn main() { cfged_out::inner::uwu(); //~ ERROR cannot find function //~^ NOTE found an item that was configured out //~| NOTE not found in `cfged_out::inner` + //~| NOTE the item is gated here // The module isn't found - we would like to get a diagnostic, but currently don't due to // the awkward way the resolver diagnostics are currently implemented. cfged_out::inner::doesnt_exist::hello(); //~ ERROR failed to resolve //~^ NOTE could not find `doesnt_exist` in `inner` //~| NOTE found an item that was configured out + //~| NOTE the item is gated here // It should find the one in the right module, not the wrong one. cfged_out::inner::right::meow(); //~ ERROR cannot find function @@ -28,4 +30,5 @@ fn main() { cfged_out::vanished(); //~ ERROR cannot find function //~^ NOTE found an item that was configured out //~| NOTE not found in `cfged_out` + //~| NOTE the item is gated here } diff --git a/tests/ui/cfg/diagnostics-cross-crate.stderr b/tests/ui/cfg/diagnostics-cross-crate.stderr index 8a238f364044..07ad4e3272d1 100644 --- a/tests/ui/cfg/diagnostics-cross-crate.stderr +++ b/tests/ui/cfg/diagnostics-cross-crate.stderr @@ -1,5 +1,5 @@ error[E0433]: failed to resolve: could not find `doesnt_exist` in `inner` - --> $DIR/diagnostics-cross-crate.rs:17:23 + --> $DIR/diagnostics-cross-crate.rs:18:23 | LL | cfged_out::inner::doesnt_exist::hello(); | ^^^^^^^^^^^^ could not find `doesnt_exist` in `inner` @@ -9,6 +9,11 @@ note: found an item that was configured out | LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ +note: the item is gated here + --> $DIR/auxiliary/cfged_out.rs:5:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ error[E0425]: cannot find function `uwu` in crate `cfged_out` --> $DIR/diagnostics-cross-crate.rs:7:16 @@ -27,9 +32,14 @@ note: found an item that was configured out | LL | pub fn uwu() {} | ^^^ +note: the item is gated here + --> $DIR/auxiliary/cfged_out.rs:2:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ error[E0425]: cannot find function `meow` in module `cfged_out::inner::right` - --> $DIR/diagnostics-cross-crate.rs:22:30 + --> $DIR/diagnostics-cross-crate.rs:24:30 | LL | cfged_out::inner::right::meow(); | ^^^^ not found in `cfged_out::inner::right` @@ -39,10 +49,14 @@ note: found an item that was configured out | LL | pub fn meow() {} | ^^^^ - = note: the item is gated behind the `what-a-cool-feature` feature +note: the item is gated behind the `what-a-cool-feature` feature + --> $DIR/auxiliary/cfged_out.rs:16:15 + | +LL | #[cfg(feature = "what-a-cool-feature")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `vanished` in crate `cfged_out` - --> $DIR/diagnostics-cross-crate.rs:28:16 + --> $DIR/diagnostics-cross-crate.rs:30:16 | LL | cfged_out::vanished(); | ^^^^^^^^ not found in `cfged_out` @@ -52,6 +66,11 @@ note: found an item that was configured out | LL | pub fn vanished() {} | ^^^^^^^^ +note: the item is gated here + --> $DIR/auxiliary/cfged_out.rs:21:1 + | +LL | #[cfg(i_dont_exist_and_you_can_do_nothing_about_it)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/cfg/diagnostics-reexport.rs b/tests/ui/cfg/diagnostics-reexport.rs index 9b3208cb87cf..9ae7d931fcb8 100644 --- a/tests/ui/cfg/diagnostics-reexport.rs +++ b/tests/ui/cfg/diagnostics-reexport.rs @@ -4,7 +4,7 @@ pub mod inner { pub fn uwu() {} } - #[cfg(FALSE)] + #[cfg(FALSE)] //~ NOTE the item is gated here pub use super::uwu; //~^ NOTE found an item that was configured out } @@ -14,7 +14,7 @@ pub use a::x; //~| NOTE no `x` in `a` mod a { - #[cfg(FALSE)] + #[cfg(FALSE)] //~ NOTE the item is gated here pub fn x() {} //~^ NOTE found an item that was configured out } @@ -25,10 +25,10 @@ pub use b::{x, y}; //~| NOTE no `y` in `b` mod b { - #[cfg(FALSE)] + #[cfg(FALSE)] //~ NOTE the item is gated here pub fn x() {} //~^ NOTE found an item that was configured out - #[cfg(FALSE)] + #[cfg(FALSE)] //~ NOTE the item is gated here pub fn y() {} //~^ NOTE found an item that was configured out } diff --git a/tests/ui/cfg/diagnostics-reexport.stderr b/tests/ui/cfg/diagnostics-reexport.stderr index e25b7cf86e21..737202fdf9ad 100644 --- a/tests/ui/cfg/diagnostics-reexport.stderr +++ b/tests/ui/cfg/diagnostics-reexport.stderr @@ -9,6 +9,11 @@ note: found an item that was configured out | LL | pub fn x() {} | ^ +note: the item is gated here + --> $DIR/diagnostics-reexport.rs:17:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ error[E0432]: unresolved imports `b::x`, `b::y` --> $DIR/diagnostics-reexport.rs:22:13 @@ -23,11 +28,21 @@ note: found an item that was configured out | LL | pub fn x() {} | ^ +note: the item is gated here + --> $DIR/diagnostics-reexport.rs:28:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ note: found an item that was configured out --> $DIR/diagnostics-reexport.rs:32:12 | LL | pub fn y() {} | ^ +note: the item is gated here + --> $DIR/diagnostics-reexport.rs:31:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ error[E0425]: cannot find function `uwu` in module `inner` --> $DIR/diagnostics-reexport.rs:38:12 @@ -40,6 +55,11 @@ note: found an item that was configured out | LL | pub use super::uwu; | ^^^ +note: the item is gated here + --> $DIR/diagnostics-reexport.rs:7:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/cfg/diagnostics-same-crate.rs b/tests/ui/cfg/diagnostics-same-crate.rs index b2a0fb58dd6b..d6f8dd21a922 100644 --- a/tests/ui/cfg/diagnostics-same-crate.rs +++ b/tests/ui/cfg/diagnostics-same-crate.rs @@ -1,11 +1,13 @@ #![allow(unexpected_cfgs)] // since we want to recognize them as unexpected pub mod inner { - #[cfg(FALSE)] + #[cfg(FALSE)] //~ NOTE the item is gated here pub fn uwu() {} //~^ NOTE found an item that was configured out - #[cfg(FALSE)] + #[cfg(FALSE)] //~ NOTE the item is gated here + //~^ NOTE the item is gated here + //~| NOTE the item is gated here pub mod doesnt_exist { //~^ NOTE found an item that was configured out //~| NOTE found an item that was configured out @@ -20,7 +22,7 @@ pub mod inner { } pub mod right { - #[cfg(feature = "what-a-cool-feature")] + #[cfg(feature = "what-a-cool-feature")] //~ NOTE the item is gated behind the `what-a-cool-feature` feature pub fn meow() {} //~^ NOTE found an item that was configured out } @@ -55,7 +57,6 @@ fn main() { // It should find the one in the right module, not the wrong one. inner::right::meow(); //~ ERROR cannot find function //~| NOTE not found in `inner::right - //~| NOTE the item is gated behind the `what-a-cool-feature` feature // Exists in the crate root - we would generally want a diagnostic, // but currently don't have one. diff --git a/tests/ui/cfg/diagnostics-same-crate.stderr b/tests/ui/cfg/diagnostics-same-crate.stderr index 86421736b8c6..dd0d10c6567e 100644 --- a/tests/ui/cfg/diagnostics-same-crate.stderr +++ b/tests/ui/cfg/diagnostics-same-crate.stderr @@ -1,41 +1,56 @@ error[E0432]: unresolved import `super::inner::doesnt_exist` - --> $DIR/diagnostics-same-crate.rs:30:9 + --> $DIR/diagnostics-same-crate.rs:32:9 | LL | use super::inner::doesnt_exist; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ no `doesnt_exist` in `inner` | note: found an item that was configured out - --> $DIR/diagnostics-same-crate.rs:9:13 + --> $DIR/diagnostics-same-crate.rs:11:13 | LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ +note: the item is gated here + --> $DIR/diagnostics-same-crate.rs:8:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ error[E0432]: unresolved import `super::inner::doesnt_exist` - --> $DIR/diagnostics-same-crate.rs:33:23 + --> $DIR/diagnostics-same-crate.rs:35:23 | LL | use super::inner::doesnt_exist::hi; | ^^^^^^^^^^^^ could not find `doesnt_exist` in `inner` | note: found an item that was configured out - --> $DIR/diagnostics-same-crate.rs:9:13 + --> $DIR/diagnostics-same-crate.rs:11:13 | LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ +note: the item is gated here + --> $DIR/diagnostics-same-crate.rs:8:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ error[E0433]: failed to resolve: could not find `doesnt_exist` in `inner` - --> $DIR/diagnostics-same-crate.rs:52:12 + --> $DIR/diagnostics-same-crate.rs:54:12 | LL | inner::doesnt_exist::hello(); | ^^^^^^^^^^^^ could not find `doesnt_exist` in `inner` | note: found an item that was configured out - --> $DIR/diagnostics-same-crate.rs:9:13 + --> $DIR/diagnostics-same-crate.rs:11:13 | LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ +note: the item is gated here + --> $DIR/diagnostics-same-crate.rs:8:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ error[E0425]: cannot find function `uwu` in module `inner` - --> $DIR/diagnostics-same-crate.rs:47:12 + --> $DIR/diagnostics-same-crate.rs:49:12 | LL | inner::uwu(); | ^^^ not found in `inner` @@ -45,28 +60,37 @@ note: found an item that was configured out | LL | pub fn uwu() {} | ^^^ +note: the item is gated here + --> $DIR/diagnostics-same-crate.rs:4:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ error[E0425]: cannot find function `meow` in module `inner::right` - --> $DIR/diagnostics-same-crate.rs:56:19 + --> $DIR/diagnostics-same-crate.rs:58:19 | LL | inner::right::meow(); | ^^^^ not found in `inner::right` | note: found an item that was configured out - --> $DIR/diagnostics-same-crate.rs:24:16 + --> $DIR/diagnostics-same-crate.rs:26:16 | LL | pub fn meow() {} | ^^^^ - = note: the item is gated behind the `what-a-cool-feature` feature +note: the item is gated behind the `what-a-cool-feature` feature + --> $DIR/diagnostics-same-crate.rs:25:15 + | +LL | #[cfg(feature = "what-a-cool-feature")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `uwu` in this scope - --> $DIR/diagnostics-same-crate.rs:43:5 + --> $DIR/diagnostics-same-crate.rs:45:5 | LL | uwu(); | ^^^ not found in this scope error[E0425]: cannot find function `vanished` in this scope - --> $DIR/diagnostics-same-crate.rs:63:5 + --> $DIR/diagnostics-same-crate.rs:64:5 | LL | vanished(); | ^^^^^^^^ not found in this scope diff --git a/tests/ui/macros/builtin-std-paths-fail.stderr b/tests/ui/macros/builtin-std-paths-fail.stderr index 331943843c02..49034c3987b2 100644 --- a/tests/ui/macros/builtin-std-paths-fail.stderr +++ b/tests/ui/macros/builtin-std-paths-fail.stderr @@ -104,6 +104,8 @@ LL | #[std::test] | note: found an item that was configured out --> $SRC_DIR/std/src/lib.rs:LL:COL +note: the item is gated here + --> $SRC_DIR/std/src/lib.rs:LL:COL error: aborting due to 16 previous errors diff --git a/tests/ui/macros/macro-outer-attributes.stderr b/tests/ui/macros/macro-outer-attributes.stderr index 87c0655a422d..a8809f3fcff6 100644 --- a/tests/ui/macros/macro-outer-attributes.stderr +++ b/tests/ui/macros/macro-outer-attributes.stderr @@ -9,6 +9,17 @@ note: found an item that was configured out | LL | pub fn bar() { }); | ^^^ +note: the item is gated here + --> $DIR/macro-outer-attributes.rs:5:45 + | +LL | $i:item) => (mod $nm { #[$a] $i }); } + | ^^^^^ +LL | +LL | / test!(a, +LL | | #[cfg(FALSE)], +LL | | pub fn bar() { }); + | |_______________________- in this macro invocation + = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this function | LL + use b::bar; From b98365871fb7b82350962e0af9245273885546e3 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 5 Jul 2024 16:33:11 -0400 Subject: [PATCH 119/734] rewrite raw-dylib-custom-dlltool to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../raw-dylib-custom-dlltool/Makefile | 11 --------- .../raw-dylib-custom-dlltool/rmake.rs | 24 +++++++++++++++++++ .../raw-dylib-custom-dlltool/script.cmd | 2 +- .../raw-dylib-inline-cross-dylib/rmake.rs | 14 +++++------ 5 files changed, 32 insertions(+), 20 deletions(-) delete mode 100644 tests/run-make/raw-dylib-custom-dlltool/Makefile create mode 100644 tests/run-make/raw-dylib-custom-dlltool/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 6d65b2e24e16..8bdaad21d7c7 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -119,7 +119,6 @@ run-make/profile/Makefile run-make/prune-link-args/Makefile run-make/raw-dylib-alt-calling-convention/Makefile run-make/raw-dylib-c/Makefile -run-make/raw-dylib-custom-dlltool/Makefile run-make/raw-dylib-import-name-type/Makefile run-make/raw-dylib-link-ordinal/Makefile run-make/raw-dylib-stdcall-ordinal/Makefile diff --git a/tests/run-make/raw-dylib-custom-dlltool/Makefile b/tests/run-make/raw-dylib-custom-dlltool/Makefile deleted file mode 100644 index f5d5360a3fbe..000000000000 --- a/tests/run-make/raw-dylib-custom-dlltool/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Test using -Cdlltool to change where raw-dylib looks for the dlltool binary. - -# only-windows -# only-gnu -# needs-dlltool - -include ../tools.mk - -all: - $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs -Cdlltool=$(CURDIR)/script.cmd - $(DIFF) output.txt "$(TMPDIR)"/output.txt diff --git a/tests/run-make/raw-dylib-custom-dlltool/rmake.rs b/tests/run-make/raw-dylib-custom-dlltool/rmake.rs new file mode 100644 index 000000000000..86b952f0b452 --- /dev/null +++ b/tests/run-make/raw-dylib-custom-dlltool/rmake.rs @@ -0,0 +1,24 @@ +// Instead of using the default dlltool, the rust compiler can also accept a custom +// command file with the -C dlltool flag. This test uses it to compile some rust code +// with the raw_dylib Windows-exclusive feature, and checks that the output contains +// the string passed from the custom dlltool, confirming that the default dlltool was +// successfully overridden. +// See https://github.com/rust-lang/rust/pull/109677 + +//@ only-windows +//@ only-gnu +//@ needs-dlltool +// Reason: this test specifically checks the custom dlltool feature, only +// available on Windows-gnu. + +use run_make_support::{diff, rustc}; + +fn main() { + let out = rustc() + .crate_type("lib") + .crate_name("raw_dylib_test") + .input("lib.rs") + .arg("-Cdlltool=script.cmd") + .run(); + diff().expected_file("output.txt").actual_file("actual.txt").normalize(r#"\r"#, "").run(); +} diff --git a/tests/run-make/raw-dylib-custom-dlltool/script.cmd b/tests/run-make/raw-dylib-custom-dlltool/script.cmd index 95f85c61c67d..51834590be03 100644 --- a/tests/run-make/raw-dylib-custom-dlltool/script.cmd +++ b/tests/run-make/raw-dylib-custom-dlltool/script.cmd @@ -1,2 +1,2 @@ -echo Called dlltool via script.cmd> %TMPDIR%\output.txt +echo Called dlltool via script.cmd> actual.txt dlltool.exe %* diff --git a/tests/run-make/raw-dylib-inline-cross-dylib/rmake.rs b/tests/run-make/raw-dylib-inline-cross-dylib/rmake.rs index b0cdc0aa4af5..6e3b31a0cdbd 100644 --- a/tests/run-make/raw-dylib-inline-cross-dylib/rmake.rs +++ b/tests/run-make/raw-dylib-inline-cross-dylib/rmake.rs @@ -32,8 +32,8 @@ fn main() { // Make sure we do find an import to the functions we expect to be imported. .assert_stdout_contains("library_function"); if is_msvc() { - cc().arg("-c").out_exe("extern_1.obj").input("extern_1.c").run(); - cc().arg("-c").out_exe("extern_2.obj").input("extern_2.c").run(); + cc().arg("-c").out_exe("extern_1").input("extern_1.c").run(); + cc().arg("-c").out_exe("extern_2").input("extern_2.c").run(); cc().input("extern_1.obj") .arg("-link") .arg("-dll") @@ -47,15 +47,15 @@ fn main() { .arg("-noimplib") .run(); } else { - cc().arg("-v").arg("-c").out_exe("extern_1.obj").input("extern_1.c").run(); - cc().arg("-v").arg("-c").out_exe("extern_2.obj").input("extern_2.c").run(); - cc().input("extern_1.obj").out_exe("extern_1.dll").arg("-shared").run(); - cc().input("extern_2.obj").out_exe("extern_2.dll").arg("-shared").run(); + cc().arg("-v").arg("-c").out_exe("extern_1").input("extern_1.c").run(); + cc().arg("-v").arg("-c").out_exe("extern_2").input("extern_2.c").run(); + cc().input("extern_1").out_exe("extern_1.dll").arg("-shared").run(); + cc().input("extern_2").out_exe("extern_2.dll").arg("-shared").run(); } let out = run("driver").stdout_utf8(); diff() .expected_file("output.txt") .actual_text("actual_output", out) - .normalize(r#"\\r"#, "") + .normalize(r#"\r"#, "") .run(); } From 39378cf4f405f3c27dacf1e3e1a509c9d73602dc Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sat, 13 Jul 2024 15:46:52 +0700 Subject: [PATCH 120/734] Add more doc-valid-idents * "AccessKit" is a commonly used accessibility toolkit used in Rust GUIs. * "CoreFoundation", "CoreGraphics", "CoreText" are frameworks on Apple OSes. * "Direct2D", "Direct3D", "DirectWrite" are frameworks on Windows * "PostScript" is a programming language and is mentioned when talking about text and vector graphics. * "OpenAL" is an audio framework / API. * "OpenType" is a font format (TrueType is already mentioned). * "WebRTC", "WebSocket", "WebTransport" are web networking technologies. * "NetBSD" and "OpenBSD" are like the already included FreeBSD. --- book/src/lint_configuration.md | 2 +- clippy_config/src/conf.rs | 13 ++++++---- tests/ui/doc/doc-fixable.fixed | 13 ++++++---- tests/ui/doc/doc-fixable.rs | 13 ++++++---- tests/ui/doc/doc-fixable.stderr | 44 ++++++++++++++++----------------- 5 files changed, 47 insertions(+), 38 deletions(-) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index ad29339a84ad..a750f3619d0d 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -455,7 +455,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "AccessKit", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` --- **Affected lints:** diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 7f53aad67933..18e481b7af95 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -18,23 +18,26 @@ use std::{cmp, env, fmt, fs, io}; #[rustfmt::skip] const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", + "AccessKit", + "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", - "DirectX", + "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", - "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", + "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", - "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", - "WebGL", "WebGL2", "WebGPU", + "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", + "OpenType", + "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", - "iOS", "macOS", "FreeBSD", + "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase", diff --git a/tests/ui/doc/doc-fixable.fixed b/tests/ui/doc/doc-fixable.fixed index 84673f1f43fd..edfffe8fcfe3 100644 --- a/tests/ui/doc/doc-fixable.fixed +++ b/tests/ui/doc/doc-fixable.fixed @@ -54,21 +54,24 @@ fn test_units() { /// This tests allowed identifiers. /// KiB MiB GiB TiB PiB EiB -/// DirectX +/// AccessKit +/// CoreFoundation CoreGraphics CoreText +/// Direct2D Direct3D DirectWrite DirectX /// ECMAScript /// GPLv2 GPLv3 /// GitHub GitLab /// IPv4 IPv6 -/// ClojureScript CoffeeScript JavaScript PureScript TypeScript +/// ClojureScript CoffeeScript JavaScript PostScript PureScript TypeScript /// WebAssembly /// NaN NaNs /// OAuth GraphQL /// OCaml -/// OpenDNS OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenTelemetry -/// WebGL WebGL2 WebGPU +/// OpenAL OpenDNS OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenTelemetry +/// OpenType +/// WebGL WebGL2 WebGPU WebRTC WebSocket WebTransport /// TensorFlow /// TrueType -/// iOS macOS FreeBSD +/// iOS macOS FreeBSD NetBSD OpenBSD /// TeX LaTeX BibTeX BibLaTeX /// MinGW /// CamelCase (see also #2395) diff --git a/tests/ui/doc/doc-fixable.rs b/tests/ui/doc/doc-fixable.rs index 4d017a99e0fb..3c0f6913e328 100644 --- a/tests/ui/doc/doc-fixable.rs +++ b/tests/ui/doc/doc-fixable.rs @@ -54,21 +54,24 @@ fn test_units() { /// This tests allowed identifiers. /// KiB MiB GiB TiB PiB EiB -/// DirectX +/// AccessKit +/// CoreFoundation CoreGraphics CoreText +/// Direct2D Direct3D DirectWrite DirectX /// ECMAScript /// GPLv2 GPLv3 /// GitHub GitLab /// IPv4 IPv6 -/// ClojureScript CoffeeScript JavaScript PureScript TypeScript +/// ClojureScript CoffeeScript JavaScript PostScript PureScript TypeScript /// WebAssembly /// NaN NaNs /// OAuth GraphQL /// OCaml -/// OpenDNS OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenTelemetry -/// WebGL WebGL2 WebGPU +/// OpenAL OpenDNS OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenTelemetry +/// OpenType +/// WebGL WebGL2 WebGPU WebRTC WebSocket WebTransport /// TensorFlow /// TrueType -/// iOS macOS FreeBSD +/// iOS macOS FreeBSD NetBSD OpenBSD /// TeX LaTeX BibTeX BibLaTeX /// MinGW /// CamelCase (see also #2395) diff --git a/tests/ui/doc/doc-fixable.stderr b/tests/ui/doc/doc-fixable.stderr index a9263f62d38d..67c0464149c6 100644 --- a/tests/ui/doc/doc-fixable.stderr +++ b/tests/ui/doc/doc-fixable.stderr @@ -133,7 +133,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:75:5 + --> tests/ui/doc/doc-fixable.rs:78:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:92:5 + --> tests/ui/doc/doc-fixable.rs:95:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -155,7 +155,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:100:8 + --> tests/ui/doc/doc-fixable.rs:103:8 | LL | /// ## CamelCaseThing | ^^^^^^^^^^^^^^ @@ -166,7 +166,7 @@ LL | /// ## `CamelCaseThing` | ~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:103:7 + --> tests/ui/doc/doc-fixable.rs:106:7 | LL | /// # CamelCaseThing | ^^^^^^^^^^^^^^ @@ -177,7 +177,7 @@ LL | /// # `CamelCaseThing` | ~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:105:22 + --> tests/ui/doc/doc-fixable.rs:108:22 | LL | /// Not a title #897 CamelCaseThing | ^^^^^^^^^^^^^^ @@ -188,7 +188,7 @@ LL | /// Not a title #897 `CamelCaseThing` | ~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:106:5 + --> tests/ui/doc/doc-fixable.rs:109:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -199,7 +199,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:113:5 + --> tests/ui/doc/doc-fixable.rs:116:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -210,7 +210,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:126:5 + --> tests/ui/doc/doc-fixable.rs:129:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -221,7 +221,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:137:43 + --> tests/ui/doc/doc-fixable.rs:140:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ @@ -232,7 +232,7 @@ LL | /** E.g., serialization of an empty list: `FooBar` | ~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:142:5 + --> tests/ui/doc/doc-fixable.rs:145:5 | LL | And BarQuz too. | ^^^^^^ @@ -243,7 +243,7 @@ LL | And `BarQuz` too. | ~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:143:1 + --> tests/ui/doc/doc-fixable.rs:146:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -254,7 +254,7 @@ LL | `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:148:43 + --> tests/ui/doc/doc-fixable.rs:151:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ @@ -265,7 +265,7 @@ LL | /** E.g., serialization of an empty list: `FooBar` | ~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:153:5 + --> tests/ui/doc/doc-fixable.rs:156:5 | LL | And BarQuz too. | ^^^^^^ @@ -276,7 +276,7 @@ LL | And `BarQuz` too. | ~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:154:1 + --> tests/ui/doc/doc-fixable.rs:157:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -287,7 +287,7 @@ LL | `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:165:5 + --> tests/ui/doc/doc-fixable.rs:168:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -298,7 +298,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:184:22 + --> tests/ui/doc/doc-fixable.rs:187:22 | LL | /// An iterator over mycrate::Collection's values. | ^^^^^^^^^^^^^^^^^^^ @@ -309,7 +309,7 @@ LL | /// An iterator over `mycrate::Collection`'s values. | ~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:208:34 + --> tests/ui/doc/doc-fixable.rs:211:34 | LL | /// Foo \[bar\] \[baz\] \[qux\]. DocMarkdownLint | ^^^^^^^^^^^^^^^ @@ -320,7 +320,7 @@ LL | /// Foo \[bar\] \[baz\] \[qux\]. `DocMarkdownLint` | ~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:231:22 + --> tests/ui/doc/doc-fixable.rs:234:22 | LL | /// There is no try (do() or do_not()). | ^^^^ @@ -331,7 +331,7 @@ LL | /// There is no try (`do()` or do_not()). | ~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:231:30 + --> tests/ui/doc/doc-fixable.rs:234:30 | LL | /// There is no try (do() or do_not()). | ^^^^^^^^ @@ -342,7 +342,7 @@ LL | /// There is no try (do() or `do_not()`). | ~~~~~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:234:5 + --> tests/ui/doc/doc-fixable.rs:237:5 | LL | /// ABes | ^^^^ @@ -353,7 +353,7 @@ LL | /// `ABes` | ~~~~~~ error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:240:9 + --> tests/ui/doc/doc-fixable.rs:243:9 | LL | /// foo() | ^^^^^ @@ -364,7 +364,7 @@ LL | /// `foo()` | ~~~~~~~ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> tests/ui/doc/doc-fixable.rs:244:5 + --> tests/ui/doc/doc-fixable.rs:247:5 | LL | /// https://github.com/rust-lang/rust-clippy/pull/12836 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `` From cc1bb8f57a167d2e01db4c2175bfea1a8f48e772 Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Thu, 11 Jul 2024 15:08:22 +0800 Subject: [PATCH 121/734] make [`or_fun_call`] and [`unwrap_or_default`] recursive. --- clippy_lints/src/methods/or_fun_call.rs | 110 ++++++++++++++---------- tests/ui/or_fun_call.fixed | 35 ++++++++ tests/ui/or_fun_call.rs | 35 ++++++++ tests/ui/or_fun_call.stderr | 50 ++++++++++- 4 files changed, 183 insertions(+), 47 deletions(-) diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index baa60454419b..e4326cb958e5 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -1,8 +1,13 @@ +use std::ops::ControlFlow; + use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_lazy_eval; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{expr_type_is_certain, implements_trait, is_type_diagnostic_item}; -use clippy_utils::{contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment}; +use clippy_utils::visitors::for_each_expr; +use clippy_utils::{ + contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment, peel_blocks, +}; use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_middle::ty; @@ -13,7 +18,7 @@ use {rustc_ast as ast, rustc_hir as hir}; use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT}; /// Checks for the `OR_FUN_CALL` lint. -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, @@ -26,7 +31,6 @@ pub(super) fn check<'tcx>( /// `or_insert(T::new())` or `or_insert(T::default())`. /// Similarly checks for `unwrap_or_else(T::new)`, `unwrap_or_else(T::default)`, /// `or_insert_with(T::new)` or `or_insert_with(T::default)`. - #[allow(clippy::too_many_arguments)] fn check_unwrap_or_default( cx: &LateContext<'_>, name: &str, @@ -123,8 +127,8 @@ pub(super) fn check<'tcx>( } /// Checks for `*or(foo())`. - #[allow(clippy::too_many_arguments)] - fn check_general_case<'tcx>( + #[expect(clippy::too_many_arguments)] + fn check_or_fn_call<'tcx>( cx: &LateContext<'tcx>, name: &str, method_span: Span, @@ -135,7 +139,7 @@ pub(super) fn check<'tcx>( span: Span, // None if lambda is required fun_span: Option, - ) { + ) -> bool { // (path, fn_has_argument, methods, suffix) const KNOW_TYPES: [(Symbol, bool, &[&str], &str); 4] = [ (sym::BTreeEntry, false, &["or_insert"], "with"), @@ -185,54 +189,68 @@ pub(super) fn check<'tcx>( format!("{name}_{suffix}({sugg})"), app, ); + true + } else { + false } } - let extract_inner_arg = |arg: &'tcx hir::Expr<'_>| { - if let hir::ExprKind::Block( - hir::Block { - stmts: [], - expr: Some(expr), - .. - }, - _, - ) = arg.kind - { - expr - } else { - arg - } - }; - if let [arg] = args { - let inner_arg = extract_inner_arg(arg); - match inner_arg.kind { - hir::ExprKind::Call(fun, or_args) => { - let or_has_args = !or_args.is_empty(); - if or_has_args - || !check_unwrap_or_default(cx, name, receiver, fun, Some(inner_arg), expr.span, method_span) - { - let fun_span = if or_has_args { None } else { Some(fun.span) }; - check_general_case(cx, name, method_span, receiver, arg, None, expr.span, fun_span); - } - }, - hir::ExprKind::Path(..) | hir::ExprKind::Closure(..) => { - check_unwrap_or_default(cx, name, receiver, inner_arg, None, expr.span, method_span); - }, - hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { - check_general_case(cx, name, method_span, receiver, arg, None, expr.span, None); - }, - _ => (), - } + let inner_arg = peel_blocks(arg); + for_each_expr(cx, inner_arg, |ex| { + // `or_fun_call` lint needs to take nested expr into account, + // but `unwrap_or_default` lint doesn't, we don't want something like: + // `opt.unwrap_or(Foo { inner: String::default(), other: 1 })` to get replaced by + // `opt.unwrap_or_default()`. + let is_nested_expr = ex.hir_id != inner_arg.hir_id; + + let is_triggered = match ex.kind { + hir::ExprKind::Call(fun, fun_args) => { + let inner_fun_has_args = !fun_args.is_empty(); + let fun_span = if inner_fun_has_args || is_nested_expr { + None + } else { + Some(fun.span) + }; + (!inner_fun_has_args + && !is_nested_expr + && check_unwrap_or_default(cx, name, receiver, fun, Some(ex), expr.span, method_span)) + || check_or_fn_call(cx, name, method_span, receiver, arg, None, expr.span, fun_span) + }, + hir::ExprKind::Path(..) | hir::ExprKind::Closure(..) if !is_nested_expr => { + check_unwrap_or_default(cx, name, receiver, ex, None, expr.span, method_span) + }, + hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { + check_or_fn_call(cx, name, method_span, receiver, arg, None, expr.span, None) + }, + _ => false, + }; + + if is_triggered { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }); } // `map_or` takes two arguments if let [arg, lambda] = args { - let inner_arg = extract_inner_arg(arg); - if let hir::ExprKind::Call(fun, or_args) = inner_arg.kind { - let fun_span = if or_args.is_empty() { Some(fun.span) } else { None }; - check_general_case(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span); - } + let inner_arg = peel_blocks(arg); + for_each_expr(cx, inner_arg, |ex| { + let is_top_most_expr = ex.hir_id == inner_arg.hir_id; + if let hir::ExprKind::Call(fun, fun_args) = ex.kind { + let fun_span = if fun_args.is_empty() && is_top_most_expr { + Some(fun.span) + } else { + None + }; + if check_or_fn_call(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span) { + return ControlFlow::Break(()); + } + } + ControlFlow::Continue(()) + }); } } diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 350155929718..7452eb776888 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -330,4 +330,39 @@ mod issue_10228 { } } +// issue #12973 +fn fn_call_in_nested_expr() { + struct Foo { + val: String, + } + + fn f() -> i32 { + 1 + } + let opt: Option = Some(1); + + //~v ERROR: use of `unwrap_or` followed by a function call + let _ = opt.unwrap_or_else(f); // suggest `.unwrap_or_else(f)` + // + //~v ERROR: use of `unwrap_or` followed by a function call + let _ = opt.unwrap_or_else(|| f() + 1); // suggest `.unwrap_or_else(|| f() + 1)` + // + //~v ERROR: use of `unwrap_or` followed by a function call + let _ = opt.unwrap_or_else(|| { + let x = f(); + x + 1 + }); + //~v ERROR: use of `map_or` followed by a function call + let _ = opt.map_or_else(|| f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)` + // + //~v ERROR: use of `unwrap_or` to construct default value + let _ = opt.unwrap_or_default(); + + let opt_foo = Some(Foo { + val: String::from("123"), + }); + //~v ERROR: use of `unwrap_or` followed by a function call + let _ = opt_foo.unwrap_or_else(|| Foo { val: String::default() }); +} + fn main() {} diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 3dcf657d7435..cd6f7bb20701 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -330,4 +330,39 @@ mod issue_10228 { } } +// issue #12973 +fn fn_call_in_nested_expr() { + struct Foo { + val: String, + } + + fn f() -> i32 { + 1 + } + let opt: Option = Some(1); + + //~v ERROR: use of `unwrap_or` followed by a function call + let _ = opt.unwrap_or({ f() }); // suggest `.unwrap_or_else(f)` + // + //~v ERROR: use of `unwrap_or` followed by a function call + let _ = opt.unwrap_or(f() + 1); // suggest `.unwrap_or_else(|| f() + 1)` + // + //~v ERROR: use of `unwrap_or` followed by a function call + let _ = opt.unwrap_or({ + let x = f(); + x + 1 + }); + //~v ERROR: use of `map_or` followed by a function call + let _ = opt.map_or(f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)` + // + //~v ERROR: use of `unwrap_or` to construct default value + let _ = opt.unwrap_or({ i32::default() }); + + let opt_foo = Some(Foo { + val: String::from("123"), + }); + //~v ERROR: use of `unwrap_or` followed by a function call + let _ = opt_foo.unwrap_or(Foo { val: String::default() }); +} + fn main() {} diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 3070db22fc5a..06f804fb41e8 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -196,5 +196,53 @@ error: use of `unwrap_or_else` to construct default value LL | let _ = stringy.unwrap_or_else(String::new); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: aborting due to 32 previous errors +error: use of `unwrap_or` followed by a function call + --> tests/ui/or_fun_call.rs:345:17 + | +LL | let _ = opt.unwrap_or({ f() }); // suggest `.unwrap_or_else(f)` + | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(f)` + +error: use of `unwrap_or` followed by a function call + --> tests/ui/or_fun_call.rs:348:17 + | +LL | let _ = opt.unwrap_or(f() + 1); // suggest `.unwrap_or_else(|| f() + 1)` + | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| f() + 1)` + +error: use of `unwrap_or` followed by a function call + --> tests/ui/or_fun_call.rs:351:17 + | +LL | let _ = opt.unwrap_or({ + | _________________^ +LL | | let x = f(); +LL | | x + 1 +LL | | }); + | |______^ + | +help: try + | +LL ~ let _ = opt.unwrap_or_else(|| { +LL + let x = f(); +LL + x + 1 +LL ~ }); + | + +error: use of `map_or` followed by a function call + --> tests/ui/or_fun_call.rs:356:17 + | +LL | let _ = opt.map_or(f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)` + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| f() + 1, |v| v)` + +error: use of `unwrap_or` to construct default value + --> tests/ui/or_fun_call.rs:359:17 + | +LL | let _ = opt.unwrap_or({ i32::default() }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` + +error: use of `unwrap_or` followed by a function call + --> tests/ui/or_fun_call.rs:365:21 + | +LL | let _ = opt_foo.unwrap_or(Foo { val: String::default() }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Foo { val: String::default() })` + +error: aborting due to 38 previous errors From 332b41dbce936647232311a51b0febcd3615d731 Mon Sep 17 00:00:00 2001 From: long-long-float Date: Sun, 12 May 2024 16:40:59 +0900 Subject: [PATCH 122/734] Use ordinal number in argument error Fix error message Fix tests Format --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 19 ++++++- tests/ui/argument-suggestions/basic.stderr | 4 +- .../display-is-suggestable.stderr | 2 +- .../extern-fn-arg-names.stderr | 2 +- .../extra_arguments.stderr | 56 +++++++++---------- .../argument-suggestions/issue-100478.stderr | 6 +- .../argument-suggestions/issue-101097.stderr | 6 +- .../argument-suggestions/issue-109425.stderr | 20 +++---- .../argument-suggestions/issue-109831.stderr | 2 +- .../argument-suggestions/issue-112507.stderr | 6 +- .../argument-suggestions/issue-96638.stderr | 2 +- .../argument-suggestions/issue-97484.stderr | 6 +- .../argument-suggestions/issue-98894.stderr | 2 +- .../argument-suggestions/issue-98897.stderr | 2 +- .../argument-suggestions/issue-99482.stderr | 2 +- .../missing_arguments.stderr | 20 +++---- .../argument-suggestions/mixed_cases.stderr | 16 +++--- ...uggest-better-removing-issue-126246.stderr | 12 ++-- .../issue-109768.stderr | 2 +- tests/ui/c-variadic/variadic-ffi-1.stderr | 2 +- .../ice-cast-type-with-error-124848.stderr | 2 +- tests/ui/coroutine/issue-102645.stderr | 2 +- tests/ui/error-codes/E0057.stderr | 4 +- tests/ui/error-codes/E0060.stderr | 2 +- tests/ui/error-codes/E0061.stderr | 4 +- tests/ui/extern/issue-18819.stderr | 2 +- tests/ui/fn/issue-3044.stderr | 2 +- .../issue-91139.migrate.stderr | 1 - .../trait-bounds/issue-58451.stderr | 2 +- tests/ui/issues/issue-4935.stderr | 2 +- tests/ui/lifetimes/issue-26638.stderr | 2 +- tests/ui/methods/method-call-err-msg.stderr | 4 +- .../overloaded-calls-bad.stderr | 4 +- tests/ui/not-enough-arguments.stderr | 2 +- tests/ui/span/issue-34264.stderr | 4 +- tests/ui/span/missing-unit-argument.stderr | 10 ++-- .../args-instead-of-tuple-errors.stderr | 6 +- .../suggestions/args-instead-of-tuple.stderr | 2 +- tests/ui/suggestions/issue-109396.stderr | 8 +-- tests/ui/suggestions/issue-109854.stderr | 4 +- tests/ui/tuple/wrong_argument_ice-3.stderr | 2 +- ...priority-higher-than-other-inherent.stderr | 2 +- ...e-ascription-instead-of-initializer.stderr | 2 +- .../type/type-check/point-at-inference-4.rs | 2 +- .../type-check/point-at-inference-4.stderr | 2 +- tests/ui/typeck/cyclic_type_ice.stderr | 2 +- tests/ui/typeck/remove-extra-argument.stderr | 2 +- tests/ui/typeck/struct-enum-wrong-args.stderr | 16 +++--- 48 files changed, 151 insertions(+), 137 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index ab0f356ce91f..09663085e969 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1094,7 +1094,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { "".to_string() }; - labels.push((provided_span, format!("unexpected argument{provided_ty_name}"))); + let idx = if provided_arg_tys.len() == 1 { + "".to_string() + } else { + format!(" #{}", arg_idx.as_usize() + 1) + }; + labels.push(( + provided_span, + format!("unexpected argument{idx}{provided_ty_name}"), + )); let mut span = provided_span; if span.can_be_used_for_suggestions() && error_span.can_be_used_for_suggestions() @@ -1175,7 +1183,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { "".to_string() }; - labels.push((span, format!("an argument{rendered} is missing"))); + labels.push(( + span, + format!( + "argument #{}{rendered} is missing", + expected_idx.as_usize() + 1 + ), + )); + suggestion_text = match suggestion_text { SuggestionText::None => SuggestionText::Provide(false), SuggestionText::Provide(_) => SuggestionText::Provide(true), diff --git a/tests/ui/argument-suggestions/basic.stderr b/tests/ui/argument-suggestions/basic.stderr index ea58ca97cfaf..2d52df212336 100644 --- a/tests/ui/argument-suggestions/basic.stderr +++ b/tests/ui/argument-suggestions/basic.stderr @@ -33,7 +33,7 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/basic.rs:22:5 | LL | missing(); - | ^^^^^^^-- an argument of type `u32` is missing + | ^^^^^^^-- argument #1 of type `u32` is missing | note: function defined here --> $DIR/basic.rs:15:4 @@ -86,7 +86,7 @@ error[E0057]: this function takes 1 argument but 0 arguments were supplied --> $DIR/basic.rs:27:5 | LL | closure(); - | ^^^^^^^-- an argument is missing + | ^^^^^^^-- argument #1 is missing | note: closure defined here --> $DIR/basic.rs:26:19 diff --git a/tests/ui/argument-suggestions/display-is-suggestable.stderr b/tests/ui/argument-suggestions/display-is-suggestable.stderr index bde87475e0a6..eea88c3e78d7 100644 --- a/tests/ui/argument-suggestions/display-is-suggestable.stderr +++ b/tests/ui/argument-suggestions/display-is-suggestable.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/display-is-suggestable.rs:6:5 | LL | foo(); - | ^^^-- an argument of type `&dyn std::fmt::Display + Send` is missing + | ^^^-- argument #1 of type `&dyn std::fmt::Display + Send` is missing | note: function defined here --> $DIR/display-is-suggestable.rs:3:4 diff --git a/tests/ui/argument-suggestions/extern-fn-arg-names.stderr b/tests/ui/argument-suggestions/extern-fn-arg-names.stderr index f6bc84c1203a..47fbfc98c676 100644 --- a/tests/ui/argument-suggestions/extern-fn-arg-names.stderr +++ b/tests/ui/argument-suggestions/extern-fn-arg-names.stderr @@ -8,7 +8,7 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/extern-fn-arg-names.rs:7:5 | LL | dstfn(1); - | ^^^^^--- an argument is missing + | ^^^^^--- argument #2 is missing | note: function defined here --> $DIR/extern-fn-arg-names.rs:2:8 diff --git a/tests/ui/argument-suggestions/extra_arguments.stderr b/tests/ui/argument-suggestions/extra_arguments.stderr index dec3da751865..8c95cc86a273 100644 --- a/tests/ui/argument-suggestions/extra_arguments.stderr +++ b/tests/ui/argument-suggestions/extra_arguments.stderr @@ -19,9 +19,9 @@ error[E0061]: this function takes 0 arguments but 2 arguments were supplied --> $DIR/extra_arguments.rs:20:3 | LL | empty(1, 1); - | ^^^^^ - - unexpected argument of type `{integer}` + | ^^^^^ - - unexpected argument #2 of type `{integer}` | | - | unexpected argument of type `{integer}` + | unexpected argument #1 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:1:4 @@ -38,7 +38,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:22:3 | LL | one_arg(1, 1); - | ^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^ - unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -55,7 +55,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:23:3 | LL | one_arg(1, ""); - | ^^^^^^^ -- unexpected argument of type `&'static str` + | ^^^^^^^ -- unexpected argument #2 of type `&'static str` | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -72,9 +72,9 @@ error[E0061]: this function takes 1 argument but 3 arguments were supplied --> $DIR/extra_arguments.rs:24:3 | LL | one_arg(1, "", 1.0); - | ^^^^^^^ -- --- unexpected argument of type `{float}` + | ^^^^^^^ -- --- unexpected argument #3 of type `{float}` | | - | unexpected argument of type `&'static str` + | unexpected argument #2 of type `&'static str` | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -91,7 +91,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:26:3 | LL | two_arg_same(1, 1, 1); - | ^^^^^^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^^^^^^ - unexpected argument #3 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:3:4 @@ -108,7 +108,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:27:3 | LL | two_arg_same(1, 1, 1.0); - | ^^^^^^^^^^^^ --- unexpected argument of type `{float}` + | ^^^^^^^^^^^^ --- unexpected argument #3 of type `{float}` | note: function defined here --> $DIR/extra_arguments.rs:3:4 @@ -125,7 +125,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:29:3 | LL | two_arg_diff(1, 1, ""); - | ^^^^^^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^^^^^^ - unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -142,7 +142,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:30:3 | LL | two_arg_diff(1, "", ""); - | ^^^^^^^^^^^^ -- unexpected argument of type `&'static str` + | ^^^^^^^^^^^^ -- unexpected argument #3 of type `&'static str` | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -159,9 +159,9 @@ error[E0061]: this function takes 2 arguments but 4 arguments were supplied --> $DIR/extra_arguments.rs:31:3 | LL | two_arg_diff(1, 1, "", ""); - | ^^^^^^^^^^^^ - -- unexpected argument of type `&'static str` + | ^^^^^^^^^^^^ - -- unexpected argument #4 of type `&'static str` | | - | unexpected argument of type `{integer}` + | unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -178,9 +178,9 @@ error[E0061]: this function takes 2 arguments but 4 arguments were supplied --> $DIR/extra_arguments.rs:32:3 | LL | two_arg_diff(1, "", 1, ""); - | ^^^^^^^^^^^^ - -- unexpected argument of type `&'static str` + | ^^^^^^^^^^^^ - -- unexpected argument #4 of type `&'static str` | | - | unexpected argument of type `{integer}` + | unexpected argument #3 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -197,7 +197,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:35:3 | LL | two_arg_same(1, 1, ""); - | ^^^^^^^^^^^^ -- unexpected argument of type `&'static str` + | ^^^^^^^^^^^^ -- unexpected argument #3 of type `&'static str` | note: function defined here --> $DIR/extra_arguments.rs:3:4 @@ -214,7 +214,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:36:3 | LL | two_arg_diff(1, 1, ""); - | ^^^^^^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^^^^^^ - unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -234,7 +234,7 @@ LL | two_arg_same( | ^^^^^^^^^^^^ ... LL | "" - | -- unexpected argument of type `&'static str` + | -- unexpected argument #3 of type `&'static str` | note: function defined here --> $DIR/extra_arguments.rs:3:4 @@ -255,7 +255,7 @@ LL | two_arg_diff( | ^^^^^^^^^^^^ LL | 1, LL | 1, - | - unexpected argument of type `{integer}` + | - unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -271,12 +271,12 @@ error[E0061]: this function takes 0 arguments but 2 arguments were supplied --> $DIR/extra_arguments.rs:8:9 | LL | empty($x, 1); - | ^^^^^ - unexpected argument of type `{integer}` + | ^^^^^ - unexpected argument #2 of type `{integer}` ... LL | foo!(1, ~); | ---------- | | | - | | unexpected argument of type `{integer}` + | | unexpected argument #1 of type `{integer}` | in this macro invocation | note: function defined here @@ -290,12 +290,12 @@ error[E0061]: this function takes 0 arguments but 2 arguments were supplied --> $DIR/extra_arguments.rs:14:9 | LL | empty(1, $y); - | ^^^^^ - unexpected argument of type `{integer}` + | ^^^^^ - unexpected argument #1 of type `{integer}` ... LL | foo!(~, 1); | ---------- | | | - | | unexpected argument of type `{integer}` + | | unexpected argument #2 of type `{integer}` | in this macro invocation | note: function defined here @@ -314,8 +314,8 @@ LL | empty($x, $y); LL | foo!(1, 1); | ---------- | | | | - | | | unexpected argument of type `{integer}` - | | unexpected argument of type `{integer}` + | | | unexpected argument #2 of type `{integer}` + | | unexpected argument #1 of type `{integer}` | in this macro invocation | note: function defined here @@ -329,7 +329,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:53:3 | LL | one_arg(1, panic!()); - | ^^^^^^^ -------- unexpected argument + | ^^^^^^^ -------- unexpected argument #2 | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -346,7 +346,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:54:3 | LL | one_arg(panic!(), 1); - | ^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^ - unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -363,7 +363,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:55:3 | LL | one_arg(stringify!($e), 1); - | ^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^ - unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -380,7 +380,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:60:3 | LL | one_arg(for _ in 1.. {}, 1); - | ^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^ - unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:2:4 diff --git a/tests/ui/argument-suggestions/issue-100478.stderr b/tests/ui/argument-suggestions/issue-100478.stderr index e4304988f9be..94709f0ebc6a 100644 --- a/tests/ui/argument-suggestions/issue-100478.stderr +++ b/tests/ui/argument-suggestions/issue-100478.stderr @@ -4,8 +4,8 @@ error[E0061]: this function takes 3 arguments but 1 argument was supplied LL | three_diff(T2::new(0)); | ^^^^^^^^^^------------ | || - | |an argument of type `T1` is missing - | an argument of type `T3` is missing + | |argument #1 of type `T1` is missing + | argument #3 of type `T3` is missing | note: function defined here --> $DIR/issue-100478.rs:30:4 @@ -63,7 +63,7 @@ LL | foo( | ^^^ ... LL | p3, p4, p5, p6, p7, p8, - | -- an argument of type `Arc` is missing + | -- argument #2 of type `Arc` is missing | note: function defined here --> $DIR/issue-100478.rs:29:4 diff --git a/tests/ui/argument-suggestions/issue-101097.stderr b/tests/ui/argument-suggestions/issue-101097.stderr index 061f510144bd..6e21f19ab4fb 100644 --- a/tests/ui/argument-suggestions/issue-101097.stderr +++ b/tests/ui/argument-suggestions/issue-101097.stderr @@ -4,7 +4,7 @@ error[E0061]: this function takes 6 arguments but 7 arguments were supplied LL | f(C, A, A, A, B, B, C); | ^ - - - - expected `C`, found `B` | | | | - | | | unexpected argument of type `A` + | | | unexpected argument #4 of type `A` | | expected `B`, found `A` | expected `A`, found `C` | @@ -64,8 +64,8 @@ error[E0308]: arguments to this function are incorrect LL | f(A, A, D, D, B, B); | ^ - - ---- two arguments of type `C` and `C` are missing | | | - | | unexpected argument of type `D` - | unexpected argument of type `D` + | | unexpected argument #4 of type `D` + | unexpected argument #3 of type `D` | note: function defined here --> $DIR/issue-101097.rs:6:4 diff --git a/tests/ui/argument-suggestions/issue-109425.stderr b/tests/ui/argument-suggestions/issue-109425.stderr index 1514f1cb487e..bfe007793d4a 100644 --- a/tests/ui/argument-suggestions/issue-109425.stderr +++ b/tests/ui/argument-suggestions/issue-109425.stderr @@ -2,9 +2,9 @@ error[E0061]: this function takes 0 arguments but 2 arguments were supplied --> $DIR/issue-109425.rs:10:5 | LL | f(0, 1,); // f() - | ^ - - unexpected argument of type `{integer}` + | ^ - - unexpected argument #2 of type `{integer}` | | - | unexpected argument of type `{integer}` + | unexpected argument #1 of type `{integer}` | note: function defined here --> $DIR/issue-109425.rs:3:4 @@ -21,9 +21,9 @@ error[E0061]: this function takes 1 argument but 3 arguments were supplied --> $DIR/issue-109425.rs:12:5 | LL | i(0, 1, 2,); // i(0,) - | ^ - - unexpected argument of type `{integer}` + | ^ - - unexpected argument #3 of type `{integer}` | | - | unexpected argument of type `{integer}` + | unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/issue-109425.rs:4:4 @@ -40,9 +40,9 @@ error[E0061]: this function takes 1 argument but 3 arguments were supplied --> $DIR/issue-109425.rs:14:5 | LL | i(0, 1, 2); // i(0) - | ^ - - unexpected argument of type `{integer}` + | ^ - - unexpected argument #3 of type `{integer}` | | - | unexpected argument of type `{integer}` + | unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/issue-109425.rs:4:4 @@ -59,9 +59,9 @@ error[E0061]: this function takes 2 arguments but 4 arguments were supplied --> $DIR/issue-109425.rs:16:5 | LL | is(0, 1, 2, ""); // is(0, "") - | ^^ - - unexpected argument of type `{integer}` + | ^^ - - unexpected argument #3 of type `{integer}` | | - | unexpected argument of type `{integer}` + | unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/issue-109425.rs:5:4 @@ -78,9 +78,9 @@ error[E0061]: this function takes 1 argument but 3 arguments were supplied --> $DIR/issue-109425.rs:18:5 | LL | s(0, 1, ""); // s("") - | ^ - - unexpected argument of type `{integer}` + | ^ - - unexpected argument #2 of type `{integer}` | | - | unexpected argument of type `{integer}` + | unexpected argument #1 of type `{integer}` | note: function defined here --> $DIR/issue-109425.rs:6:4 diff --git a/tests/ui/argument-suggestions/issue-109831.stderr b/tests/ui/argument-suggestions/issue-109831.stderr index 7b9a3c9ef2c6..12be0887121a 100644 --- a/tests/ui/argument-suggestions/issue-109831.stderr +++ b/tests/ui/argument-suggestions/issue-109831.stderr @@ -29,7 +29,7 @@ error[E0061]: this function takes 3 arguments but 4 arguments were supplied --> $DIR/issue-109831.rs:7:5 | LL | f(A, A, B, C); - | ^ - - - unexpected argument + | ^ - - - unexpected argument #4 | | | | | expected `B`, found `A` | expected `B`, found `A` diff --git a/tests/ui/argument-suggestions/issue-112507.stderr b/tests/ui/argument-suggestions/issue-112507.stderr index 17bde4d97433..908ed35c6697 100644 --- a/tests/ui/argument-suggestions/issue-112507.stderr +++ b/tests/ui/argument-suggestions/issue-112507.stderr @@ -4,12 +4,12 @@ error[E0061]: this enum variant takes 1 argument but 4 arguments were supplied LL | let _a = Value::Float( | ^^^^^^^^^^^^ LL | 0, - | - unexpected argument of type `{integer}` + | - unexpected argument #1 of type `{integer}` LL | None, LL | None, - | ---- unexpected argument of type `Option<_>` + | ---- unexpected argument #3 of type `Option<_>` LL | 0, - | - unexpected argument of type `{integer}` + | - unexpected argument #4 of type `{integer}` | note: tuple variant defined here --> $DIR/issue-112507.rs:2:5 diff --git a/tests/ui/argument-suggestions/issue-96638.stderr b/tests/ui/argument-suggestions/issue-96638.stderr index 887bf82a2f6f..6492acbad940 100644 --- a/tests/ui/argument-suggestions/issue-96638.stderr +++ b/tests/ui/argument-suggestions/issue-96638.stderr @@ -4,7 +4,7 @@ error[E0061]: this function takes 3 arguments but 2 arguments were supplied LL | f(&x, ""); | ^ -- -- expected `usize`, found `&str` | | - | an argument of type `usize` is missing + | argument #1 of type `usize` is missing | note: function defined here --> $DIR/issue-96638.rs:1:4 diff --git a/tests/ui/argument-suggestions/issue-97484.stderr b/tests/ui/argument-suggestions/issue-97484.stderr index 6bdb734fddfa..a7708f6e0d73 100644 --- a/tests/ui/argument-suggestions/issue-97484.stderr +++ b/tests/ui/argument-suggestions/issue-97484.stderr @@ -2,11 +2,11 @@ error[E0061]: this function takes 4 arguments but 7 arguments were supplied --> $DIR/issue-97484.rs:12:5 | LL | foo(&&A, B, C, D, E, F, G); - | ^^^ - - - - unexpected argument of type `F` + | ^^^ - - - - unexpected argument #6 of type `F` | | | | | | | expected `&E`, found `E` - | | unexpected argument of type `C` - | unexpected argument of type `B` + | | unexpected argument #3 of type `C` + | unexpected argument #2 of type `B` | note: function defined here --> $DIR/issue-97484.rs:9:4 diff --git a/tests/ui/argument-suggestions/issue-98894.stderr b/tests/ui/argument-suggestions/issue-98894.stderr index 72e6fec27e62..93e604c3101f 100644 --- a/tests/ui/argument-suggestions/issue-98894.stderr +++ b/tests/ui/argument-suggestions/issue-98894.stderr @@ -2,7 +2,7 @@ error[E0057]: this function takes 2 arguments but 1 argument was supplied --> $DIR/issue-98894.rs:2:5 | LL | (|_, ()| ())(if true {} else {return;}); - | ^^^^^^^^^^^^--------------------------- an argument of type `()` is missing + | ^^^^^^^^^^^^--------------------------- argument #2 of type `()` is missing | note: closure defined here --> $DIR/issue-98894.rs:2:6 diff --git a/tests/ui/argument-suggestions/issue-98897.stderr b/tests/ui/argument-suggestions/issue-98897.stderr index eed3964559ab..671e3d99d855 100644 --- a/tests/ui/argument-suggestions/issue-98897.stderr +++ b/tests/ui/argument-suggestions/issue-98897.stderr @@ -2,7 +2,7 @@ error[E0057]: this function takes 2 arguments but 1 argument was supplied --> $DIR/issue-98897.rs:2:5 | LL | (|_, ()| ())([return, ()]); - | ^^^^^^^^^^^^-------------- an argument of type `()` is missing + | ^^^^^^^^^^^^-------------- argument #2 of type `()` is missing | note: closure defined here --> $DIR/issue-98897.rs:2:6 diff --git a/tests/ui/argument-suggestions/issue-99482.stderr b/tests/ui/argument-suggestions/issue-99482.stderr index 9c83b47f8b64..be4078746152 100644 --- a/tests/ui/argument-suggestions/issue-99482.stderr +++ b/tests/ui/argument-suggestions/issue-99482.stderr @@ -2,7 +2,7 @@ error[E0057]: this function takes 2 arguments but 1 argument was supplied --> $DIR/issue-99482.rs:3:14 | LL | let _f = f(main); - | ^ ---- an argument of type `()` is missing + | ^ ---- argument #1 of type `()` is missing | note: closure defined here --> $DIR/issue-99482.rs:2:13 diff --git a/tests/ui/argument-suggestions/missing_arguments.stderr b/tests/ui/argument-suggestions/missing_arguments.stderr index ba9ece040bec..3a27a51d0320 100644 --- a/tests/ui/argument-suggestions/missing_arguments.stderr +++ b/tests/ui/argument-suggestions/missing_arguments.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing_arguments.rs:10:3 | LL | one_arg(); - | ^^^^^^^-- an argument of type `i32` is missing + | ^^^^^^^-- argument #1 of type `i32` is missing | note: function defined here --> $DIR/missing_arguments.rs:1:4 @@ -34,7 +34,7 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/missing_arguments.rs:15:3 | LL | two_same( 1 ); - | ^^^^^^^^----------------- an argument of type `i32` is missing + | ^^^^^^^^----------------- argument #2 of type `i32` is missing | note: function defined here --> $DIR/missing_arguments.rs:2:4 @@ -66,7 +66,7 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/missing_arguments.rs:17:3 | LL | two_diff( 1 ); - | ^^^^^^^^----------------- an argument of type `f32` is missing + | ^^^^^^^^----------------- argument #2 of type `f32` is missing | note: function defined here --> $DIR/missing_arguments.rs:3:4 @@ -82,7 +82,7 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/missing_arguments.rs:18:3 | LL | two_diff( 1.0 ); - | ^^^^^^^^ --- an argument of type `i32` is missing + | ^^^^^^^^ --- argument #1 of type `i32` is missing | note: function defined here --> $DIR/missing_arguments.rs:3:4 @@ -130,7 +130,7 @@ error[E0061]: this function takes 3 arguments but 2 arguments were supplied --> $DIR/missing_arguments.rs:23:3 | LL | three_same( 1, 1 ); - | ^^^^^^^^^^------------------------- an argument of type `i32` is missing + | ^^^^^^^^^^------------------------- argument #3 of type `i32` is missing | note: function defined here --> $DIR/missing_arguments.rs:4:4 @@ -146,7 +146,7 @@ error[E0061]: this function takes 3 arguments but 2 arguments were supplied --> $DIR/missing_arguments.rs:26:3 | LL | three_diff( 1.0, "" ); - | ^^^^^^^^^^ --- an argument of type `i32` is missing + | ^^^^^^^^^^ --- argument #1 of type `i32` is missing | note: function defined here --> $DIR/missing_arguments.rs:5:4 @@ -162,7 +162,7 @@ error[E0061]: this function takes 3 arguments but 2 arguments were supplied --> $DIR/missing_arguments.rs:27:3 | LL | three_diff( 1, "" ); - | ^^^^^^^^^^ -- an argument of type `f32` is missing + | ^^^^^^^^^^ -- argument #2 of type `f32` is missing | note: function defined here --> $DIR/missing_arguments.rs:5:4 @@ -178,7 +178,7 @@ error[E0061]: this function takes 3 arguments but 2 arguments were supplied --> $DIR/missing_arguments.rs:28:3 | LL | three_diff( 1, 1.0 ); - | ^^^^^^^^^^------------------------- an argument of type `&str` is missing + | ^^^^^^^^^^------------------------- argument #3 of type `&str` is missing | note: function defined here --> $DIR/missing_arguments.rs:5:4 @@ -212,8 +212,8 @@ error[E0061]: this function takes 3 arguments but 1 argument was supplied LL | three_diff( 1.0 ); | ^^^^^^^^^^------------------------- | | | - | | an argument of type `i32` is missing - | an argument of type `&str` is missing + | | argument #1 of type `i32` is missing + | argument #3 of type `&str` is missing | note: function defined here --> $DIR/missing_arguments.rs:5:4 diff --git a/tests/ui/argument-suggestions/mixed_cases.stderr b/tests/ui/argument-suggestions/mixed_cases.stderr index c645dd381792..bec5d4dc16ba 100644 --- a/tests/ui/argument-suggestions/mixed_cases.stderr +++ b/tests/ui/argument-suggestions/mixed_cases.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/mixed_cases.rs:10:3 | LL | two_args(1, "", X {}); - | ^^^^^^^^ -- ---- unexpected argument of type `X` + | ^^^^^^^^ -- ---- unexpected argument #3 of type `X` | | | expected `f32`, found `&str` | @@ -21,10 +21,10 @@ error[E0061]: this function takes 3 arguments but 4 arguments were supplied --> $DIR/mixed_cases.rs:11:3 | LL | three_args(1, "", X {}, ""); - | ^^^^^^^^^^ -- ---- -- unexpected argument of type `&'static str` + | ^^^^^^^^^^ -- ---- -- unexpected argument #4 of type `&'static str` | | | - | | unexpected argument of type `X` - | an argument of type `f32` is missing + | | unexpected argument #3 of type `X` + | argument #2 of type `f32` is missing | note: function defined here --> $DIR/mixed_cases.rs:6:4 @@ -43,7 +43,7 @@ LL | three_args(1, X {}); | ^^^^^^^^^^--------- | | | | | expected `f32`, found `X` - | an argument of type `&str` is missing + | argument #3 of type `&str` is missing | note: function defined here --> $DIR/mixed_cases.rs:6:4 @@ -59,9 +59,9 @@ error[E0308]: arguments to this function are incorrect --> $DIR/mixed_cases.rs:17:3 | LL | three_args(1, "", X {}); - | ^^^^^^^^^^ -- ---- unexpected argument of type `X` + | ^^^^^^^^^^ -- ---- unexpected argument #3 of type `X` | | - | an argument of type `f32` is missing + | argument #2 of type `f32` is missing | note: function defined here --> $DIR/mixed_cases.rs:6:4 @@ -98,7 +98,7 @@ error[E0061]: this function takes 3 arguments but 2 arguments were supplied LL | three_args("", 1); | ^^^^^^^^^^ -- - | | | - | | an argument of type `f32` is missing + | | argument #2 of type `f32` is missing | | expected `&str`, found `{integer}` | expected `i32`, found `&'static str` | diff --git a/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr index dc293945eb60..730f20cfb88e 100644 --- a/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr +++ b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr @@ -32,7 +32,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/suggest-better-removing-issue-126246.rs:10:5 | LL | add_one(2, 2); - | ^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^ - unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/suggest-better-removing-issue-126246.rs:1:4 @@ -49,7 +49,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/suggest-better-removing-issue-126246.rs:11:5 | LL | add_one(no_such_local, 10); - | ^^^^^^^ ------------- unexpected argument + | ^^^^^^^ ------------- unexpected argument #1 | note: function defined here --> $DIR/suggest-better-removing-issue-126246.rs:1:4 @@ -66,7 +66,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/suggest-better-removing-issue-126246.rs:13:5 | LL | add_one(10, no_such_local); - | ^^^^^^^ ------------- unexpected argument + | ^^^^^^^ ------------- unexpected argument #2 | note: function defined here --> $DIR/suggest-better-removing-issue-126246.rs:1:4 @@ -83,7 +83,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/suggest-better-removing-issue-126246.rs:15:5 | LL | add_two(10, no_such_local, 10); - | ^^^^^^^ ------------- unexpected argument + | ^^^^^^^ ------------- unexpected argument #2 | note: function defined here --> $DIR/suggest-better-removing-issue-126246.rs:5:4 @@ -100,7 +100,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/suggest-better-removing-issue-126246.rs:17:5 | LL | add_two(no_such_local, 10, 10); - | ^^^^^^^ ------------- unexpected argument + | ^^^^^^^ ------------- unexpected argument #1 | note: function defined here --> $DIR/suggest-better-removing-issue-126246.rs:5:4 @@ -117,7 +117,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/suggest-better-removing-issue-126246.rs:19:5 | LL | add_two(10, 10, no_such_local); - | ^^^^^^^ ------------- unexpected argument + | ^^^^^^^ ------------- unexpected argument #3 | note: function defined here --> $DIR/suggest-better-removing-issue-126246.rs:5:4 diff --git a/tests/ui/associated-inherent-types/issue-109768.stderr b/tests/ui/associated-inherent-types/issue-109768.stderr index e960f4fb5d17..e71551f9e732 100644 --- a/tests/ui/associated-inherent-types/issue-109768.stderr +++ b/tests/ui/associated-inherent-types/issue-109768.stderr @@ -34,7 +34,7 @@ error[E0061]: this struct takes 1 argument but 0 arguments were supplied --> $DIR/issue-109768.rs:10:56 | LL | const WRAPPED_ASSOC_3: Wrapper = Wrapper(); - | ^^^^^^^-- an argument is missing + | ^^^^^^^-- argument #1 is missing | note: tuple struct defined here --> $DIR/issue-109768.rs:3:8 diff --git a/tests/ui/c-variadic/variadic-ffi-1.stderr b/tests/ui/c-variadic/variadic-ffi-1.stderr index 4beea83d8a52..72d60a1439af 100644 --- a/tests/ui/c-variadic/variadic-ffi-1.stderr +++ b/tests/ui/c-variadic/variadic-ffi-1.stderr @@ -24,7 +24,7 @@ error[E0060]: this function takes at least 2 arguments but 1 argument was suppli --> $DIR/variadic-ffi-1.rs:23:9 | LL | foo(1); - | ^^^--- an argument of type `u8` is missing + | ^^^--- argument #2 of type `u8` is missing | note: function defined here --> $DIR/variadic-ffi-1.rs:15:8 diff --git a/tests/ui/cast/ice-cast-type-with-error-124848.stderr b/tests/ui/cast/ice-cast-type-with-error-124848.stderr index 2d86bf76d110..1e2adcc7d9ee 100644 --- a/tests/ui/cast/ice-cast-type-with-error-124848.stderr +++ b/tests/ui/cast/ice-cast-type-with-error-124848.stderr @@ -39,7 +39,7 @@ error[E0061]: this struct takes 2 arguments but 1 argument was supplied --> $DIR/ice-cast-type-with-error-124848.rs:12:24 | LL | let mut unpinned = MyType(Cell::new(None)); - | ^^^^^^----------------- an argument is missing + | ^^^^^^----------------- argument #2 is missing | note: tuple struct defined here --> $DIR/ice-cast-type-with-error-124848.rs:7:8 diff --git a/tests/ui/coroutine/issue-102645.stderr b/tests/ui/coroutine/issue-102645.stderr index ab5e4a8459f4..1ef37d3f7d10 100644 --- a/tests/ui/coroutine/issue-102645.stderr +++ b/tests/ui/coroutine/issue-102645.stderr @@ -2,7 +2,7 @@ error[E0061]: this method takes 1 argument but 0 arguments were supplied --> $DIR/issue-102645.rs:15:22 | LL | Pin::new(&mut b).resume(); - | ^^^^^^-- an argument of type `()` is missing + | ^^^^^^-- argument #1 of type `()` is missing | note: method defined here --> $SRC_DIR/core/src/ops/coroutine.rs:LL:COL diff --git a/tests/ui/error-codes/E0057.stderr b/tests/ui/error-codes/E0057.stderr index efd2af6d609b..ef6e2908b939 100644 --- a/tests/ui/error-codes/E0057.stderr +++ b/tests/ui/error-codes/E0057.stderr @@ -2,7 +2,7 @@ error[E0057]: this function takes 1 argument but 0 arguments were supplied --> $DIR/E0057.rs:3:13 | LL | let a = f(); - | ^-- an argument is missing + | ^-- argument #1 is missing | note: closure defined here --> $DIR/E0057.rs:2:13 @@ -18,7 +18,7 @@ error[E0057]: this function takes 1 argument but 2 arguments were supplied --> $DIR/E0057.rs:5:13 | LL | let c = f(2, 3); - | ^ - unexpected argument of type `{integer}` + | ^ - unexpected argument #2 of type `{integer}` | note: closure defined here --> $DIR/E0057.rs:2:13 diff --git a/tests/ui/error-codes/E0060.stderr b/tests/ui/error-codes/E0060.stderr index 88c1f1bbb2a5..8387b15b9708 100644 --- a/tests/ui/error-codes/E0060.stderr +++ b/tests/ui/error-codes/E0060.stderr @@ -2,7 +2,7 @@ error[E0060]: this function takes at least 1 argument but 0 arguments were suppl --> $DIR/E0060.rs:6:14 | LL | unsafe { printf(); } - | ^^^^^^-- an argument of type `*const u8` is missing + | ^^^^^^-- argument #1 of type `*const u8` is missing | note: function defined here --> $DIR/E0060.rs:2:8 diff --git a/tests/ui/error-codes/E0061.stderr b/tests/ui/error-codes/E0061.stderr index fa4ccbe6677c..7b180c071208 100644 --- a/tests/ui/error-codes/E0061.stderr +++ b/tests/ui/error-codes/E0061.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/E0061.rs:6:5 | LL | f(0); - | ^--- an argument of type `&str` is missing + | ^--- argument #2 of type `&str` is missing | note: function defined here --> $DIR/E0061.rs:1:4 @@ -18,7 +18,7 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/E0061.rs:9:5 | LL | f2(); - | ^^-- an argument of type `u16` is missing + | ^^-- argument #1 of type `u16` is missing | note: function defined here --> $DIR/E0061.rs:3:4 diff --git a/tests/ui/extern/issue-18819.stderr b/tests/ui/extern/issue-18819.stderr index b2cf0bad1df6..6de0ebfe9aee 100644 --- a/tests/ui/extern/issue-18819.stderr +++ b/tests/ui/extern/issue-18819.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/issue-18819.rs:16:5 | LL | print_x(X); - | ^^^^^^^--- an argument of type `&str` is missing + | ^^^^^^^--- argument #2 of type `&str` is missing | note: expected `&dyn Foo`, found `X` --> $DIR/issue-18819.rs:16:13 diff --git a/tests/ui/fn/issue-3044.stderr b/tests/ui/fn/issue-3044.stderr index 06254775b74d..8351818dc897 100644 --- a/tests/ui/fn/issue-3044.stderr +++ b/tests/ui/fn/issue-3044.stderr @@ -5,7 +5,7 @@ LL | needlesArr.iter().fold(|x, y| { | _______________________^^^^- LL | | LL | | }); - | |______- an argument is missing + | |______- argument #2 is missing | note: method defined here --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL diff --git a/tests/ui/generic-associated-types/issue-91139.migrate.stderr b/tests/ui/generic-associated-types/issue-91139.migrate.stderr index 23b7bf45afbb..e3b658558e32 100644 --- a/tests/ui/generic-associated-types/issue-91139.migrate.stderr +++ b/tests/ui/generic-associated-types/issue-91139.migrate.stderr @@ -1,7 +1,6 @@ error: expected identifier, found `<<` --> $DIR/issue-91139.rs:1:1 | -LL | <<<<<<< HEAD | ^^ expected identifier error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/trait-bounds/issue-58451.stderr b/tests/ui/higher-ranked/trait-bounds/issue-58451.stderr index 99d088799fbd..34d7db9b3cf8 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-58451.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-58451.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/issue-58451.rs:12:9 | LL | f(&[f()]); - | ^-- an argument is missing + | ^-- argument #1 is missing | note: function defined here --> $DIR/issue-58451.rs:5:4 diff --git a/tests/ui/issues/issue-4935.stderr b/tests/ui/issues/issue-4935.stderr index f18cf66f14d0..7ee895d91c75 100644 --- a/tests/ui/issues/issue-4935.stderr +++ b/tests/ui/issues/issue-4935.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/issue-4935.rs:5:13 | LL | fn main() { foo(5, 6) } - | ^^^ - unexpected argument of type `{integer}` + | ^^^ - unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/issue-4935.rs:3:4 diff --git a/tests/ui/lifetimes/issue-26638.stderr b/tests/ui/lifetimes/issue-26638.stderr index 403a8c67ccb3..dc18e0f1f7a1 100644 --- a/tests/ui/lifetimes/issue-26638.stderr +++ b/tests/ui/lifetimes/issue-26638.stderr @@ -50,7 +50,7 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/issue-26638.rs:4:47 | LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() } - | ^^^^-- an argument of type `&u8` is missing + | ^^^^-- argument #1 of type `&u8` is missing | help: provide the argument | diff --git a/tests/ui/methods/method-call-err-msg.stderr b/tests/ui/methods/method-call-err-msg.stderr index 0855a17b3339..84005119a878 100644 --- a/tests/ui/methods/method-call-err-msg.stderr +++ b/tests/ui/methods/method-call-err-msg.stderr @@ -19,7 +19,7 @@ error[E0061]: this method takes 1 argument but 0 arguments were supplied --> $DIR/method-call-err-msg.rs:14:7 | LL | .one() - | ^^^-- an argument of type `isize` is missing + | ^^^-- argument #1 of type `isize` is missing | note: method defined here --> $DIR/method-call-err-msg.rs:6:8 @@ -35,7 +35,7 @@ error[E0061]: this method takes 2 arguments but 1 argument was supplied --> $DIR/method-call-err-msg.rs:15:7 | LL | .two(0); - | ^^^--- an argument of type `isize` is missing + | ^^^--- argument #2 of type `isize` is missing | note: method defined here --> $DIR/method-call-err-msg.rs:7:8 diff --git a/tests/ui/mismatched_types/overloaded-calls-bad.stderr b/tests/ui/mismatched_types/overloaded-calls-bad.stderr index cd483e7ad2c6..c52fa7136153 100644 --- a/tests/ui/mismatched_types/overloaded-calls-bad.stderr +++ b/tests/ui/mismatched_types/overloaded-calls-bad.stderr @@ -16,7 +16,7 @@ error[E0057]: this function takes 1 argument but 0 arguments were supplied --> $DIR/overloaded-calls-bad.rs:35:15 | LL | let ans = s(); - | ^-- an argument of type `isize` is missing + | ^-- argument #1 of type `isize` is missing | note: implementation defined here --> $DIR/overloaded-calls-bad.rs:10:1 @@ -32,7 +32,7 @@ error[E0057]: this function takes 1 argument but 2 arguments were supplied --> $DIR/overloaded-calls-bad.rs:37:15 | LL | let ans = s("burma", "shave"); - | ^ ------- ------- unexpected argument of type `&'static str` + | ^ ------- ------- unexpected argument #2 of type `&'static str` | | | expected `isize`, found `&str` | diff --git a/tests/ui/not-enough-arguments.stderr b/tests/ui/not-enough-arguments.stderr index 8b2dafb4e1d0..89e988666674 100644 --- a/tests/ui/not-enough-arguments.stderr +++ b/tests/ui/not-enough-arguments.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 4 arguments but 3 arguments were supplied --> $DIR/not-enough-arguments.rs:27:3 | LL | foo(1, 2, 3); - | ^^^--------- an argument of type `isize` is missing + | ^^^--------- argument #4 of type `isize` is missing | note: function defined here --> $DIR/not-enough-arguments.rs:5:4 diff --git a/tests/ui/span/issue-34264.stderr b/tests/ui/span/issue-34264.stderr index 89c67719b5ae..b581cdd0be24 100644 --- a/tests/ui/span/issue-34264.stderr +++ b/tests/ui/span/issue-34264.stderr @@ -54,7 +54,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:7:5 | LL | foo(Some(42), 2, ""); - | ^^^ -- unexpected argument of type `&'static str` + | ^^^ -- unexpected argument #3 of type `&'static str` | note: function defined here --> $DIR/issue-34264.rs:1:4 @@ -85,7 +85,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:10:5 | LL | bar(1, 2, 3); - | ^^^ - unexpected argument of type `{integer}` + | ^^^ - unexpected argument #3 of type `{integer}` | note: function defined here --> $DIR/issue-34264.rs:3:4 diff --git a/tests/ui/span/missing-unit-argument.stderr b/tests/ui/span/missing-unit-argument.stderr index ff89f7753341..79980f48ab6b 100644 --- a/tests/ui/span/missing-unit-argument.stderr +++ b/tests/ui/span/missing-unit-argument.stderr @@ -2,7 +2,7 @@ error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:11:33 | LL | let _: Result<(), String> = Ok(); - | ^^-- an argument of type `()` is missing + | ^^-- argument #1 of type `()` is missing | note: tuple variant defined here --> $SRC_DIR/core/src/result.rs:LL:COL @@ -31,7 +31,7 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/missing-unit-argument.rs:13:5 | LL | foo(()); - | ^^^---- an argument of type `()` is missing + | ^^^---- argument #2 of type `()` is missing | note: function defined here --> $DIR/missing-unit-argument.rs:1:4 @@ -47,7 +47,7 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:14:5 | LL | bar(); - | ^^^-- an argument of type `()` is missing + | ^^^-- argument #1 of type `()` is missing | note: function defined here --> $DIR/missing-unit-argument.rs:2:4 @@ -63,7 +63,7 @@ error[E0061]: this method takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:15:7 | LL | S.baz(); - | ^^^-- an argument of type `()` is missing + | ^^^-- argument #1 of type `()` is missing | note: method defined here --> $DIR/missing-unit-argument.rs:6:8 @@ -79,7 +79,7 @@ error[E0061]: this method takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:16:7 | LL | S.generic::<()>(); - | ^^^^^^^^^^^^^-- an argument of type `()` is missing + | ^^^^^^^^^^^^^-- argument #1 of type `()` is missing | note: method defined here --> $DIR/missing-unit-argument.rs:7:8 diff --git a/tests/ui/suggestions/args-instead-of-tuple-errors.stderr b/tests/ui/suggestions/args-instead-of-tuple-errors.stderr index 510b99bb5af7..1051a16b40d7 100644 --- a/tests/ui/suggestions/args-instead-of-tuple-errors.stderr +++ b/tests/ui/suggestions/args-instead-of-tuple-errors.stderr @@ -2,7 +2,7 @@ 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); - | ^^^^ - unexpected argument of type `{integer}` + | ^^^^ - unexpected argument #2 of type `{integer}` | note: expected `(i32, bool)`, found integer --> $DIR/args-instead-of-tuple-errors.rs:6:39 @@ -30,7 +30,7 @@ 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); - | ^^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^^ - unexpected argument #2 of type `{integer}` | note: expected `(i32, bool)`, found integer --> $DIR/args-instead-of-tuple-errors.rs:8:14 @@ -54,7 +54,7 @@ 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(); - | ^^^^-- an argument of type `(i8,)` is missing + | ^^^^-- argument #1 of type `(i8,)` is missing | note: tuple variant defined here --> $SRC_DIR/core/src/option.rs:LL:COL diff --git a/tests/ui/suggestions/args-instead-of-tuple.stderr b/tests/ui/suggestions/args-instead-of-tuple.stderr index 0bdf10b0d63a..3ca560f93eb7 100644 --- a/tests/ui/suggestions/args-instead-of-tuple.stderr +++ b/tests/ui/suggestions/args-instead-of-tuple.stderr @@ -28,7 +28,7 @@ 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(); - | ^^^^-- an argument of type `()` is missing + | ^^^^-- argument #1 of type `()` is missing | note: tuple variant defined here --> $SRC_DIR/core/src/option.rs:LL:COL diff --git a/tests/ui/suggestions/issue-109396.stderr b/tests/ui/suggestions/issue-109396.stderr index d4956872a399..5419e8240c59 100644 --- a/tests/ui/suggestions/issue-109396.stderr +++ b/tests/ui/suggestions/issue-109396.stderr @@ -11,14 +11,14 @@ LL | let mut mutex = std::mem::zeroed( | ^^^^^^^^^^^^^^^^ LL | LL | file.as_raw_fd(), - | ---------------- unexpected argument + | ---------------- unexpected argument #1 LL | LL | 0, - | - unexpected argument of type `{integer}` + | - unexpected argument #2 of type `{integer}` LL | 0, - | - unexpected argument of type `{integer}` + | - unexpected argument #3 of type `{integer}` LL | 0, - | - unexpected argument of type `{integer}` + | - unexpected argument #4 of type `{integer}` | note: function defined here --> $SRC_DIR/core/src/mem/mod.rs:LL:COL diff --git a/tests/ui/suggestions/issue-109854.stderr b/tests/ui/suggestions/issue-109854.stderr index 52444cd4c45a..d9cbbe37d461 100644 --- a/tests/ui/suggestions/issue-109854.stderr +++ b/tests/ui/suggestions/issue-109854.stderr @@ -7,9 +7,9 @@ LL | String::with_capacity( LL | / r#" LL | | pub(crate) struct Person {} LL | | "#, - | |__- unexpected argument of type `&'static str` + | |__- unexpected argument #2 of type `&'static str` LL | r#""#, - | ----- unexpected argument of type `&'static str` + | ----- unexpected argument #3 of type `&'static str` | note: expected `usize`, found fn item --> $DIR/issue-109854.rs:4:5 diff --git a/tests/ui/tuple/wrong_argument_ice-3.stderr b/tests/ui/tuple/wrong_argument_ice-3.stderr index ce21751f39d2..78212ed1e769 100644 --- a/tests/ui/tuple/wrong_argument_ice-3.stderr +++ b/tests/ui/tuple/wrong_argument_ice-3.stderr @@ -2,7 +2,7 @@ error[E0061]: this method takes 1 argument but 2 arguments were supplied --> $DIR/wrong_argument_ice-3.rs:9:16 | LL | groups.push(new_group, vec![process]); - | ^^^^ ------------- unexpected argument of type `Vec<&Process>` + | ^^^^ ------------- unexpected argument #2 of type `Vec<&Process>` | note: expected `(Vec, Vec)`, found `Vec` --> $DIR/wrong_argument_ice-3.rs:9:21 diff --git a/tests/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr b/tests/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr index db75a520c658..371f5b10988a 100644 --- a/tests/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr +++ b/tests/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr @@ -2,7 +2,7 @@ error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:21:5 | LL | ::V(); - | ^^^^^^-- an argument of type `u8` is missing + | ^^^^^^-- argument #1 of type `u8` is missing | note: tuple variant defined here --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:5:5 diff --git a/tests/ui/type/type-ascription-instead-of-initializer.stderr b/tests/ui/type/type-ascription-instead-of-initializer.stderr index 224ff6e74048..630e82d254ee 100644 --- a/tests/ui/type/type-ascription-instead-of-initializer.stderr +++ b/tests/ui/type/type-ascription-instead-of-initializer.stderr @@ -11,7 +11,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/type-ascription-instead-of-initializer.rs:2:12 | LL | let x: Vec::with_capacity(10, 20); - | ^^^^^^^^^^^^^^^^^^ -- unexpected argument of type `{integer}` + | ^^^^^^^^^^^^^^^^^^ -- unexpected argument #2 of type `{integer}` | note: associated function defined here --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL diff --git a/tests/ui/type/type-check/point-at-inference-4.rs b/tests/ui/type/type-check/point-at-inference-4.rs index 3deb234c2751..5745b7385327 100644 --- a/tests/ui/type/type-check/point-at-inference-4.rs +++ b/tests/ui/type/type-check/point-at-inference-4.rs @@ -13,7 +13,7 @@ fn main() { //~^ ERROR this method takes 2 arguments but 1 argument was supplied //~| NOTE this argument has type `i32`... //~| NOTE ... which causes `s` to have type `S` - //~| NOTE an argument is missing + //~| NOTE argument #2 is missing //~| HELP provide the argument //~| HELP change the type of the numeric literal from `i32` to `u32` let t: S = s; diff --git a/tests/ui/type/type-check/point-at-inference-4.stderr b/tests/ui/type/type-check/point-at-inference-4.stderr index 5f7bb8b9367e..a953ca70ea27 100644 --- a/tests/ui/type/type-check/point-at-inference-4.stderr +++ b/tests/ui/type/type-check/point-at-inference-4.stderr @@ -2,7 +2,7 @@ error[E0061]: this method takes 2 arguments but 1 argument was supplied --> $DIR/point-at-inference-4.rs:12:7 | LL | s.infer(0i32); - | ^^^^^------ an argument is missing + | ^^^^^------ argument #2 is missing | note: method defined here --> $DIR/point-at-inference-4.rs:4:8 diff --git a/tests/ui/typeck/cyclic_type_ice.stderr b/tests/ui/typeck/cyclic_type_ice.stderr index bfff6830fc52..36715b4ee5d1 100644 --- a/tests/ui/typeck/cyclic_type_ice.stderr +++ b/tests/ui/typeck/cyclic_type_ice.stderr @@ -13,7 +13,7 @@ error[E0057]: this function takes 2 arguments but 1 argument was supplied --> $DIR/cyclic_type_ice.rs:3:5 | LL | f(f); - | ^--- an argument is missing + | ^--- argument #2 is missing | note: closure defined here --> $DIR/cyclic_type_ice.rs:2:13 diff --git a/tests/ui/typeck/remove-extra-argument.stderr b/tests/ui/typeck/remove-extra-argument.stderr index 4bab2959651b..d4e0dcb50aed 100644 --- a/tests/ui/typeck/remove-extra-argument.stderr +++ b/tests/ui/typeck/remove-extra-argument.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/remove-extra-argument.rs:6:5 | LL | l(vec![], vec![]) - | ^ ------ unexpected argument of type `Vec<_>` + | ^ ------ unexpected argument #2 of type `Vec<_>` | note: function defined here --> $DIR/remove-extra-argument.rs:3:4 diff --git a/tests/ui/typeck/struct-enum-wrong-args.stderr b/tests/ui/typeck/struct-enum-wrong-args.stderr index d005eca841ec..e58d162901e1 100644 --- a/tests/ui/typeck/struct-enum-wrong-args.stderr +++ b/tests/ui/typeck/struct-enum-wrong-args.stderr @@ -2,7 +2,7 @@ error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:6:13 | LL | let _ = Some(3, 2); - | ^^^^ - unexpected argument of type `{integer}` + | ^^^^ - unexpected argument #2 of type `{integer}` | note: tuple variant defined here --> $SRC_DIR/core/src/option.rs:LL:COL @@ -16,9 +16,9 @@ error[E0061]: this enum variant takes 1 argument but 3 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:7:13 | LL | let _ = Ok(3, 6, 2); - | ^^ - - unexpected argument of type `{integer}` + | ^^ - - unexpected argument #3 of type `{integer}` | | - | unexpected argument of type `{integer}` + | unexpected argument #2 of type `{integer}` | note: tuple variant defined here --> $SRC_DIR/core/src/result.rs:LL:COL @@ -32,7 +32,7 @@ error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:8:13 | LL | let _ = Ok(); - | ^^-- an argument is missing + | ^^-- argument #1 is missing | note: tuple variant defined here --> $SRC_DIR/core/src/result.rs:LL:COL @@ -45,7 +45,7 @@ error[E0061]: this struct takes 1 argument but 0 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:9:13 | LL | let _ = Wrapper(); - | ^^^^^^^-- an argument of type `i32` is missing + | ^^^^^^^-- argument #1 of type `i32` is missing | note: tuple struct defined here --> $DIR/struct-enum-wrong-args.rs:2:8 @@ -61,7 +61,7 @@ error[E0061]: this struct takes 1 argument but 2 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:10:13 | LL | let _ = Wrapper(5, 2); - | ^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^ - unexpected argument #2 of type `{integer}` | note: tuple struct defined here --> $DIR/struct-enum-wrong-args.rs:2:8 @@ -94,7 +94,7 @@ error[E0061]: this struct takes 2 arguments but 1 argument was supplied --> $DIR/struct-enum-wrong-args.rs:12:13 | LL | let _ = DoubleWrapper(5); - | ^^^^^^^^^^^^^--- an argument of type `i32` is missing + | ^^^^^^^^^^^^^--- argument #2 of type `i32` is missing | note: tuple struct defined here --> $DIR/struct-enum-wrong-args.rs:3:8 @@ -110,7 +110,7 @@ error[E0061]: this struct takes 2 arguments but 3 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:13:13 | LL | let _ = DoubleWrapper(5, 2, 7); - | ^^^^^^^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^^^^^^^ - unexpected argument #3 of type `{integer}` | note: tuple struct defined here --> $DIR/struct-enum-wrong-args.rs:3:8 From b90ee2a51a66371702cab6a007a4efc862ff0544 Mon Sep 17 00:00:00 2001 From: klensy Date: Sun, 14 Jul 2024 13:48:29 +0300 Subject: [PATCH 123/734] reenable some windows tests --- tests/codegen/generic-debug.rs | 1 - tests/codegen/issues/issue-58881.rs | 1 - tests/codegen/mainsubprogram.rs | 1 - tests/codegen/mainsubprogramstart.rs | 1 - tests/codegen/nounwind.rs | 1 - 5 files changed, 5 deletions(-) diff --git a/tests/codegen/generic-debug.rs b/tests/codegen/generic-debug.rs index 3423abe7187b..0ad0b0746570 100644 --- a/tests/codegen/generic-debug.rs +++ b/tests/codegen/generic-debug.rs @@ -1,4 +1,3 @@ -//@ ignore-windows //@ ignore-wasi wasi codegens the main symbol differently //@ compile-flags: -g -C no-prepopulate-passes diff --git a/tests/codegen/issues/issue-58881.rs b/tests/codegen/issues/issue-58881.rs index 759e3b70baa1..ba6285f3972e 100644 --- a/tests/codegen/issues/issue-58881.rs +++ b/tests/codegen/issues/issue-58881.rs @@ -1,7 +1,6 @@ //@ compile-flags: -C no-prepopulate-passes -Copt-level=0 // //@ only-x86_64 -//@ ignore-windows #![crate_type = "lib"] diff --git a/tests/codegen/mainsubprogram.rs b/tests/codegen/mainsubprogram.rs index 12b24c90229e..ce3fe3c86080 100644 --- a/tests/codegen/mainsubprogram.rs +++ b/tests/codegen/mainsubprogram.rs @@ -1,7 +1,6 @@ // This test depends on a patch that was committed to upstream LLVM // before 4.0, formerly backported to the Rust LLVM fork. -//@ ignore-windows //@ ignore-apple //@ ignore-wasi diff --git a/tests/codegen/mainsubprogramstart.rs b/tests/codegen/mainsubprogramstart.rs index 20741791db5c..0bcb311644d0 100644 --- a/tests/codegen/mainsubprogramstart.rs +++ b/tests/codegen/mainsubprogramstart.rs @@ -1,4 +1,3 @@ -//@ ignore-windows //@ ignore-apple //@ ignore-wasi wasi codegens the main symbol differently diff --git a/tests/codegen/nounwind.rs b/tests/codegen/nounwind.rs index 464bc2535c2b..c910644458aa 100644 --- a/tests/codegen/nounwind.rs +++ b/tests/codegen/nounwind.rs @@ -1,6 +1,5 @@ //@ aux-build:nounwind.rs //@ compile-flags: -C no-prepopulate-passes -C panic=abort -C metadata=a -//@ ignore-windows //@ ignore-android #![crate_type = "lib"] From e13eb37eeb3ccb447f33496fe86d77498558d2d5 Mon Sep 17 00:00:00 2001 From: Gurinder Singh Date: Sun, 14 Jul 2024 17:46:25 +0530 Subject: [PATCH 124/734] Fix malformed suggestion for repeated maybe unsized bounds --- compiler/rustc_hir/src/hir.rs | 24 ++- compiler/rustc_middle/src/ty/diagnostics.rs | 69 +++++-- ...tionf-for-repeated-unsized-bound-127441.rs | 39 ++++ ...f-for-repeated-unsized-bound-127441.stderr | 192 ++++++++++++++++++ 4 files changed, 295 insertions(+), 29 deletions(-) create mode 100644 tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs create mode 100644 tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index d57fad6ba4c2..0f1b2bec6c64 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -723,7 +723,7 @@ impl<'hir> Generics<'hir> { ) } - fn span_for_predicate_removal(&self, pos: usize) -> Span { + pub fn span_for_predicate_removal(&self, pos: usize) -> Span { let predicate = &self.predicates[pos]; let span = predicate.span(); @@ -766,15 +766,21 @@ impl<'hir> Generics<'hir> { return self.span_for_predicate_removal(predicate_pos); } - let span = bounds[bound_pos].span(); - if bound_pos == 0 { - // where T: ?Sized + Bar, Foo: Bar, - // ^^^^^^^^^ - span.to(bounds[1].span().shrink_to_lo()) + let bound_span = bounds[bound_pos].span(); + if bound_pos < bounds.len() - 1 { + // If there's another bound after the current bound + // include the following '+' e.g.: + // + // `T: Foo + CurrentBound + Bar` + // ^^^^^^^^^^^^^^^ + bound_span.to(bounds[bound_pos + 1].span().shrink_to_lo()) } else { - // where T: Bar + ?Sized, Foo: Bar, - // ^^^^^^^^^ - bounds[bound_pos - 1].span().shrink_to_hi().to(span) + // If the current bound is the last bound + // include the preceding '+' E.g.: + // + // `T: Foo + Bar + CurrentBound` + // ^^^^^^^^^^^^^^^ + bound_span.with_lo(bounds[bound_pos - 1].span().hi()) } } } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 4bf223379913..3a5cb22be388 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -188,31 +188,60 @@ fn suggest_changing_unsized_bound( continue; }; - for (pos, bound) in predicate.bounds.iter().enumerate() { - let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound else { - continue; - }; - if poly.trait_ref.trait_def_id() != def_id { - continue; - } - if predicate.origin == PredicateOrigin::ImplTrait && predicate.bounds.len() == 1 { - // For `impl ?Sized` with no other bounds, suggest `impl Sized` instead. - let bound_span = bound.span(); - if bound_span.can_be_used_for_suggestions() { - let question_span = bound_span.with_hi(bound_span.lo() + BytePos(1)); - suggestions.push(( + let unsized_bounds = predicate + .bounds + .iter() + .enumerate() + .filter(|(_, bound)| { + if let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound + && poly.trait_ref.trait_def_id() == def_id + { + true + } else { + false + } + }) + .collect::>(); + + if unsized_bounds.is_empty() { + continue; + } + + let mut push_suggestion = |sp, msg| suggestions.push((sp, String::new(), msg)); + + if predicate.bounds.len() == unsized_bounds.len() { + // All the bounds are unsized bounds, e.g. + // `T: ?Sized + ?Sized` or `_: impl ?Sized + ?Sized`, + // so in this case: + // - if it's an impl trait predicate suggest changing the + // the first bound to sized and removing the rest + // - Otherwise simply suggest removing the entire predicate + if predicate.origin == PredicateOrigin::ImplTrait { + let first_bound = unsized_bounds[0].1; + let first_bound_span = first_bound.span(); + if first_bound_span.can_be_used_for_suggestions() { + let question_span = + first_bound_span.with_hi(first_bound_span.lo() + BytePos(1)); + push_suggestion( question_span, - String::new(), SuggestChangingConstraintsMessage::ReplaceMaybeUnsizedWithSized, - )); + ); + + for (pos, _) in unsized_bounds.iter().skip(1) { + let sp = generics.span_for_bound_removal(where_pos, *pos); + push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized); + } } } else { + let sp = generics.span_for_predicate_removal(where_pos); + push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized); + } + } else { + // Some of the bounds are other than unsized. + // So push separate removal suggestion for each unsized bound + for (pos, _) in unsized_bounds { let sp = generics.span_for_bound_removal(where_pos, pos); - suggestions.push(( - sp, - String::new(), - SuggestChangingConstraintsMessage::RemoveMaybeUnsized, - )); + push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized); } } } diff --git a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs b/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs new file mode 100644 index 000000000000..e6d7f74880fb --- /dev/null +++ b/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs @@ -0,0 +1,39 @@ +// Regression test for #127441 + +// Tests that we make the correct suggestion +// in case there are more than one `?Sized` +// bounds on a function parameter + +use std::fmt::Debug; + +fn foo1(a: T) {} +//~^ ERROR he size for values of type `T` cannot be known at compilation time + +fn foo2(a: T) {} +//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~| ERROR the size for values of type `T` cannot be known at compilation time + +fn foo3(a: T) {} +//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~| ERROR he size for values of type `T` cannot be known at compilation time + +fn foo4(a: T) {} +//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~| ERROR the size for values of type `T` cannot be known at compilation time + +fn foo5(_: impl ?Sized) {} +//~^ ERROR the size for values of type `impl ?Sized` cannot be known at compilation time + +fn foo6(_: impl ?Sized + ?Sized) {} +//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~| ERROR the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation tim + +fn foo7(_: impl ?Sized + ?Sized + Debug) {} +//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~| ERROR the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time + +fn foo8(_: impl ?Sized + Debug + ?Sized ) {} +//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~| ERROR the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time + +fn main() {} diff --git a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr b/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr new file mode 100644 index 000000000000..3e8f45ee9fc2 --- /dev/null +++ b/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr @@ -0,0 +1,192 @@ +error[E0203]: type parameter has more than one relaxed default bound, only one is supported + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:12 + | +LL | fn foo2(a: T) {} + | ^^^^^^ ^^^^^^ + +error[E0203]: type parameter has more than one relaxed default bound, only one is supported + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:12 + | +LL | fn foo3(a: T) {} + | ^^^^^^ ^^^^^^ + +error[E0203]: type parameter has more than one relaxed default bound, only one is supported + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:12 + | +LL | fn foo4(a: T) {} + | ^^^^^^ ^^^^^^ + +error[E0203]: type parameter has more than one relaxed default bound, only one is supported + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:17 + | +LL | fn foo6(_: impl ?Sized + ?Sized) {} + | ^^^^^^ ^^^^^^ + +error[E0203]: type parameter has more than one relaxed default bound, only one is supported + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:17 + | +LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {} + | ^^^^^^ ^^^^^^ + +error[E0203]: type parameter has more than one relaxed default bound, only one is supported + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:17 + | +LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {} + | ^^^^^^ ^^^^^^ + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:9:20 + | +LL | fn foo1(a: T) {} + | - ^ doesn't have a size known at compile-time + | | + | this type parameter needs to be `Sized` + | + = help: unsized fn params are gated as an unstable feature +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn foo1(a: T) {} +LL + fn foo1(a: T) {} + | +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo1(a: &T) {} + | + + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:29 + | +LL | fn foo2(a: T) {} + | - ^ doesn't have a size known at compile-time + | | + | this type parameter needs to be `Sized` + | + = help: unsized fn params are gated as an unstable feature +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn foo2(a: T) {} +LL + fn foo2(a: T) {} + | +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo2(a: &T) {} + | + + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:37 + | +LL | fn foo3(a: T) {} + | - ^ doesn't have a size known at compile-time + | | + | this type parameter needs to be `Sized` + | + = help: unsized fn params are gated as an unstable feature +help: consider restricting type parameters + | +LL - fn foo3(a: T) {} +LL + fn foo3(a: T) {} + | +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo3(a: &T) {} + | + + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:38 + | +LL | fn foo4(a: T) {} + | - ^ doesn't have a size known at compile-time + | | + | this type parameter needs to be `Sized` + | + = help: unsized fn params are gated as an unstable feature +help: consider restricting type parameters + | +LL - fn foo4(a: T) {} +LL + fn foo4(a: T) {} + | +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo4(a: &T) {} + | + + +error[E0277]: the size for values of type `impl ?Sized` cannot be known at compilation time + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:24:9 + | +LL | fn foo5(_: impl ?Sized) {} + | ^ ----------- this type parameter needs to be `Sized` + | | + | doesn't have a size known at compile-time + | + = help: unsized fn params are gated as an unstable feature +help: consider replacing `?Sized` with `Sized` + | +LL - fn foo5(_: impl ?Sized) {} +LL + fn foo5(_: impl Sized) {} + | +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo5(_: &impl ?Sized) {} + | + + +error[E0277]: the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation time + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:9 + | +LL | fn foo6(_: impl ?Sized + ?Sized) {} + | ^ -------------------- this type parameter needs to be `Sized` + | | + | doesn't have a size known at compile-time + | + = help: unsized fn params are gated as an unstable feature +help: consider restricting type parameters + | +LL - fn foo6(_: impl ?Sized + ?Sized) {} +LL + fn foo6(_: impl Sized) {} + | +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo6(_: &impl ?Sized + ?Sized) {} + | + + +error[E0277]: the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:9 + | +LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {} + | ^ ---------------------------- this type parameter needs to be `Sized` + | | + | doesn't have a size known at compile-time + | + = help: unsized fn params are gated as an unstable feature +help: consider restricting type parameters + | +LL - fn foo7(_: impl ?Sized + ?Sized + Debug) {} +LL + fn foo7(_: impl Debug) {} + | +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo7(_: &impl ?Sized + ?Sized + Debug) {} + | + + +error[E0277]: the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:9 + | +LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {} + | ^ ---------------------------- this type parameter needs to be `Sized` + | | + | doesn't have a size known at compile-time + | + = help: unsized fn params are gated as an unstable feature +help: consider restricting type parameters + | +LL - fn foo8(_: impl ?Sized + Debug + ?Sized ) {} +LL + fn foo8(_: impl Debug ) {} + | +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo8(_: &impl ?Sized + Debug + ?Sized ) {} + | + + +error: aborting due to 14 previous errors + +Some errors have detailed explanations: E0203, E0277. +For more information about an error, try `rustc --explain E0203`. From 185f4b06a7d04255834aecbaa4f1fd33b0db04f1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 14 Jul 2024 14:52:36 -0400 Subject: [PATCH 125/734] Fix trivial gen ident usage in tools --- clippy_lints/src/misc_early/mod.rs | 4 ++-- clippy_lints/src/trait_bounds.rs | 20 ++++++++++---------- clippy_lints/src/types/type_complexity.rs | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index fedcfd11fdcc..4cba13a05c24 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -364,8 +364,8 @@ declare_lint_pass!(MiscEarlyLints => [ ]); impl EarlyLintPass for MiscEarlyLints { - fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) { - for param in &gen.params { + fn check_generics(&mut self, cx: &EarlyContext<'_>, generics: &Generics) { + for param in &generics.params { builtin_type_shadow::check(cx, param); } } diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index c05cd9ed5934..07390d6f4302 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -102,9 +102,9 @@ impl TraitBounds { impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS, TRAIT_DUPLICATION_IN_BOUNDS]); impl<'tcx> LateLintPass<'tcx> for TraitBounds { - fn check_generics(&mut self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) { - self.check_type_repetition(cx, gen); - check_trait_bound_duplication(cx, gen); + fn check_generics(&mut self, cx: &LateContext<'tcx>, generics: &'tcx Generics<'_>) { + self.check_type_repetition(cx, generics); + check_trait_bound_duplication(cx, generics); } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { @@ -238,7 +238,7 @@ impl TraitBounds { } #[allow(clippy::mutable_key_type)] - fn check_type_repetition<'tcx>(&self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) { + fn check_type_repetition<'tcx>(&self, cx: &LateContext<'tcx>, generics: &'tcx Generics<'_>) { struct SpanlessTy<'cx, 'tcx> { ty: &'tcx Ty<'tcx>, cx: &'cx LateContext<'tcx>, @@ -258,12 +258,12 @@ impl TraitBounds { } impl Eq for SpanlessTy<'_, '_> {} - if gen.span.from_expansion() { + if generics.span.from_expansion() { return; } let mut map: UnhashMap, Vec<&GenericBound<'_>>> = UnhashMap::default(); let mut applicability = Applicability::MaybeIncorrect; - for bound in gen.predicates { + for bound in generics.predicates { if let WherePredicate::BoundPredicate(ref p) = bound && p.origin != PredicateOrigin::ImplTrait && p.bounds.len() as u64 <= self.max_trait_bounds @@ -301,8 +301,8 @@ impl TraitBounds { } } -fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { - if gen.span.from_expansion() { +fn check_trait_bound_duplication(cx: &LateContext<'_>, generics: &'_ Generics<'_>) { + if generics.span.from_expansion() { return; } @@ -313,7 +313,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { // | // collects each of these where clauses into a set keyed by generic name and comparable trait // eg. (T, Clone) - let where_predicates = gen + let where_predicates = generics .predicates .iter() .filter_map(|pred| { @@ -342,7 +342,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { // | // compare trait bounds keyed by generic name and comparable trait to collected where // predicates eg. (T, Clone) - for predicate in gen.predicates.iter().filter(|pred| !pred.in_where_clause()) { + for predicate in generics.predicates.iter().filter(|pred| !pred.in_where_clause()) { if let WherePredicate::BoundPredicate(bound_predicate) = predicate && bound_predicate.origin != PredicateOrigin::ImplTrait && !bound_predicate.span.from_expansion() diff --git a/clippy_lints/src/types/type_complexity.rs b/clippy_lints/src/types/type_complexity.rs index 0aa50c99c169..b6e765d7c393 100644 --- a/clippy_lints/src/types/type_complexity.rs +++ b/clippy_lints/src/types/type_complexity.rs @@ -57,7 +57,7 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor { bound .bound_generic_params .iter() - .any(|gen| matches!(gen.kind, GenericParamKind::Lifetime { .. })) + .any(|param| matches!(param.kind, GenericParamKind::Lifetime { .. })) }); if has_lifetime_parameters { // complex trait bounds like A<'a, 'b> From eb3cc5f824d74eb50ad1bdb3105045bd8eb135ef Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 14 Jul 2024 22:02:13 -0700 Subject: [PATCH 126/734] Use Option's discriminant as its size hint --- library/core/src/option.rs | 24 +++++++++++++++------- tests/codegen/option-as-slice.rs | 35 +++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 8ec7716012f5..1a8fe1e6051a 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -770,6 +770,13 @@ impl Option { } } + #[inline] + const fn len(&self) -> usize { + // Using the intrinsic avoids emitting a branch to get the 0 or 1. + let discriminant: isize = crate::intrinsics::discriminant_value(self); + discriminant as usize + } + /// Returns a slice of the contained value, if any. If this is `None`, an /// empty slice is returned. This can be useful to have a single type of /// iterator over an `Option` or slice. @@ -812,7 +819,7 @@ impl Option { unsafe { slice::from_raw_parts( (self as *const Self).byte_add(core::mem::offset_of!(Self, Some.0)).cast(), - self.is_some() as usize, + self.len(), ) } } @@ -869,7 +876,7 @@ impl Option { unsafe { slice::from_raw_parts_mut( (self as *mut Self).byte_add(core::mem::offset_of!(Self, Some.0)).cast(), - self.is_some() as usize, + self.len(), ) } } @@ -2242,10 +2249,8 @@ impl Iterator for Item { #[inline] fn size_hint(&self) -> (usize, Option) { - match self.opt { - Some(_) => (1, Some(1)), - None => (0, Some(0)), - } + let len = self.len(); + (len, Some(len)) } } @@ -2256,7 +2261,12 @@ impl DoubleEndedIterator for Item { } } -impl ExactSizeIterator for Item {} +impl ExactSizeIterator for Item { + #[inline] + fn len(&self) -> usize { + self.opt.len() + } +} impl FusedIterator for Item {} unsafe impl TrustedLen for Item {} diff --git a/tests/codegen/option-as-slice.rs b/tests/codegen/option-as-slice.rs index 65637a2495d0..cfa479aa4b2f 100644 --- a/tests/codegen/option-as-slice.rs +++ b/tests/codegen/option-as-slice.rs @@ -14,6 +14,14 @@ pub fn u64_opt_as_slice(o: &Option) -> &[u64] { // CHECK-NOT: br // CHECK-NOT: switch // CHECK-NOT: icmp + // CHECK: %[[LEN:.+]] = load i64,{{.+}} !range ![[META_U64:.+]], !noundef + // CHECK-NOT: select + // CHECK-NOT: br + // CHECK-NOT: switch + // CHECK-NOT: icmp + // CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %{{.+}}, 0 + // CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1 + // CHECK-NEXT: ret { ptr, i64 } %[[T1]] o.as_slice() } @@ -25,10 +33,35 @@ pub fn nonzero_u64_opt_as_slice(o: &Option>) -> &[NonZero] { // CHECK-NOT: switch // CHECK-NOT: icmp // CHECK: %[[NZ:.+]] = icmp ne i64 %{{.+}}, 0 - // CHECK-NEXT: zext i1 %[[NZ]] to i64 + // CHECK-NEXT: %[[LEN:.+]] = zext i1 %[[NZ]] to i64 // CHECK-NOT: select // CHECK-NOT: br // CHECK-NOT: switch // CHECK-NOT: icmp + // CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %o, 0 + // CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1 + // CHECK-NEXT: ret { ptr, i64 } %[[T1]] o.as_slice() } + +// CHECK-LABEL: @u8_opt_as_slice +#[no_mangle] +pub fn u8_opt_as_slice(o: &Option) -> &[u8] { + // CHECK-NOT: select + // CHECK-NOT: br + // CHECK-NOT: switch + // CHECK-NOT: icmp + // CHECK: %[[TAG:.+]] = load i8,{{.+}} !range ![[META_U8:.+]], !noundef + // CHECK: %[[LEN:.+]] = zext{{.*}} i8 %[[TAG]] to i64 + // CHECK-NOT: select + // CHECK-NOT: br + // CHECK-NOT: switch + // CHECK-NOT: icmp + // CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %{{.+}}, 0 + // CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1 + // CHECK-NEXT: ret { ptr, i64 } %[[T1]] + o.as_slice() +} + +// CHECK: ![[META_U64]] = !{i64 0, i64 2} +// CHECK: ![[META_U8]] = !{i8 0, i8 2} From 636ddcb099b76294f2727c2c1a176d694cd9bd80 Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Mon, 15 Jul 2024 10:15:52 +0200 Subject: [PATCH 127/734] Ignore allocation bytes in one more mir-opt test Following on PR #126502, add `rustc -Zdump-mir-exclude-alloc-bytes` to tests/mir-opt/dataflow-const-prop/aggregate_copy.rs as well to skip writing allocation bytes in MIR dumps. Fixes #126261 --- .../aggregate_copy.foo.DataflowConstProp.diff | 6 ++---- tests/mir-opt/dataflow-const-prop/aggregate_copy.rs | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff index 1aeaaff21dce..3b739a25cb86 100644 --- a/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff +++ b/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff @@ -57,9 +57,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 05 00 00 00 03 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs b/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs index aca5f047222f..9cd485813bc9 100644 --- a/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs +++ b/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs @@ -1,6 +1,7 @@ //! Verify that we manage to propagate the value of aggregate `a` even without directly mentioning //! the contained scalars. //@ test-mir-pass: DataflowConstProp +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes const Foo: (u32, u32) = (5, 3); From 3b390d416d06be695f2bef2f5ed85b15f5d2fef2 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 15 Jul 2024 08:44:02 +0000 Subject: [PATCH 128/734] Bump clippy version --- Cargo.toml | 2 +- tests/compile-test.rs | 5 +- .../index_refutable_slice.fixed | 24 - .../index_refutable_slice.rs | 2 + .../index_refutable_slice.stderr | 2 +- tests/ui/crashes/ice-3717.fixed | 11 - tests/ui/crashes/ice-3717.rs | 2 + tests/ui/crashes/ice-3717.stderr | 2 +- tests/ui/derivable_impls.fixed | 295 --------- tests/ui/derivable_impls.rs | 2 + tests/ui/derivable_impls.stderr | 16 +- .../if_let_slice_binding.fixed | 177 ------ .../if_let_slice_binding.rs | 2 + .../if_let_slice_binding.stderr | 20 +- .../slice_indexing_in_macro.fixed | 29 - .../slice_indexing_in_macro.rs | 2 + .../slice_indexing_in_macro.stderr | 2 +- tests/ui/let_unit.fixed | 196 ------ tests/ui/let_unit.rs | 2 + tests/ui/let_unit.stderr | 8 +- tests/ui/manual_assert.edition2018.fixed | 76 --- tests/ui/manual_assert.edition2018.stderr | 20 +- tests/ui/manual_assert.edition2021.fixed | 76 --- tests/ui/manual_assert.edition2021.stderr | 20 +- tests/ui/manual_assert.rs | 2 + tests/ui/manual_async_fn.fixed | 115 ---- tests/ui/manual_async_fn.rs | 2 + tests/ui/manual_async_fn.stderr | 26 +- tests/ui/manual_split_once.fixed | 144 ----- tests/ui/manual_split_once.rs | 2 + tests/ui/manual_split_once.stderr | 38 +- tests/ui/match_same_arms2.fixed | 258 -------- tests/ui/match_same_arms2.rs | 3 + tests/ui/match_same_arms2.stderr | 30 +- tests/ui/significant_drop_tightening.fixed | 144 ----- tests/ui/significant_drop_tightening.rs | 2 + tests/ui/significant_drop_tightening.stderr | 8 +- tests/ui/unnecessary_iter_cloned.fixed | 201 ------ tests/ui/unnecessary_iter_cloned.rs | 2 + tests/ui/unnecessary_iter_cloned.stderr | 10 +- tests/ui/unnecessary_to_owned.fixed | 587 ------------------ tests/ui/unnecessary_to_owned.rs | 2 + tests/ui/unnecessary_to_owned.stderr | 224 +++---- 43 files changed, 244 insertions(+), 2549 deletions(-) delete mode 100644 tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed delete mode 100644 tests/ui/crashes/ice-3717.fixed delete mode 100644 tests/ui/derivable_impls.fixed delete mode 100644 tests/ui/index_refutable_slice/if_let_slice_binding.fixed delete mode 100644 tests/ui/index_refutable_slice/slice_indexing_in_macro.fixed delete mode 100644 tests/ui/let_unit.fixed delete mode 100644 tests/ui/manual_assert.edition2018.fixed delete mode 100644 tests/ui/manual_assert.edition2021.fixed delete mode 100644 tests/ui/manual_async_fn.fixed delete mode 100644 tests/ui/manual_split_once.fixed delete mode 100644 tests/ui/match_same_arms2.fixed delete mode 100644 tests/ui/significant_drop_tightening.fixed delete mode 100644 tests/ui/unnecessary_iter_cloned.fixed delete mode 100644 tests/ui/unnecessary_to_owned.fixed diff --git a/Cargo.toml b/Cargo.toml index 437884990551..5e52fd7e57ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ color-print = "0.3.4" anstream = "0.6.0" [dev-dependencies] -ui_test = "0.23" +ui_test = "0.24" regex = "1.5.5" toml = "0.7.3" walkdir = "2.3" diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 333a2ab58575..e8c7cd1bc417 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -5,7 +5,7 @@ use ui_test::custom_flags::rustfix::RustfixMode; use ui_test::spanned::Spanned; -use ui_test::{status_emitter, Args, CommandBuilder, Config, Match, Mode, OutputConflictHandling}; +use ui_test::{status_emitter, Args, CommandBuilder, Config, Match, OutputConflictHandling}; use std::collections::BTreeMap; use std::env::{self, set_var, var_os}; @@ -122,7 +122,8 @@ fn base_config(test_dir: &str) -> (Config, Args) { out_dir: target_dir.join("ui_test"), ..Config::rustc(Path::new("tests").join(test_dir)) }; - config.comment_defaults.base().mode = Some(Spanned::dummy(Mode::Yolo)).into(); + config.comment_defaults.base().exit_status = None.into(); + config.comment_defaults.base().require_annotations = None.into(); config .comment_defaults .base() diff --git a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed deleted file mode 100644 index 36540bf1dcf7..000000000000 --- a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed +++ /dev/null @@ -1,24 +0,0 @@ -#![deny(clippy::index_refutable_slice)] - -fn below_limit() { - let slice: Option<&[u32]> = Some(&[1, 2, 3]); - if let Some([_, _, _, _, _, _, _, slice_7, ..]) = slice { - //~^ ERROR: binding can be a slice pattern - // This would usually not be linted but is included now due to the - // index limit in the config file - println!("{}", slice_7); - } -} - -fn above_limit() { - let slice: Option<&[u32]> = Some(&[1, 2, 3]); - if let Some(slice) = slice { - // This will not be linted as 8 is above the limit - println!("{}", slice[8]); - } -} - -fn main() { - below_limit(); - above_limit(); -} diff --git a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs index da76bb20fd96..e64c8ff32900 100644 --- a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs +++ b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs @@ -1,5 +1,7 @@ #![deny(clippy::index_refutable_slice)] +//@no-rustfix: need to change the suggestion to a multipart suggestion + fn below_limit() { let slice: Option<&[u32]> = Some(&[1, 2, 3]); if let Some(slice) = slice { diff --git a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr index 0b989e5cf064..3ea600c7d7b0 100644 --- a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr +++ b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr @@ -1,5 +1,5 @@ error: this binding can be a slice pattern to avoid indexing - --> tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs:5:17 + --> tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs:7:17 | LL | if let Some(slice) = slice { | ^^^^^ diff --git a/tests/ui/crashes/ice-3717.fixed b/tests/ui/crashes/ice-3717.fixed deleted file mode 100644 index 3f54b326979c..000000000000 --- a/tests/ui/crashes/ice-3717.fixed +++ /dev/null @@ -1,11 +0,0 @@ -#![deny(clippy::implicit_hasher)] - -use std::collections::HashSet; - -fn main() {} - -pub fn ice_3717(_: &HashSet) { - //~^ ERROR: parameter of type `HashSet` should be generalized over different hashers - let _ = [0u8; 0]; - let _: HashSet = HashSet::default(); -} diff --git a/tests/ui/crashes/ice-3717.rs b/tests/ui/crashes/ice-3717.rs index 2890a9277c71..770f6cf448a6 100644 --- a/tests/ui/crashes/ice-3717.rs +++ b/tests/ui/crashes/ice-3717.rs @@ -1,5 +1,7 @@ #![deny(clippy::implicit_hasher)] +//@no-rustfix: need to change the suggestion to a multipart suggestion + use std::collections::HashSet; fn main() {} diff --git a/tests/ui/crashes/ice-3717.stderr b/tests/ui/crashes/ice-3717.stderr index 54b18a9641af..01627ff5b94b 100644 --- a/tests/ui/crashes/ice-3717.stderr +++ b/tests/ui/crashes/ice-3717.stderr @@ -1,5 +1,5 @@ error: parameter of type `HashSet` should be generalized over different hashers - --> tests/ui/crashes/ice-3717.rs:7:21 + --> tests/ui/crashes/ice-3717.rs:9:21 | LL | pub fn ice_3717(_: &HashSet) { | ^^^^^^^^^^^^^^ diff --git a/tests/ui/derivable_impls.fixed b/tests/ui/derivable_impls.fixed deleted file mode 100644 index c85f384fd6eb..000000000000 --- a/tests/ui/derivable_impls.fixed +++ /dev/null @@ -1,295 +0,0 @@ -#![allow(dead_code)] - -use std::collections::HashMap; - -#[derive(Default)] -struct FooDefault<'a> { - a: bool, - b: i32, - c: u64, - d: Vec, - e: FooND1, - f: FooND2, - g: HashMap, - h: (i32, Vec), - i: [Vec; 3], - j: [i32; 5], - k: Option, - l: &'a [i32], -} - - -#[derive(Default)] -struct TupleDefault(bool, i32, u64); - - -struct FooND1 { - a: bool, -} - -impl std::default::Default for FooND1 { - fn default() -> Self { - Self { a: true } - } -} - -struct FooND2 { - a: i32, -} - -impl std::default::Default for FooND2 { - fn default() -> Self { - Self { a: 5 } - } -} - -struct FooNDNew { - a: bool, -} - -impl FooNDNew { - fn new() -> Self { - Self { a: true } - } -} - -impl Default for FooNDNew { - fn default() -> Self { - Self::new() - } -} - -struct FooNDVec(Vec); - -impl Default for FooNDVec { - fn default() -> Self { - Self(vec![5, 12]) - } -} - -#[derive(Default)] -struct StrDefault<'a>(&'a str); - - -#[derive(Default)] -struct AlreadyDerived(i32, bool); - -macro_rules! mac { - () => { - 0 - }; - ($e:expr) => { - struct X(u32); - impl Default for X { - fn default() -> Self { - Self($e) - } - } - }; -} - -mac!(0); - -#[derive(Default)] -struct Y(u32); - -struct RustIssue26925 { - a: Option, -} - -// We should watch out for cases where a manual impl is needed because a -// derive adds different type bounds (https://github.com/rust-lang/rust/issues/26925). -// For example, a struct with Option does not require T: Default, but a derive adds -// that type bound anyways. So until #26925 get fixed we should disable lint -// for the following case -impl Default for RustIssue26925 { - fn default() -> Self { - Self { a: None } - } -} - -struct SpecializedImpl { - a: A, - b: B, -} - -impl Default for SpecializedImpl { - fn default() -> Self { - Self { - a: T::default(), - b: T::default(), - } - } -} - -#[derive(Default)] -struct WithoutSelfCurly { - a: bool, -} - - -#[derive(Default)] -struct WithoutSelfParan(bool); - - -// https://github.com/rust-lang/rust-clippy/issues/7655 - -pub struct SpecializedImpl2 { - v: Vec, -} - -impl Default for SpecializedImpl2 { - fn default() -> Self { - Self { v: Vec::new() } - } -} - -// https://github.com/rust-lang/rust-clippy/issues/7654 - -pub struct Color { - pub r: u8, - pub g: u8, - pub b: u8, -} - -/// `#000000` -impl Default for Color { - fn default() -> Self { - Color { r: 0, g: 0, b: 0 } - } -} - -pub struct Color2 { - pub r: u8, - pub g: u8, - pub b: u8, -} - -impl Default for Color2 { - /// `#000000` - fn default() -> Self { - Self { r: 0, g: 0, b: 0 } - } -} - -#[derive(Default)] -pub struct RepeatDefault1 { - a: [i8; 32], -} - - -pub struct RepeatDefault2 { - a: [i8; 33], -} - -impl Default for RepeatDefault2 { - fn default() -> Self { - RepeatDefault2 { a: [0; 33] } - } -} - -// https://github.com/rust-lang/rust-clippy/issues/7753 - -pub enum IntOrString { - Int(i32), - String(String), -} - -impl Default for IntOrString { - fn default() -> Self { - IntOrString::Int(0) - } -} - -#[derive(Default)] -pub enum SimpleEnum { - Foo, - #[default] - Bar, -} - - -pub enum NonExhaustiveEnum { - Foo, - #[non_exhaustive] - Bar, -} - -impl Default for NonExhaustiveEnum { - fn default() -> Self { - NonExhaustiveEnum::Bar - } -} - -// https://github.com/rust-lang/rust-clippy/issues/10396 - -#[derive(Default)] -struct DefaultType; - -struct GenericType { - t: T, -} - -impl Default for GenericType { - fn default() -> Self { - Self { t: Default::default() } - } -} - -struct InnerGenericType { - t: T, -} - -impl Default for InnerGenericType { - fn default() -> Self { - Self { t: Default::default() } - } -} - -struct OtherGenericType { - inner: InnerGenericType, -} - -impl Default for OtherGenericType { - fn default() -> Self { - Self { - inner: Default::default(), - } - } -} - -mod issue10158 { - pub trait T {} - - #[derive(Default)] - pub struct S {} - impl T for S {} - - pub struct Outer { - pub inner: Box, - } - - impl Default for Outer { - fn default() -> Self { - Outer { - // Box::::default() adjusts to Box - inner: Box::::default(), - } - } - } -} - -mod issue11368 { - pub struct A { - a: u32, - } - - impl Default for A { - #[track_caller] - fn default() -> Self { - Self { a: 0 } - } - } -} - -fn main() {} diff --git a/tests/ui/derivable_impls.rs b/tests/ui/derivable_impls.rs index 21d73ba8b777..58f7771b6275 100644 --- a/tests/ui/derivable_impls.rs +++ b/tests/ui/derivable_impls.rs @@ -1,5 +1,7 @@ #![allow(dead_code)] +//@no-rustfix: need to change the suggestion to a multipart suggestion + use std::collections::HashMap; struct FooDefault<'a> { diff --git a/tests/ui/derivable_impls.stderr b/tests/ui/derivable_impls.stderr index 0adb422373d8..d3adfa60e10f 100644 --- a/tests/ui/derivable_impls.stderr +++ b/tests/ui/derivable_impls.stderr @@ -1,5 +1,5 @@ error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:20:1 + --> tests/ui/derivable_impls.rs:22:1 | LL | / impl std::default::Default for FooDefault<'_> { LL | | fn default() -> Self { @@ -20,7 +20,7 @@ LL | struct FooDefault<'a> { | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:41:1 + --> tests/ui/derivable_impls.rs:43:1 | LL | / impl std::default::Default for TupleDefault { LL | | fn default() -> Self { @@ -37,7 +37,7 @@ LL | struct TupleDefault(bool, i32, u64); | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:93:1 + --> tests/ui/derivable_impls.rs:95:1 | LL | / impl Default for StrDefault<'_> { LL | | fn default() -> Self { @@ -54,7 +54,7 @@ LL | struct StrDefault<'a>(&'a str); | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:119:1 + --> tests/ui/derivable_impls.rs:121:1 | LL | / impl Default for Y { LL | | fn default() -> Self { @@ -71,7 +71,7 @@ LL | struct Y(u32); | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:158:1 + --> tests/ui/derivable_impls.rs:160:1 | LL | / impl Default for WithoutSelfCurly { LL | | fn default() -> Self { @@ -88,7 +88,7 @@ LL | struct WithoutSelfCurly { | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:166:1 + --> tests/ui/derivable_impls.rs:168:1 | LL | / impl Default for WithoutSelfParan { LL | | fn default() -> Self { @@ -105,7 +105,7 @@ LL | struct WithoutSelfParan(bool); | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:216:1 + --> tests/ui/derivable_impls.rs:218:1 | LL | / impl Default for RepeatDefault1 { LL | | fn default() -> Self { @@ -122,7 +122,7 @@ LL | pub struct RepeatDefault1 { | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:250:1 + --> tests/ui/derivable_impls.rs:252:1 | LL | / impl Default for SimpleEnum { LL | | fn default() -> Self { diff --git a/tests/ui/index_refutable_slice/if_let_slice_binding.fixed b/tests/ui/index_refutable_slice/if_let_slice_binding.fixed deleted file mode 100644 index 13f0cbe9cc88..000000000000 --- a/tests/ui/index_refutable_slice/if_let_slice_binding.fixed +++ /dev/null @@ -1,177 +0,0 @@ -#![deny(clippy::index_refutable_slice)] -#![allow(clippy::uninlined_format_args)] - -enum SomeEnum { - One(T), - Two(T), - Three(T), - Four(T), -} - -fn lintable_examples() { - // Try with reference - let slice: Option<&[u32]> = Some(&[1, 2, 3]); - if let Some([slice_0, ..]) = slice { - //~^ ERROR: this binding can be a slice pattern to avoid indexing - println!("{}", slice_0); - } - - // Try with copy - let slice: Option<[u32; 3]> = Some([1, 2, 3]); - if let Some([slice_0, ..]) = slice { - //~^ ERROR: this binding can be a slice pattern to avoid indexing - println!("{}", slice_0); - } - - // Try with long slice and small indices - let slice: Option<[u32; 9]> = Some([1, 2, 3, 4, 5, 6, 7, 8, 9]); - if let Some([slice_0, _, slice_2, ..]) = slice { - //~^ ERROR: this binding can be a slice pattern to avoid indexing - println!("{}", slice_2); - println!("{}", slice_0); - } - - // Multiple bindings - let slice_wrapped: SomeEnum<[u32; 3]> = SomeEnum::One([5, 6, 7]); - if let SomeEnum::One([slice_0, ..]) | SomeEnum::Three([slice_0, ..]) = slice_wrapped { - //~^ ERROR: this binding can be a slice pattern to avoid indexing - println!("{}", slice_0); - } - - // Two lintable slices in one if let - let a_wrapped: SomeEnum<[u32; 3]> = SomeEnum::One([9, 5, 1]); - let b_wrapped: Option<[u32; 2]> = Some([4, 6]); - if let (SomeEnum::Three([_, _, a_2, ..]), Some([_, b_1, ..])) = (a_wrapped, b_wrapped) { - //~^ ERROR: this binding can be a slice pattern to avoid indexing - //~| ERROR: this binding can be a slice pattern to avoid indexing - println!("{} -> {}", a_2, b_1); - } - - // This requires the slice values to be borrowed as the slice values can only be - // borrowed and `String` doesn't implement copy - let slice: Option<[String; 2]> = Some([String::from("1"), String::from("2")]); - if let Some([_, ref slice_1, ..]) = slice { - //~^ ERROR: this binding can be a slice pattern to avoid indexing - println!("{:?}", slice_1); - } - println!("{:?}", slice); - - // This should not suggest using the `ref` keyword as the scrutinee is already - // a reference - let slice: Option<[String; 2]> = Some([String::from("1"), String::from("2")]); - if let Some([slice_0, ..]) = &slice { - //~^ ERROR: this binding can be a slice pattern to avoid indexing - println!("{:?}", slice_0); - } - println!("{:?}", slice); -} - -fn slice_index_above_limit() { - let slice: Option<&[u32]> = Some(&[1, 2, 3]); - - if let Some(slice) = slice { - // Would cause a panic, IDK - println!("{}", slice[7]); - } -} - -fn slice_is_used() { - let slice: Option<&[u32]> = Some(&[1, 2, 3]); - if let Some(slice) = slice { - println!("{:?}", slice.len()); - } - - let slice: Option<&[u32]> = Some(&[1, 2, 3]); - if let Some(slice) = slice { - println!("{:?}", slice.to_vec()); - } - - let opt: Option<[String; 2]> = Some([String::from("Hello"), String::from("world")]); - if let Some(slice) = opt { - if !slice.is_empty() { - println!("first: {}", slice[0]); - } - } -} - -/// The slice is used by an external function and should therefore not be linted -fn check_slice_as_arg() { - fn is_interesting(slice: &[T; 2]) -> bool { - !slice.is_empty() - } - - let slice_wrapped: Option<[String; 2]> = Some([String::from("Hello"), String::from("world")]); - if let Some(slice) = &slice_wrapped { - if is_interesting(slice) { - println!("This is interesting {}", slice[0]); - } - } - println!("{:?}", slice_wrapped); -} - -fn check_slice_in_struct() { - #[derive(Debug)] - struct Wrapper<'a> { - inner: Option<&'a [String]>, - is_awesome: bool, - } - - impl<'a> Wrapper<'a> { - fn is_super_awesome(&self) -> bool { - self.is_awesome - } - } - - let inner = &[String::from("New"), String::from("World")]; - let wrap = Wrapper { - inner: Some(inner), - is_awesome: true, - }; - - // Test 1: Field access - if let Some([slice_0, ..]) = wrap.inner { - //~^ ERROR: this binding can be a slice pattern to avoid indexing - if wrap.is_awesome { - println!("This is awesome! {}", slice_0); - } - } - - // Test 2: function access - if let Some([slice_0, ..]) = wrap.inner { - //~^ ERROR: this binding can be a slice pattern to avoid indexing - if wrap.is_super_awesome() { - println!("This is super awesome! {}", slice_0); - } - } - println!("Complete wrap: {:?}", wrap); -} - -/// This would be a nice additional feature to have in the future, but adding it -/// now would make the PR too large. This is therefore only a test that we don't -/// lint cases we can't make a reasonable suggestion for -fn mutable_slice_index() { - // Mut access - let mut slice: Option<[String; 1]> = Some([String::from("Penguin")]); - if let Some(ref mut slice) = slice { - slice[0] = String::from("Mr. Penguin"); - } - println!("Use after modification: {:?}", slice); - - // Mut access on reference - let mut slice: Option<[String; 1]> = Some([String::from("Cat")]); - if let Some(slice) = &mut slice { - slice[0] = String::from("Lord Meow Meow"); - } - println!("Use after modification: {:?}", slice); -} - -/// The lint will ignore bindings with sub patterns as it would be hard -/// to build correct suggestions for these instances :) -fn binding_with_sub_pattern() { - let slice: Option<&[u32]> = Some(&[1, 2, 3]); - if let Some(slice @ [_, _, _]) = slice { - println!("{:?}", slice[2]); - } -} - -fn main() {} diff --git a/tests/ui/index_refutable_slice/if_let_slice_binding.rs b/tests/ui/index_refutable_slice/if_let_slice_binding.rs index d8d38c167fa5..5bbdabcaad19 100644 --- a/tests/ui/index_refutable_slice/if_let_slice_binding.rs +++ b/tests/ui/index_refutable_slice/if_let_slice_binding.rs @@ -1,6 +1,8 @@ #![deny(clippy::index_refutable_slice)] #![allow(clippy::uninlined_format_args)] +//@no-rustfix: need to change the suggestion to a multipart suggestion + enum SomeEnum { One(T), Two(T), diff --git a/tests/ui/index_refutable_slice/if_let_slice_binding.stderr b/tests/ui/index_refutable_slice/if_let_slice_binding.stderr index 14e0f931f240..8819cb0e28bf 100644 --- a/tests/ui/index_refutable_slice/if_let_slice_binding.stderr +++ b/tests/ui/index_refutable_slice/if_let_slice_binding.stderr @@ -1,5 +1,5 @@ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:14:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:16:17 | LL | if let Some(slice) = slice { | ^^^^^ @@ -19,7 +19,7 @@ LL | println!("{}", slice_0); | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:21:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:23:17 | LL | if let Some(slice) = slice { | ^^^^^ @@ -34,7 +34,7 @@ LL | println!("{}", slice_0); | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:28:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:30:17 | LL | if let Some(slice) = slice { | ^^^^^ @@ -50,7 +50,7 @@ LL ~ println!("{}", slice_0); | error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:36:26 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:38:26 | LL | if let SomeEnum::One(slice) | SomeEnum::Three(slice) = slice_wrapped { | ^^^^^ @@ -65,7 +65,7 @@ LL | println!("{}", slice_0); | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:44:29 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:46:29 | LL | if let (SomeEnum::Three(a), Some(b)) = (a_wrapped, b_wrapped) { | ^ @@ -80,7 +80,7 @@ LL | println!("{} -> {}", a_2, b[1]); | ~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:44:38 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:46:38 | LL | if let (SomeEnum::Three(a), Some(b)) = (a_wrapped, b_wrapped) { | ^ @@ -95,7 +95,7 @@ LL | println!("{} -> {}", a[2], b_1); | ~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:53:21 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:55:21 | LL | if let Some(ref slice) = slice { | ^^^^^ @@ -110,7 +110,7 @@ LL | println!("{:?}", slice_1); | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:62:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:64:17 | LL | if let Some(slice) = &slice { | ^^^^^ @@ -125,7 +125,7 @@ LL | println!("{:?}", slice_0); | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:132:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:134:17 | LL | if let Some(slice) = wrap.inner { | ^^^^^ @@ -140,7 +140,7 @@ LL | println!("This is awesome! {}", slice_0); | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:140:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:142:17 | LL | if let Some(slice) = wrap.inner { | ^^^^^ diff --git a/tests/ui/index_refutable_slice/slice_indexing_in_macro.fixed b/tests/ui/index_refutable_slice/slice_indexing_in_macro.fixed deleted file mode 100644 index 72edc539f043..000000000000 --- a/tests/ui/index_refutable_slice/slice_indexing_in_macro.fixed +++ /dev/null @@ -1,29 +0,0 @@ -#![deny(clippy::index_refutable_slice)] - -extern crate if_chain; -use if_chain::if_chain; - -macro_rules! if_let_slice_macro { - () => { - // This would normally be linted - let slice: Option<&[u32]> = Some(&[1, 2, 3]); - if let Some(slice) = slice { - println!("{}", slice[0]); - } - }; -} - -fn main() { - // Don't lint this - if_let_slice_macro!(); - - // Do lint this - if_chain! { - let slice: Option<&[u32]> = Some(&[1, 2, 3]); - if let Some([slice_0, ..]) = slice; - //~^ ERROR: this binding can be a slice pattern to avoid indexing - then { - println!("{}", slice_0); - } - } -} diff --git a/tests/ui/index_refutable_slice/slice_indexing_in_macro.rs b/tests/ui/index_refutable_slice/slice_indexing_in_macro.rs index 7b474ba423b9..5d9fad488899 100644 --- a/tests/ui/index_refutable_slice/slice_indexing_in_macro.rs +++ b/tests/ui/index_refutable_slice/slice_indexing_in_macro.rs @@ -1,5 +1,7 @@ #![deny(clippy::index_refutable_slice)] +//@no-rustfix: need to change the suggestion to a multipart suggestion + extern crate if_chain; use if_chain::if_chain; diff --git a/tests/ui/index_refutable_slice/slice_indexing_in_macro.stderr b/tests/ui/index_refutable_slice/slice_indexing_in_macro.stderr index caccd0f9295e..69f0aaa97778 100644 --- a/tests/ui/index_refutable_slice/slice_indexing_in_macro.stderr +++ b/tests/ui/index_refutable_slice/slice_indexing_in_macro.stderr @@ -1,5 +1,5 @@ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/slice_indexing_in_macro.rs:23:21 + --> tests/ui/index_refutable_slice/slice_indexing_in_macro.rs:25:21 | LL | if let Some(slice) = slice; | ^^^^^ diff --git a/tests/ui/let_unit.fixed b/tests/ui/let_unit.fixed deleted file mode 100644 index 3456e274f6a4..000000000000 --- a/tests/ui/let_unit.fixed +++ /dev/null @@ -1,196 +0,0 @@ -#![warn(clippy::let_unit_value)] -#![allow(unused, clippy::no_effect, clippy::needless_late_init, path_statements)] - -macro_rules! let_and_return { - ($n:expr) => {{ - let ret = $n; - }}; -} - -fn main() { - println!("x"); - let _y = 1; // this is fine - let _z = ((), 1); // this as well - if true { - // do not lint this, since () is explicit - let _a = (); - let () = dummy(); - let () = (); - () = dummy(); - () = (); - let _a: () = (); - let _a: () = dummy(); - } - - consume_units_with_for_loop(); // should be fine as well - - multiline_sugg(); - - let_and_return!(()) // should be fine -} - -fn dummy() {} - -// Related to issue #1964 -fn consume_units_with_for_loop() { - // `for_let_unit` lint should not be triggered by consuming them using for loop. - let v = vec![(), (), ()]; - let mut count = 0; - for _ in v { - count += 1; - } - assert_eq!(count, 3); - - // Same for consuming from some other Iterator. - let (tx, rx) = ::std::sync::mpsc::channel(); - tx.send(()).unwrap(); - drop(tx); - - count = 0; - for _ in rx.iter() { - count += 1; - } - assert_eq!(count, 1); -} - -fn multiline_sugg() { - let v: Vec = vec![2]; - - v - .into_iter() - .map(|i| i * 2) - .filter(|i| i % 2 == 0) - .map(|_| ()) - .next() - .unwrap(); -} - -#[derive(Copy, Clone)] -pub struct ContainsUnit(()); // should be fine - -fn _returns_generic() { - fn f() -> T { - unimplemented!() - } - fn f2(_: T) -> U { - unimplemented!() - } - fn f3(x: T) -> T { - x - } - fn f5(x: bool) -> Option { - x.then(|| T::default()) - } - - let _: () = f(); - let x: () = f(); - - let _: () = f2(0i32); - let x: () = f2(0i32); - - let _: () = f3(()); - let x: () = f3(()); - - fn f4(mut x: Vec) -> T { - x.pop().unwrap() - } - let _: () = f4(vec![()]); - let x: () = f4(vec![()]); - - let _: () = { - let x = 5; - f2(x) - }; - - let _: () = if true { f() } else { f2(0) }; - let x: () = if true { f() } else { f2(0) }; - - match Some(0) { - None => f2(1), - Some(0) => f(), - Some(1) => f2(3), - Some(_) => (), - }; - - let _: () = f5(true).unwrap(); - - #[allow(clippy::let_unit_value)] - { - let x = f(); - let y; - let z; - match 0 { - 0 => { - y = f(); - z = f(); - }, - 1 => { - println!("test"); - y = f(); - z = f3(()); - }, - _ => panic!(), - } - - let x1; - let x2; - if true { - x1 = f(); - x2 = x1; - } else { - x2 = f(); - x1 = x2; - } - - let opt; - match f5(true) { - Some(x) => opt = x, - None => panic!(), - }; - - #[warn(clippy::let_unit_value)] - { - let _: () = x; - let _: () = y; - let _: () = z; - let _: () = x1; - let _: () = x2; - let _: () = opt; - } - } - - let () = f(); -} - -fn attributes() { - fn f() {} - - #[allow(clippy::let_unit_value)] - let _ = f(); - #[expect(clippy::let_unit_value)] - let _ = f(); -} - -async fn issue10433() { - let _pending: () = std::future::pending().await; -} - -pub async fn issue11502(a: ()) {} - -pub fn issue12594() { - fn returns_unit() {} - - fn returns_result(res: T) -> Result { - Ok(res) - } - - fn actual_test() { - // create first a unit value'd value - returns_unit(); - returns_result(()).unwrap(); - returns_result(()).unwrap(); - // make sure we replace only the first variable - let res = 1; - returns_result(res).unwrap(); - } -} diff --git a/tests/ui/let_unit.rs b/tests/ui/let_unit.rs index e2dafbcb7714..530103ffaf6e 100644 --- a/tests/ui/let_unit.rs +++ b/tests/ui/let_unit.rs @@ -1,6 +1,8 @@ #![warn(clippy::let_unit_value)] #![allow(unused, clippy::no_effect, clippy::needless_late_init, path_statements)] +//@no-rustfix: need to change the suggestion to a multipart suggestion + macro_rules! let_and_return { ($n:expr) => {{ let ret = $n; diff --git a/tests/ui/let_unit.stderr b/tests/ui/let_unit.stderr index 2f62c33c8873..6f149454af2d 100644 --- a/tests/ui/let_unit.stderr +++ b/tests/ui/let_unit.stderr @@ -1,5 +1,5 @@ error: this let-binding has unit value - --> tests/ui/let_unit.rs:11:5 + --> tests/ui/let_unit.rs:13:5 | LL | let _x = println!("x"); | ^^^^^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `println!("x");` @@ -8,7 +8,7 @@ LL | let _x = println!("x"); = help: to override `-D warnings` add `#[allow(clippy::let_unit_value)]` error: this let-binding has unit value - --> tests/ui/let_unit.rs:59:5 + --> tests/ui/let_unit.rs:61:5 | LL | / let _ = v LL | | .into_iter() @@ -31,7 +31,7 @@ LL + .unwrap(); | error: this let-binding has unit value - --> tests/ui/let_unit.rs:108:5 + --> tests/ui/let_unit.rs:110:5 | LL | / let x = match Some(0) { LL | | None => f2(1), @@ -52,7 +52,7 @@ LL + }; | error: this let-binding has unit value - --> tests/ui/let_unit.rs:189:9 + --> tests/ui/let_unit.rs:191:9 | LL | let res = returns_unit(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/manual_assert.edition2018.fixed b/tests/ui/manual_assert.edition2018.fixed deleted file mode 100644 index 758357808010..000000000000 --- a/tests/ui/manual_assert.edition2018.fixed +++ /dev/null @@ -1,76 +0,0 @@ -//@revisions: edition2018 edition2021 -//@[edition2018] edition:2018 -//@[edition2021] edition:2021 - -#![warn(clippy::manual_assert)] -#![allow(dead_code, unused_doc_comments)] -#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args, clippy::useless_vec)] - -macro_rules! one { - () => { - 1 - }; -} - -fn main() { - let a = vec![1, 2, 3]; - let c = Some(2); - if !a.is_empty() - && a.len() == 3 - && c.is_some() - && !a.is_empty() - && a.len() == 3 - && !a.is_empty() - && a.len() == 3 - && !a.is_empty() - && a.len() == 3 - { - panic!("qaqaq{:?}", a); - } - assert!(a.is_empty(), "qaqaq{:?}", a); - assert!(a.is_empty(), "qwqwq"); - if a.len() == 3 { - println!("qwq"); - println!("qwq"); - println!("qwq"); - } - if let Some(b) = c { - panic!("orz {}", b); - } - if a.len() == 3 { - panic!("qaqaq"); - } else { - println!("qwq"); - } - let b = vec![1, 2, 3]; - assert!(!b.is_empty(), "panic1"); - assert!(!(b.is_empty() && a.is_empty()), "panic2"); - assert!(!(a.is_empty() && !b.is_empty()), "panic3"); - assert!(!(b.is_empty() || a.is_empty()), "panic4"); - assert!(!(a.is_empty() || !b.is_empty()), "panic5"); - assert!(!a.is_empty(), "with expansion {}", one!()); - if a.is_empty() { - let _ = 0; - } else if a.len() == 1 { - panic!("panic6"); - } -} - -fn issue7730(a: u8) { - // Suggestion should preserve comment - // comment -/* this is a - multiline - comment */ -/// Doc comment -// comment after `panic!` -assert!(!(a > 2), "panic with comment"); -} - -fn issue12505() { - struct Foo(T); - - impl Foo { - const BAR: () = assert!(!(N == 0), ); - } -} diff --git a/tests/ui/manual_assert.edition2018.stderr b/tests/ui/manual_assert.edition2018.stderr index 1eebe1bfe177..004463720e26 100644 --- a/tests/ui/manual_assert.edition2018.stderr +++ b/tests/ui/manual_assert.edition2018.stderr @@ -1,5 +1,5 @@ error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:30:5 + --> tests/ui/manual_assert.rs:32:5 | LL | / if !a.is_empty() { LL | | panic!("qaqaq{:?}", a); @@ -10,7 +10,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::manual_assert)]` error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:33:5 + --> tests/ui/manual_assert.rs:35:5 | LL | / if !a.is_empty() { LL | | panic!("qwqwq"); @@ -18,7 +18,7 @@ LL | | } | |_____^ help: try instead: `assert!(a.is_empty(), "qwqwq");` error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:50:5 + --> tests/ui/manual_assert.rs:52:5 | LL | / if b.is_empty() { LL | | panic!("panic1"); @@ -26,7 +26,7 @@ LL | | } | |_____^ help: try instead: `assert!(!b.is_empty(), "panic1");` error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:53:5 + --> tests/ui/manual_assert.rs:55:5 | LL | / if b.is_empty() && a.is_empty() { LL | | panic!("panic2"); @@ -34,7 +34,7 @@ LL | | } | |_____^ help: try instead: `assert!(!(b.is_empty() && a.is_empty()), "panic2");` error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:56:5 + --> tests/ui/manual_assert.rs:58:5 | LL | / if a.is_empty() && !b.is_empty() { LL | | panic!("panic3"); @@ -42,7 +42,7 @@ LL | | } | |_____^ help: try instead: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");` error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:59:5 + --> tests/ui/manual_assert.rs:61:5 | LL | / if b.is_empty() || a.is_empty() { LL | | panic!("panic4"); @@ -50,7 +50,7 @@ LL | | } | |_____^ help: try instead: `assert!(!(b.is_empty() || a.is_empty()), "panic4");` error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:62:5 + --> tests/ui/manual_assert.rs:64:5 | LL | / if a.is_empty() || !b.is_empty() { LL | | panic!("panic5"); @@ -58,7 +58,7 @@ LL | | } | |_____^ help: try instead: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");` error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:65:5 + --> tests/ui/manual_assert.rs:67:5 | LL | / if a.is_empty() { LL | | panic!("with expansion {}", one!()) @@ -66,7 +66,7 @@ LL | | } | |_____^ help: try instead: `assert!(!a.is_empty(), "with expansion {}", one!());` error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:77:5 + --> tests/ui/manual_assert.rs:79:5 | LL | / if a > 2 { LL | | // comment @@ -83,7 +83,7 @@ LL | assert!(!(a > 2), "panic with comment"); | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:91:25 + --> tests/ui/manual_assert.rs:93:25 | LL | const BAR: () = if N == 0 { | _________________________^ diff --git a/tests/ui/manual_assert.edition2021.fixed b/tests/ui/manual_assert.edition2021.fixed deleted file mode 100644 index 758357808010..000000000000 --- a/tests/ui/manual_assert.edition2021.fixed +++ /dev/null @@ -1,76 +0,0 @@ -//@revisions: edition2018 edition2021 -//@[edition2018] edition:2018 -//@[edition2021] edition:2021 - -#![warn(clippy::manual_assert)] -#![allow(dead_code, unused_doc_comments)] -#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args, clippy::useless_vec)] - -macro_rules! one { - () => { - 1 - }; -} - -fn main() { - let a = vec![1, 2, 3]; - let c = Some(2); - if !a.is_empty() - && a.len() == 3 - && c.is_some() - && !a.is_empty() - && a.len() == 3 - && !a.is_empty() - && a.len() == 3 - && !a.is_empty() - && a.len() == 3 - { - panic!("qaqaq{:?}", a); - } - assert!(a.is_empty(), "qaqaq{:?}", a); - assert!(a.is_empty(), "qwqwq"); - if a.len() == 3 { - println!("qwq"); - println!("qwq"); - println!("qwq"); - } - if let Some(b) = c { - panic!("orz {}", b); - } - if a.len() == 3 { - panic!("qaqaq"); - } else { - println!("qwq"); - } - let b = vec![1, 2, 3]; - assert!(!b.is_empty(), "panic1"); - assert!(!(b.is_empty() && a.is_empty()), "panic2"); - assert!(!(a.is_empty() && !b.is_empty()), "panic3"); - assert!(!(b.is_empty() || a.is_empty()), "panic4"); - assert!(!(a.is_empty() || !b.is_empty()), "panic5"); - assert!(!a.is_empty(), "with expansion {}", one!()); - if a.is_empty() { - let _ = 0; - } else if a.len() == 1 { - panic!("panic6"); - } -} - -fn issue7730(a: u8) { - // Suggestion should preserve comment - // comment -/* this is a - multiline - comment */ -/// Doc comment -// comment after `panic!` -assert!(!(a > 2), "panic with comment"); -} - -fn issue12505() { - struct Foo(T); - - impl Foo { - const BAR: () = assert!(!(N == 0), ); - } -} diff --git a/tests/ui/manual_assert.edition2021.stderr b/tests/ui/manual_assert.edition2021.stderr index 1eebe1bfe177..004463720e26 100644 --- a/tests/ui/manual_assert.edition2021.stderr +++ b/tests/ui/manual_assert.edition2021.stderr @@ -1,5 +1,5 @@ error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:30:5 + --> tests/ui/manual_assert.rs:32:5 | LL | / if !a.is_empty() { LL | | panic!("qaqaq{:?}", a); @@ -10,7 +10,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::manual_assert)]` error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:33:5 + --> tests/ui/manual_assert.rs:35:5 | LL | / if !a.is_empty() { LL | | panic!("qwqwq"); @@ -18,7 +18,7 @@ LL | | } | |_____^ help: try instead: `assert!(a.is_empty(), "qwqwq");` error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:50:5 + --> tests/ui/manual_assert.rs:52:5 | LL | / if b.is_empty() { LL | | panic!("panic1"); @@ -26,7 +26,7 @@ LL | | } | |_____^ help: try instead: `assert!(!b.is_empty(), "panic1");` error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:53:5 + --> tests/ui/manual_assert.rs:55:5 | LL | / if b.is_empty() && a.is_empty() { LL | | panic!("panic2"); @@ -34,7 +34,7 @@ LL | | } | |_____^ help: try instead: `assert!(!(b.is_empty() && a.is_empty()), "panic2");` error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:56:5 + --> tests/ui/manual_assert.rs:58:5 | LL | / if a.is_empty() && !b.is_empty() { LL | | panic!("panic3"); @@ -42,7 +42,7 @@ LL | | } | |_____^ help: try instead: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");` error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:59:5 + --> tests/ui/manual_assert.rs:61:5 | LL | / if b.is_empty() || a.is_empty() { LL | | panic!("panic4"); @@ -50,7 +50,7 @@ LL | | } | |_____^ help: try instead: `assert!(!(b.is_empty() || a.is_empty()), "panic4");` error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:62:5 + --> tests/ui/manual_assert.rs:64:5 | LL | / if a.is_empty() || !b.is_empty() { LL | | panic!("panic5"); @@ -58,7 +58,7 @@ LL | | } | |_____^ help: try instead: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");` error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:65:5 + --> tests/ui/manual_assert.rs:67:5 | LL | / if a.is_empty() { LL | | panic!("with expansion {}", one!()) @@ -66,7 +66,7 @@ LL | | } | |_____^ help: try instead: `assert!(!a.is_empty(), "with expansion {}", one!());` error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:77:5 + --> tests/ui/manual_assert.rs:79:5 | LL | / if a > 2 { LL | | // comment @@ -83,7 +83,7 @@ LL | assert!(!(a > 2), "panic with comment"); | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:91:25 + --> tests/ui/manual_assert.rs:93:25 | LL | const BAR: () = if N == 0 { | _________________________^ diff --git a/tests/ui/manual_assert.rs b/tests/ui/manual_assert.rs index 363bafdf05d0..6337920a3eea 100644 --- a/tests/ui/manual_assert.rs +++ b/tests/ui/manual_assert.rs @@ -2,6 +2,8 @@ //@[edition2018] edition:2018 //@[edition2021] edition:2021 +//@no-rustfix: need to change the suggestion to a multipart suggestion + #![warn(clippy::manual_assert)] #![allow(dead_code, unused_doc_comments)] #![allow(clippy::nonminimal_bool, clippy::uninlined_format_args, clippy::useless_vec)] diff --git a/tests/ui/manual_async_fn.fixed b/tests/ui/manual_async_fn.fixed deleted file mode 100644 index 18444090a426..000000000000 --- a/tests/ui/manual_async_fn.fixed +++ /dev/null @@ -1,115 +0,0 @@ -#![warn(clippy::manual_async_fn)] -#![allow(clippy::needless_pub_self, unused)] - -use std::future::Future; - -async fn fut() -> i32 { 42 } - -#[rustfmt::skip] -async fn fut2() -> i32 { 42 } - -#[rustfmt::skip] -async fn fut3() -> i32 { 42 } - -async fn empty_fut() {} - -#[rustfmt::skip] -async fn empty_fut2() {} - -#[rustfmt::skip] -async fn empty_fut3() {} - -async fn core_fut() -> i32 { 42 } - -// should be ignored -fn has_other_stmts() -> impl core::future::Future { - let _ = 42; - async move { 42 } -} - -// should be ignored -fn not_fut() -> i32 { - 42 -} - -// should be ignored -async fn already_async() -> impl Future { - async { 42 } -} - -struct S; -impl S { - async fn inh_fut() -> i32 { - // NOTE: this code is here just to check that the indentation is correct in the suggested fix - let a = 42; - let b = 21; - if a < b { - let c = 21; - let d = 42; - if c < d { - let _ = 42; - } - } - 42 - } - - // should be ignored - fn not_fut(&self) -> i32 { - 42 - } - - // should be ignored - fn has_other_stmts() -> impl core::future::Future { - let _ = 42; - async move { 42 } - } - - // should be ignored - async fn already_async(&self) -> impl Future { - async { 42 } - } -} - -// Tests related to lifetime capture - -async fn elided(_: &i32) -> i32 { 42 } - -// should be ignored -fn elided_not_bound(_: &i32) -> impl Future { - async { 42 } -} - -async fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> i32 { 42 } - -// should be ignored -#[allow(clippy::needless_lifetimes)] -fn explicit_not_bound<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future { - async { 42 } -} - -// should be ignored -mod issue_5765 { - use std::future::Future; - - struct A; - impl A { - fn f(&self) -> impl Future { - async {} - } - } - - fn test() { - let _future = { - let a = A; - a.f() - }; - } -} - -pub async fn issue_10450() -> i32 { 42 } - -pub(crate) async fn issue_10450_2() -> i32 { 42 } - -pub(self) async fn issue_10450_3() -> i32 { 42 } - -fn main() {} diff --git a/tests/ui/manual_async_fn.rs b/tests/ui/manual_async_fn.rs index d42165bbe3d8..6b8ac5033a92 100644 --- a/tests/ui/manual_async_fn.rs +++ b/tests/ui/manual_async_fn.rs @@ -1,6 +1,8 @@ #![warn(clippy::manual_async_fn)] #![allow(clippy::needless_pub_self, unused)] +//@no-rustfix: need to change the suggestion to a multipart suggestion + use std::future::Future; fn fut() -> impl Future { diff --git a/tests/ui/manual_async_fn.stderr b/tests/ui/manual_async_fn.stderr index c50af5a49883..f88fc30b3b54 100644 --- a/tests/ui/manual_async_fn.stderr +++ b/tests/ui/manual_async_fn.stderr @@ -1,5 +1,5 @@ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:6:1 + --> tests/ui/manual_async_fn.rs:8:1 | LL | fn fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | fn fut() -> impl Future { 42 } | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:11:1 + --> tests/ui/manual_async_fn.rs:13:1 | LL | fn fut2() ->impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | fn fut2() ->impl Future { 42 } | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:16:1 + --> tests/ui/manual_async_fn.rs:18:1 | LL | fn fut3()-> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -46,7 +46,7 @@ LL | fn fut3()-> impl Future { 42 } | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:20:1 + --> tests/ui/manual_async_fn.rs:22:1 | LL | fn empty_fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL | fn empty_fut() -> impl Future {} | ~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:25:1 + --> tests/ui/manual_async_fn.rs:27:1 | LL | fn empty_fut2() ->impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -76,7 +76,7 @@ LL | fn empty_fut2() ->impl Future {} | ~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:30:1 + --> tests/ui/manual_async_fn.rs:32:1 | LL | fn empty_fut3()-> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -91,7 +91,7 @@ LL | fn empty_fut3()-> impl Future {} | ~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:34:1 + --> tests/ui/manual_async_fn.rs:36:1 | LL | fn core_fut() -> impl core::future::Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,7 +106,7 @@ LL | fn core_fut() -> impl core::future::Future { 42 } | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:56:5 + --> tests/ui/manual_async_fn.rs:58:5 | LL | fn inh_fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL + } | error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:91:1 + --> tests/ui/manual_async_fn.rs:93:1 | LL | fn elided(_: &i32) -> impl Future + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -148,7 +148,7 @@ LL | fn elided(_: &i32) -> impl Future + '_ { 42 } | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:100:1 + --> tests/ui/manual_async_fn.rs:102:1 | LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -163,7 +163,7 @@ LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:129:1 + --> tests/ui/manual_async_fn.rs:131:1 | LL | pub fn issue_10450() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -178,7 +178,7 @@ LL | pub fn issue_10450() -> impl Future { 42 } | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:133:1 + --> tests/ui/manual_async_fn.rs:135:1 | LL | pub(crate) fn issue_10450_2() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -193,7 +193,7 @@ LL | pub(crate) fn issue_10450_2() -> impl Future { 42 } | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:137:1 + --> tests/ui/manual_async_fn.rs:139:1 | LL | pub(self) fn issue_10450_3() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/manual_split_once.fixed b/tests/ui/manual_split_once.fixed deleted file mode 100644 index aaac6a048e1d..000000000000 --- a/tests/ui/manual_split_once.fixed +++ /dev/null @@ -1,144 +0,0 @@ -#![warn(clippy::manual_split_once)] -#![allow(unused, clippy::iter_skip_next, clippy::iter_nth_zero)] - -extern crate itertools; - -#[allow(unused_imports)] -use itertools::Itertools; - -fn main() { - let _ = "key=value".splitn(2, '=').nth(2); - let _ = "key=value".split_once('=').unwrap().1; - let _ = "key=value".split_once('=').unwrap().1; - let (_, _) = "key=value".split_once('=').unwrap(); - - let s = String::from("key=value"); - let _ = s.split_once('=').unwrap().1; - - let s = Box::::from("key=value"); - let _ = s.split_once('=').unwrap().1; - - let s = &"key=value"; - let _ = s.split_once('=').unwrap().1; - - fn _f(s: &str) -> Option<&str> { - let _ = s.split_once('=')?.1; - let _ = s.split_once('=')?.1; - let _ = s.rsplit_once('=')?.0; - let _ = s.rsplit_once('=')?.0; - None - } - - // Don't lint, slices don't have `split_once` - let _ = [0, 1, 2].splitn(2, |&x| x == 1).nth(1).unwrap(); - - // `rsplitn` gives the results in the reverse order of `rsplit_once` - let _ = "key=value".rsplit_once('=').unwrap().0; - let (_, _) = "key=value".rsplit_once('=').map(|(x, y)| (y, x)).unwrap(); - let _ = s.rsplit_once('=').map(|x| x.0); -} - -fn indirect() -> Option<()> { - let (l, r) = "a.b.c".split_once('.').unwrap(); - - - - let (l, r) = "a.b.c".split_once('.')?; - - - - let (l, r) = "a.b.c".rsplit_once('.').unwrap(); - - - - let (l, r) = "a.b.c".rsplit_once('.')?; - - - - // could lint, currently doesn't - - let mut iter = "a.b.c".splitn(2, '.'); - let other = 1; - let l = iter.next()?; - let r = iter.next()?; - - let mut iter = "a.b.c".splitn(2, '.'); - let mut mut_binding = iter.next()?; - let r = iter.next()?; - - let mut iter = "a.b.c".splitn(2, '.'); - let tuple = (iter.next()?, iter.next()?); - - // should not lint - - let mut missing_unwrap = "a.b.c".splitn(2, '.'); - let l = missing_unwrap.next(); - let r = missing_unwrap.next(); - - let mut mixed_unrap = "a.b.c".splitn(2, '.'); - let unwrap = mixed_unrap.next().unwrap(); - let question_mark = mixed_unrap.next()?; - - let mut iter = "a.b.c".splitn(2, '.'); - let same_name = iter.next()?; - let same_name = iter.next()?; - - let mut iter = "a.b.c".splitn(2, '.'); - let shadows_existing = "d"; - let shadows_existing = iter.next()?; - let r = iter.next()?; - - let mut iter = "a.b.c".splitn(2, '.'); - let becomes_shadowed = iter.next()?; - let becomes_shadowed = "d"; - let r = iter.next()?; - - let mut iter = "a.b.c".splitn(2, '.'); - let l = iter.next()?; - let r = iter.next()?; - let third_usage = iter.next()?; - - let mut n_three = "a.b.c".splitn(3, '.'); - let l = n_three.next()?; - let r = n_three.next()?; - - let mut iter = "a.b.c".splitn(2, '.'); - { - let in_block = iter.next()?; - } - let r = iter.next()?; - - let mut lacks_binding = "a.b.c".splitn(2, '.'); - let _ = lacks_binding.next()?; - let r = lacks_binding.next()?; - - let mut mapped = "a.b.c".splitn(2, '.').map(|_| "~"); - let l = iter.next()?; - let r = iter.next()?; - - let mut assigned = ""; - let mut iter = "a.b.c".splitn(2, '.'); - let l = iter.next()?; - assigned = iter.next()?; - - None -} - -#[clippy::msrv = "1.51"] -fn _msrv_1_51() { - // `str::split_once` was stabilized in 1.52. Do not lint this - let _ = "key=value".splitn(2, '=').nth(1).unwrap(); - - let mut iter = "a.b.c".splitn(2, '.'); - let a = iter.next().unwrap(); - let b = iter.next().unwrap(); -} - -#[clippy::msrv = "1.52"] -fn _msrv_1_52() { - let _ = "key=value".split_once('=').unwrap().1; - - let (a, b) = "a.b.c".split_once('.').unwrap(); - - -} diff --git a/tests/ui/manual_split_once.rs b/tests/ui/manual_split_once.rs index 113e1737c97d..e13c827468b8 100644 --- a/tests/ui/manual_split_once.rs +++ b/tests/ui/manual_split_once.rs @@ -1,6 +1,8 @@ #![warn(clippy::manual_split_once)] #![allow(unused, clippy::iter_skip_next, clippy::iter_nth_zero)] +//@no-rustfix: need to change the suggestion to a multipart suggestion + extern crate itertools; #[allow(unused_imports)] diff --git a/tests/ui/manual_split_once.stderr b/tests/ui/manual_split_once.stderr index c5c9be3ac63d..566204ad8762 100644 --- a/tests/ui/manual_split_once.stderr +++ b/tests/ui/manual_split_once.stderr @@ -1,5 +1,5 @@ error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:11:13 + --> tests/ui/manual_split_once.rs:13:13 | LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=').unwrap().1` @@ -8,79 +8,79 @@ LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); = help: to override `-D warnings` add `#[allow(clippy::manual_split_once)]` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:12:13 + --> tests/ui/manual_split_once.rs:14:13 | LL | let _ = "key=value".splitn(2, '=').skip(1).next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=').unwrap().1` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:13:18 + --> tests/ui/manual_split_once.rs:15:18 | LL | let (_, _) = "key=value".splitn(2, '=').next_tuple().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=')` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:16:13 + --> tests/ui/manual_split_once.rs:18:13 | LL | let _ = s.splitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=').unwrap().1` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:19:13 + --> tests/ui/manual_split_once.rs:21:13 | LL | let _ = s.splitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=').unwrap().1` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:22:13 + --> tests/ui/manual_split_once.rs:24:13 | LL | let _ = s.splitn(2, '=').skip(1).next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=').unwrap().1` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:25:17 + --> tests/ui/manual_split_once.rs:27:17 | LL | let _ = s.splitn(2, '=').nth(1)?; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=')?.1` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:26:17 + --> tests/ui/manual_split_once.rs:28:17 | LL | let _ = s.splitn(2, '=').skip(1).next()?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=')?.1` error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:27:17 + --> tests/ui/manual_split_once.rs:29:17 | LL | let _ = s.rsplitn(2, '=').nth(1)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.rsplit_once('=')?.0` error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:28:17 + --> tests/ui/manual_split_once.rs:30:17 | LL | let _ = s.rsplitn(2, '=').skip(1).next()?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.rsplit_once('=')?.0` error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:36:13 + --> tests/ui/manual_split_once.rs:38:13 | LL | let _ = "key=value".rsplitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".rsplit_once('=').unwrap().0` error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:37:18 + --> tests/ui/manual_split_once.rs:39:18 | LL | let (_, _) = "key=value".rsplitn(2, '=').next_tuple().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".rsplit_once('=').map(|(x, y)| (y, x))` error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:38:13 + --> tests/ui/manual_split_once.rs:40:13 | LL | let _ = s.rsplitn(2, '=').nth(1); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.rsplit_once('=').map(|x| x.0)` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:42:5 + --> tests/ui/manual_split_once.rs:44:5 | LL | let mut iter = "a.b.c".splitn(2, '.'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -103,7 +103,7 @@ LL - let r = iter.next().unwrap(); | error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:46:5 + --> tests/ui/manual_split_once.rs:48:5 | LL | let mut iter = "a.b.c".splitn(2, '.'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -126,7 +126,7 @@ LL - let r = iter.next()?; | error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:50:5 + --> tests/ui/manual_split_once.rs:52:5 | LL | let mut iter = "a.b.c".rsplitn(2, '.'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -149,7 +149,7 @@ LL - let l = iter.next().unwrap(); | error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:54:5 + --> tests/ui/manual_split_once.rs:56:5 | LL | let mut iter = "a.b.c".rsplitn(2, '.'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -172,13 +172,13 @@ LL - let l = iter.next()?; | error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:139:13 + --> tests/ui/manual_split_once.rs:141:13 | LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=').unwrap().1` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:141:5 + --> tests/ui/manual_split_once.rs:143:5 | LL | let mut iter = "a.b.c".splitn(2, '.'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/match_same_arms2.fixed b/tests/ui/match_same_arms2.fixed deleted file mode 100644 index 09e960ddd6a9..000000000000 --- a/tests/ui/match_same_arms2.fixed +++ /dev/null @@ -1,258 +0,0 @@ -#![warn(clippy::match_same_arms)] -#![allow( - clippy::disallowed_names, - clippy::diverging_sub_expression, - clippy::uninlined_format_args, - clippy::match_single_binding, - clippy::match_like_matches_macro -)] -fn bar(_: T) {} -fn foo() -> bool { - unimplemented!() -} - -fn match_same_arms() { - let _ = match 42 { - _ => { - foo(); - let mut a = 42 + [23].len() as i32; - if true { - a += 7; - } - a = -31 - a; - a - }, - }; - //~^^^^^^^^^^^^^^^^^^^ ERROR: this match arm has an identical body to the `_` wildcard arm - - let _ = match 42 { - 51 | 42 => foo(), //~ ERROR: this match arm has an identical body to another arm - _ => true, - }; - - let _ = match Some(42) { - None | Some(_) => 24, //~ ERROR: this match arm has an identical body to another arm - }; - - let _ = match Some(42) { - Some(foo) => 24, - None => 24, - }; - - let _ = match Some(42) { - Some(42) => 24, - Some(a) => 24, // bindings are different - None => 0, - }; - - let _ = match Some(42) { - Some(a) if a > 0 => 24, - Some(a) => 24, // one arm has a guard - None => 0, - }; - - match (Some(42), Some(42)) { - (None, Some(a)) | (Some(a), None) => bar(a), //~ ERROR: this match arm has an identical body to another arm - _ => (), - } - - // No warning because guards are different - let _ = match Some(42) { - Some(a) if a == 42 => a, - Some(a) if a == 24 => a, - Some(_) => 24, - None => 0, - }; - - let _ = match (Some(42), Some(42)) { - (None, Some(a)) | (Some(a), None) if a == 42 => a, //~ ERROR: this match arm has an identical body to another arm - _ => 0, - }; - - match (Some(42), Some(42)) { - (Some(a), ..) | (.., Some(a)) => bar(a), //~ ERROR: this match arm has an identical body to another arm - _ => (), - } - - let _ = match Some(()) { - Some(()) => 0.0, - None => -0.0, - }; - - match (Some(42), Some("")) { - (Some(a), None) => bar(a), - (None, Some(a)) => bar(a), // bindings have different types - _ => (), - } - - let x: Result = Ok(3); - - // No warning because of the guard. - match x { - Ok(x) if x * x == 64 => println!("ok"), - Ok(_) => println!("ok"), - Err(_) => println!("err"), - } - - // This used to be a false positive; see issue #1996. - match x { - Ok(3) => println!("ok"), - Ok(x) if x * x == 64 => println!("ok 64"), - Ok(_) => println!("ok"), - Err(_) => println!("err"), - } - - match (x, Some(1i32)) { - (Ok(x), Some(_)) | (Ok(_), Some(x)) => println!("ok {}", x), //~ ERROR: this match arm has an identical body to another arm - _ => println!("err"), - } - - // No warning; different types for `x`. - match (x, Some(1.0f64)) { - (Ok(x), Some(_)) => println!("ok {}", x), - (Ok(_), Some(x)) => println!("ok {}", x), - _ => println!("err"), - } - - // False negative #2251. - match x { - Ok(_tmp) => println!("ok"), - Ok(_) | Ok(3) => println!("ok"), //~ ERROR: this match arm has an identical body to another arm - Err(_) => { - unreachable!(); - }, - } - - // False positive #1390 - macro_rules! empty { - ($e:expr) => {}; - } - match 0 { - 0 => { - empty!(0); - }, - 1 => { - empty!(1); - }, - x => { - empty!(x); - }, - }; - - // still lint if the tokens are the same - match 0 { - 1 | 0 => { - empty!(0); - }, - x => { - empty!(x); - }, - } - //~^^^^^^^ ERROR: this match arm has an identical body to another arm - - match_expr_like_matches_macro_priority(); -} - -fn match_expr_like_matches_macro_priority() { - enum E { - A, - B, - C, - } - let x = E::A; - let _ans = match x { - E::A => false, - E::B => false, - _ => true, - }; -} - -fn main() { - let _ = match Some(0) { - Some(0) => 0, - Some(1) => 1, - #[cfg(feature = "foo")] - Some(2) => 2, - _ => 1, - }; - - enum Foo { - X(u32), - Y(u32), - Z(u32), - } - - // Don't lint. `Foo::X(0)` and `Foo::Z(_)` overlap with the arm in between. - let _ = match Foo::X(0) { - Foo::X(0) => 1, - Foo::X(_) | Foo::Y(_) | Foo::Z(0) => 2, - Foo::Z(_) => 1, - _ => 0, - }; - - // Suggest moving `Foo::Z(_)` up. - let _ = match Foo::X(0) { - Foo::X(0) | Foo::Z(_) => 1, //~ ERROR: this match arm has an identical body to another arm - Foo::X(_) | Foo::Y(_) => 2, - _ => 0, - }; - - // Suggest moving `Foo::X(0)` down. - let _ = match Foo::X(0) { - Foo::Y(_) | Foo::Z(0) => 2, - Foo::Z(_) | Foo::X(0) => 1, //~ ERROR: this match arm has an identical body to another arm - _ => 0, - }; - - // Don't lint. - let _ = match 0 { - -2 => 1, - -5..=50 => 2, - -150..=88 => 1, - _ => 3, - }; - - struct Bar { - x: u32, - y: u32, - z: u32, - } - - // Lint. - let _ = match None { - Some(Bar { y: 10, z: 0, .. }) => 2, - None => 50, - Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1, //~ ERROR: this match arm has an identical body to another arm - _ => 200, - }; - - let _ = match 0 { - 0 => todo!(), - 1 => todo!(), - 2 => core::convert::identity::(todo!()), - 3 => core::convert::identity::(todo!()), - _ => 5, - }; - - let _ = match 0 { - 1 | 0 => cfg!(not_enable), - _ => false, - }; -} - -// issue #8919, fixed on https://github.com/rust-lang/rust/pull/97312 -mod with_lifetime { - enum MaybeStaticStr<'a> { - Static(&'static str), - Borrowed(&'a str), - } - - impl<'a> MaybeStaticStr<'a> { - fn get(&self) -> &'a str { - match *self { - MaybeStaticStr::Borrowed(s) | MaybeStaticStr::Static(s) => s, - //~^ ERROR: this match arm has an identical body to another arm - } - } - } -} diff --git a/tests/ui/match_same_arms2.rs b/tests/ui/match_same_arms2.rs index cc7425135cc4..dedd02e78733 100644 --- a/tests/ui/match_same_arms2.rs +++ b/tests/ui/match_same_arms2.rs @@ -6,6 +6,9 @@ clippy::match_single_binding, clippy::match_like_matches_macro )] + +//@no-rustfix: need to change the suggestion to a multipart suggestion + fn bar(_: T) {} fn foo() -> bool { unimplemented!() diff --git a/tests/ui/match_same_arms2.stderr b/tests/ui/match_same_arms2.stderr index a5d137c658b7..3a28b5afc2b8 100644 --- a/tests/ui/match_same_arms2.stderr +++ b/tests/ui/match_same_arms2.stderr @@ -1,5 +1,5 @@ error: this match arm has an identical body to the `_` wildcard arm - --> tests/ui/match_same_arms2.rs:16:9 + --> tests/ui/match_same_arms2.rs:19:9 | LL | / 42 => { LL | | foo(); @@ -12,7 +12,7 @@ LL | | _ => { | = help: or try changing either arm body note: `_` wildcard arm here - --> tests/ui/match_same_arms2.rs:25:9 + --> tests/ui/match_same_arms2.rs:28:9 | LL | / _ => { LL | | foo(); @@ -26,7 +26,7 @@ LL | | }, = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]` error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:39:9 + --> tests/ui/match_same_arms2.rs:42:9 | LL | 51 => foo(), | ^^^^^^^^^^^ @@ -42,7 +42,7 @@ LL - 42 => foo(), | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:45:9 + --> tests/ui/match_same_arms2.rs:48:9 | LL | None => 24, | ^^^^^^^^^^ @@ -58,7 +58,7 @@ LL - Some(_) => 24, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:67:9 + --> tests/ui/match_same_arms2.rs:70:9 | LL | (None, Some(a)) => bar(a), | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -74,7 +74,7 @@ LL - (Some(a), None) => bar(a), | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:81:9 + --> tests/ui/match_same_arms2.rs:84:9 | LL | (None, Some(a)) if a == 42 => a, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL - (Some(a), None) if a == 42 => a, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:86:9 + --> tests/ui/match_same_arms2.rs:89:9 | LL | (Some(a), ..) => bar(a), | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,7 +106,7 @@ LL - (.., Some(a)) => bar(a), | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:120:9 + --> tests/ui/match_same_arms2.rs:123:9 | LL | (Ok(x), Some(_)) => println!("ok {}", x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -122,7 +122,7 @@ LL - (Ok(_), Some(x)) => println!("ok {}", x), | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:136:9 + --> tests/ui/match_same_arms2.rs:139:9 | LL | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -138,7 +138,7 @@ LL - Ok(3) => println!("ok"), | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:163:9 + --> tests/ui/match_same_arms2.rs:166:9 | LL | / 1 => { LL | | empty!(0); @@ -158,7 +158,7 @@ LL - }, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:214:9 + --> tests/ui/match_same_arms2.rs:217:9 | LL | Foo::X(0) => 1, | ^^^^^^^^^^^^^^ @@ -174,7 +174,7 @@ LL - Foo::Z(_) => 1, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:224:9 + --> tests/ui/match_same_arms2.rs:227:9 | LL | Foo::Z(_) => 1, | ^^^^^^^^^^^^^^ @@ -190,7 +190,7 @@ LL - Foo::X(0) => 1, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:247:9 + --> tests/ui/match_same_arms2.rs:250:9 | LL | Some(Bar { y: 0, x: 5, .. }) => 1, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -206,7 +206,7 @@ LL - Some(Bar { x: 0, y: 5, .. }) => 1, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:261:9 + --> tests/ui/match_same_arms2.rs:264:9 | LL | 1 => cfg!(not_enable), | ^^^^^^^^^^^^^^^^^^^^^ @@ -222,7 +222,7 @@ LL - 0 => cfg!(not_enable), | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:277:17 + --> tests/ui/match_same_arms2.rs:280:17 | LL | MaybeStaticStr::Borrowed(s) => s, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/significant_drop_tightening.fixed b/tests/ui/significant_drop_tightening.fixed deleted file mode 100644 index ed05f6e0c8d3..000000000000 --- a/tests/ui/significant_drop_tightening.fixed +++ /dev/null @@ -1,144 +0,0 @@ -#![warn(clippy::significant_drop_tightening)] - -use std::sync::Mutex; - -pub fn complex_return_triggers_the_lint() -> i32 { - fn foo() -> i32 { - 1 - } - let mutex = Mutex::new(1); - let lock = mutex.lock().unwrap(); - let _ = *lock; - let _ = *lock; - drop(lock); - foo() -} - -pub fn issue_10413() { - let mutex = Mutex::new(Some(1)); - let opt = Some(1); - if opt.is_some() { - let lock = mutex.lock().unwrap(); - let _ = *lock; - if opt.is_some() { - let _ = *lock; - } - } -} - -pub fn issue_11128() { - use std::mem::drop as unlock; - - struct Foo { - droppable: Option>, - mutex: Mutex>, - } - - impl Drop for Foo { - fn drop(&mut self) { - if let Some(droppable) = self.droppable.take() { - let lock = self.mutex.lock().unwrap(); - let idx_opt = lock.iter().copied().find(|el| Some(el) == droppable.first()); - if let Some(idx) = idx_opt { - let local_droppable = vec![lock.first().copied().unwrap_or_default()]; - unlock(lock); - drop(local_droppable); - } - } - } - } -} - -pub fn issue_11160() -> bool { - let mutex = Mutex::new(1i32); - let lock = mutex.lock().unwrap(); - let _ = lock.abs(); - true -} - -pub fn issue_11189() { - struct Number { - pub value: u32, - } - - fn do_something() -> Result<(), ()> { - let number = Mutex::new(Number { value: 1 }); - let number2 = Mutex::new(Number { value: 2 }); - let number3 = Mutex::new(Number { value: 3 }); - let mut lock = number.lock().unwrap(); - let mut lock2 = number2.lock().unwrap(); - let mut lock3 = number3.lock().unwrap(); - lock.value += 1; - lock2.value += 1; - lock3.value += 1; - drop((lock, lock2, lock3)); - Ok(()) - } -} - -pub fn path_return_can_be_ignored() -> i32 { - let mutex = Mutex::new(1); - let lock = mutex.lock().unwrap(); - let rslt = *lock; - let _ = *lock; - rslt -} - -pub fn post_bindings_can_be_ignored() { - let mutex = Mutex::new(1); - let lock = mutex.lock().unwrap(); - let rslt = *lock; - let another = rslt; - let _ = another; -} - -pub fn unnecessary_contention_with_multiple_owned_results() { - { - let mutex = Mutex::new(1i32); - let lock = mutex.lock().unwrap(); - let _ = lock.abs(); - let _ = lock.is_positive(); - } - - { - let mutex = Mutex::new(1i32); - let lock = mutex.lock().unwrap(); - let rslt0 = lock.abs(); - let rslt1 = lock.is_positive(); - drop(lock); - do_heavy_computation_that_takes_time((rslt0, rslt1)); - } -} - -pub fn unnecessary_contention_with_single_owned_results() { - { - let mutex = Mutex::new(1i32); - let lock = mutex.lock().unwrap(); - let _ = lock.abs(); - } - { - let mutex = Mutex::new(vec![1i32]); - let mut lock = mutex.lock().unwrap(); - lock.clear(); - } - - { - let mutex = Mutex::new(1i32); - - let rslt0 = mutex.lock().unwrap().abs(); - - do_heavy_computation_that_takes_time(rslt0); - } - { - let mutex = Mutex::new(vec![1i32]); - - mutex.lock().unwrap().clear(); - - do_heavy_computation_that_takes_time(()); - } -} - -// Marker used for illustration purposes. -pub fn do_heavy_computation_that_takes_time(_: T) {} - -fn main() {} diff --git a/tests/ui/significant_drop_tightening.rs b/tests/ui/significant_drop_tightening.rs index e5f17278f0f6..77538167548e 100644 --- a/tests/ui/significant_drop_tightening.rs +++ b/tests/ui/significant_drop_tightening.rs @@ -1,5 +1,7 @@ #![warn(clippy::significant_drop_tightening)] +//@no-rustfix: need to change the suggestion to a multipart suggestion + use std::sync::Mutex; pub fn complex_return_triggers_the_lint() -> i32 { diff --git a/tests/ui/significant_drop_tightening.stderr b/tests/ui/significant_drop_tightening.stderr index 5fc66279f00e..2d7da4f394d3 100644 --- a/tests/ui/significant_drop_tightening.stderr +++ b/tests/ui/significant_drop_tightening.stderr @@ -1,5 +1,5 @@ error: temporary with significant `Drop` can be early dropped - --> tests/ui/significant_drop_tightening.rs:10:9 + --> tests/ui/significant_drop_tightening.rs:12:9 | LL | pub fn complex_return_triggers_the_lint() -> i32 { | __________________________________________________- @@ -24,7 +24,7 @@ LL + drop(lock); | error: temporary with significant `Drop` can be early dropped - --> tests/ui/significant_drop_tightening.rs:104:13 + --> tests/ui/significant_drop_tightening.rs:106:13 | LL | / { LL | | let mutex = Mutex::new(1i32); @@ -44,7 +44,7 @@ LL + drop(lock); | error: temporary with significant `Drop` can be early dropped - --> tests/ui/significant_drop_tightening.rs:125:13 + --> tests/ui/significant_drop_tightening.rs:127:13 | LL | / { LL | | let mutex = Mutex::new(1i32); @@ -67,7 +67,7 @@ LL - let rslt0 = lock.abs(); | error: temporary with significant `Drop` can be early dropped - --> tests/ui/significant_drop_tightening.rs:131:17 + --> tests/ui/significant_drop_tightening.rs:133:17 | LL | / { LL | | let mutex = Mutex::new(vec![1i32]); diff --git a/tests/ui/unnecessary_iter_cloned.fixed b/tests/ui/unnecessary_iter_cloned.fixed deleted file mode 100644 index dc5e163ff04e..000000000000 --- a/tests/ui/unnecessary_iter_cloned.fixed +++ /dev/null @@ -1,201 +0,0 @@ -#![allow(unused_assignments)] -#![warn(clippy::unnecessary_to_owned)] - -#[allow(dead_code)] -#[derive(Clone, Copy)] -enum FileType { - Account, - PrivateKey, - Certificate, -} - -fn main() { - let path = std::path::Path::new("x"); - - let _ = check_files(&[(FileType::Account, path)]); - let _ = check_files_vec(vec![(FileType::Account, path)]); - - // negative tests - let _ = check_files_ref(&[(FileType::Account, path)]); - let _ = check_files_mut(&[(FileType::Account, path)]); - let _ = check_files_ref_mut(&[(FileType::Account, path)]); - let _ = check_files_self_and_arg(&[(FileType::Account, path)]); - let _ = check_files_mut_path_buf(&[(FileType::Account, std::path::PathBuf::new())]); - - check_mut_iteratee_and_modify_inner_variable(); -} - -// `check_files` and its variants are based on: -// https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262 -fn check_files(files: &[(FileType, &std::path::Path)]) -> bool { - for (t, path) in files { - let other = match get_file_path(t) { - Ok(p) => p, - Err(_) => { - return false; - }, - }; - if !path.is_file() || !other.is_file() { - return false; - } - } - true -} - -fn check_files_vec(files: Vec<(FileType, &std::path::Path)>) -> bool { - for (t, path) in files.iter() { - let other = match get_file_path(t) { - Ok(p) => p, - Err(_) => { - return false; - }, - }; - if !path.is_file() || !other.is_file() { - return false; - } - } - true -} - -fn check_files_ref(files: &[(FileType, &std::path::Path)]) -> bool { - for (ref t, path) in files.iter().copied() { - let other = match get_file_path(t) { - Ok(p) => p, - Err(_) => { - return false; - }, - }; - if !path.is_file() || !other.is_file() { - return false; - } - } - true -} - -#[allow(unused_assignments)] -fn check_files_mut(files: &[(FileType, &std::path::Path)]) -> bool { - for (mut t, path) in files.iter().copied() { - t = FileType::PrivateKey; - let other = match get_file_path(&t) { - Ok(p) => p, - Err(_) => { - return false; - }, - }; - if !path.is_file() || !other.is_file() { - return false; - } - } - true -} - -fn check_files_ref_mut(files: &[(FileType, &std::path::Path)]) -> bool { - for (ref mut t, path) in files.iter().copied() { - *t = FileType::PrivateKey; - let other = match get_file_path(t) { - Ok(p) => p, - Err(_) => { - return false; - }, - }; - if !path.is_file() || !other.is_file() { - return false; - } - } - true -} - -fn check_files_self_and_arg(files: &[(FileType, &std::path::Path)]) -> bool { - for (t, path) in files.iter().copied() { - let other = match get_file_path(&t) { - Ok(p) => p, - Err(_) => { - return false; - }, - }; - if !path.join(path).is_file() || !other.is_file() { - return false; - } - } - true -} - -#[allow(unused_assignments)] -fn check_files_mut_path_buf(files: &[(FileType, std::path::PathBuf)]) -> bool { - for (mut t, path) in files.iter().cloned() { - t = FileType::PrivateKey; - let other = match get_file_path(&t) { - Ok(p) => p, - Err(_) => { - return false; - }, - }; - if !path.is_file() || !other.is_file() { - return false; - } - } - true -} - -fn get_file_path(_file_type: &FileType) -> Result { - Ok(std::path::PathBuf::new()) -} - -// Issue 12098 -// https://github.com/rust-lang/rust-clippy/issues/12098 -// no message emits -fn check_mut_iteratee_and_modify_inner_variable() { - struct Test { - list: Vec, - mut_this: bool, - } - - impl Test { - fn list(&self) -> &[String] { - &self.list - } - } - - let mut test = Test { - list: vec![String::from("foo"), String::from("bar")], - mut_this: false, - }; - - for _item in test.list().to_vec() { - println!("{}", _item); - - test.mut_this = true; - { - test.mut_this = true; - } - } -} - -mod issue_12821 { - fn foo() { - let v: Vec<_> = "hello".chars().collect(); - for c in v.iter() { - //~^ ERROR: unnecessary use of `cloned` - println!("{c}"); // should not suggest to remove `&` - } - } - - fn bar() { - let v: Vec<_> = "hello".chars().collect(); - for c in v.iter() { - //~^ ERROR: unnecessary use of `cloned` - let ref_c = c; //~ HELP: remove any references to the binding - println!("{ref_c}"); - } - } - - fn baz() { - let v: Vec<_> = "hello".chars().enumerate().collect(); - for (i, c) in v.iter() { - //~^ ERROR: unnecessary use of `cloned` - let ref_c = c; //~ HELP: remove any references to the binding - let ref_i = i; - println!("{i} {ref_c}"); // should not suggest to remove `&` from `i` - } - } -} diff --git a/tests/ui/unnecessary_iter_cloned.rs b/tests/ui/unnecessary_iter_cloned.rs index 8f797ac717fb..331b7b25271b 100644 --- a/tests/ui/unnecessary_iter_cloned.rs +++ b/tests/ui/unnecessary_iter_cloned.rs @@ -1,6 +1,8 @@ #![allow(unused_assignments)] #![warn(clippy::unnecessary_to_owned)] +//@no-rustfix: need to change the suggestion to a multipart suggestion + #[allow(dead_code)] #[derive(Clone, Copy)] enum FileType { diff --git a/tests/ui/unnecessary_iter_cloned.stderr b/tests/ui/unnecessary_iter_cloned.stderr index 0bdb37a521fc..e3592e3cbbd8 100644 --- a/tests/ui/unnecessary_iter_cloned.stderr +++ b/tests/ui/unnecessary_iter_cloned.stderr @@ -1,5 +1,5 @@ error: unnecessary use of `copied` - --> tests/ui/unnecessary_iter_cloned.rs:31:22 + --> tests/ui/unnecessary_iter_cloned.rs:33:22 | LL | for (t, path) in files.iter().copied() { | ^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL + let other = match get_file_path(t) { | error: unnecessary use of `copied` - --> tests/ui/unnecessary_iter_cloned.rs:46:22 + --> tests/ui/unnecessary_iter_cloned.rs:48:22 | LL | for (t, path) in files.iter().copied() { | ^^^^^^^^^^^^^^^^^^^^^ @@ -33,13 +33,13 @@ LL + let other = match get_file_path(t) { | error: unnecessary use of `cloned` - --> tests/ui/unnecessary_iter_cloned.rs:177:18 + --> tests/ui/unnecessary_iter_cloned.rs:179:18 | LL | for c in v.iter().cloned() { | ^^^^^^^^^^^^^^^^^ help: use: `v.iter()` error: unnecessary use of `cloned` - --> tests/ui/unnecessary_iter_cloned.rs:185:18 + --> tests/ui/unnecessary_iter_cloned.rs:187:18 | LL | for c in v.iter().cloned() { | ^^^^^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL + let ref_c = c; | error: unnecessary use of `cloned` - --> tests/ui/unnecessary_iter_cloned.rs:194:23 + --> tests/ui/unnecessary_iter_cloned.rs:196:23 | LL | for (i, c) in v.iter().cloned() { | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed deleted file mode 100644 index fdcac8fb08dc..000000000000 --- a/tests/ui/unnecessary_to_owned.fixed +++ /dev/null @@ -1,587 +0,0 @@ -#![allow( - clippy::needless_borrow, - clippy::needless_borrows_for_generic_args, - clippy::ptr_arg, - clippy::manual_async_fn, - clippy::needless_lifetimes -)] -#![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)] - -use std::borrow::Cow; -use std::ffi::{CStr, CString, OsStr, OsString}; -use std::ops::Deref; - -#[derive(Clone)] -struct X(String); - -impl Deref for X { - type Target = [u8]; - fn deref(&self) -> &[u8] { - self.0.as_bytes() - } -} - -impl AsRef for X { - fn as_ref(&self) -> &str { - self.0.as_str() - } -} - -#[allow(clippy::to_string_trait_impl)] -impl ToString for X { - fn to_string(&self) -> String { - self.0.to_string() - } -} - -impl X { - fn join(&self, other: impl AsRef) -> Self { - let mut s = self.0.clone(); - s.push_str(other.as_ref()); - Self(s) - } -} - -#[allow(dead_code)] -#[derive(Clone)] -enum FileType { - Account, - PrivateKey, - Certificate, -} - -fn main() { - let c_str = CStr::from_bytes_with_nul(&[0]).unwrap(); - let os_str = OsStr::new("x"); - let path = std::path::Path::new("x"); - let s = "x"; - let array = ["x"]; - let array_ref = &["x"]; - let slice = &["x"][..]; - let x = X(String::from("x")); - let x_ref = &x; - - require_c_str(&Cow::from(c_str)); - require_c_str(c_str); - - require_os_str(os_str); - require_os_str(&Cow::from(os_str)); - require_os_str(os_str); - - require_path(path); - require_path(&Cow::from(path)); - require_path(path); - - require_str(s); - require_str(&Cow::from(s)); - require_str(s); - require_str(x_ref.as_ref()); - - require_slice(slice); - require_slice(&Cow::from(slice)); - require_slice(array.as_ref()); - require_slice(array_ref.as_ref()); - require_slice(slice); - require_slice(&x_ref.to_owned()); // No longer flagged because of #8759. - - require_x(&Cow::::Owned(x.clone())); - require_x(&x_ref.to_owned()); // No longer flagged because of #8759. - - require_deref_c_str(c_str); - require_deref_os_str(os_str); - require_deref_path(path); - require_deref_str(s); - require_deref_slice(slice); - - require_impl_deref_c_str(c_str); - require_impl_deref_os_str(os_str); - require_impl_deref_path(path); - require_impl_deref_str(s); - require_impl_deref_slice(slice); - - require_deref_str_slice(s, slice); - require_deref_slice_str(slice, s); - - require_as_ref_c_str(c_str); - require_as_ref_os_str(os_str); - require_as_ref_path(path); - require_as_ref_str(s); - require_as_ref_str(&x); - require_as_ref_slice(array); - require_as_ref_slice(array_ref); - require_as_ref_slice(slice); - - require_impl_as_ref_c_str(c_str); - require_impl_as_ref_os_str(os_str); - require_impl_as_ref_path(path); - require_impl_as_ref_str(s); - require_impl_as_ref_str(&x); - require_impl_as_ref_slice(array); - require_impl_as_ref_slice(array_ref); - require_impl_as_ref_slice(slice); - - require_as_ref_str_slice(s, array); - require_as_ref_str_slice(s, array_ref); - require_as_ref_str_slice(s, slice); - require_as_ref_slice_str(array, s); - require_as_ref_slice_str(array_ref, s); - require_as_ref_slice_str(slice, s); - - let _ = x.join(x_ref); - - let _ = slice.iter().copied(); - let _ = slice.iter().copied(); - let _ = [std::path::PathBuf::new()][..].iter().cloned(); - let _ = [std::path::PathBuf::new()][..].iter().cloned(); - - let _ = slice.iter().copied(); - let _ = slice.iter().copied(); - let _ = [std::path::PathBuf::new()][..].iter().cloned(); - let _ = [std::path::PathBuf::new()][..].iter().cloned(); - - let _ = check_files(&[FileType::Account]); - - // negative tests - require_string(&s.to_string()); - require_string(&Cow::from(s).into_owned()); - require_string(&s.to_owned()); - require_string(&x_ref.to_string()); - - // `X` isn't copy. - require_slice(&x.to_owned()); - require_deref_slice(x.to_owned()); - - // The following should be flagged by `redundant_clone`, but not by this lint. - require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap()); - require_os_str(&OsString::from("x")); - require_path(&std::path::PathBuf::from("x")); - require_str(&String::from("x")); - require_slice(&[String::from("x")]); - - let slice = [0u8; 1024]; - let _ref_str: &str = core::str::from_utf8(&slice).expect("not UTF-8"); - let _ref_str: &str = core::str::from_utf8(b"foo").unwrap(); - let _ref_str: &str = core::str::from_utf8(b"foo".as_slice()).unwrap(); - // Expression is of type `&String`, can't suggest `str::from_utf8` here - let _ref_string = &String::from_utf8(b"foo".to_vec()).unwrap(); - macro_rules! arg_from_macro { - () => { - b"foo".to_vec() - }; - } - macro_rules! string_from_utf8_from_macro { - () => { - &String::from_utf8(b"foo".to_vec()).unwrap() - }; - } - let _ref_str: &str = &String::from_utf8(arg_from_macro!()).unwrap(); - let _ref_str: &str = string_from_utf8_from_macro!(); -} - -fn require_c_str(_: &CStr) {} -fn require_os_str(_: &OsStr) {} -fn require_path(_: &std::path::Path) {} -fn require_str(_: &str) {} -fn require_slice(_: &[T]) {} -fn require_x(_: &X) {} - -fn require_deref_c_str>(_: T) {} -fn require_deref_os_str>(_: T) {} -fn require_deref_path>(_: T) {} -fn require_deref_str>(_: T) {} -fn require_deref_slice>(_: U) {} - -fn require_impl_deref_c_str(_: impl Deref) {} -fn require_impl_deref_os_str(_: impl Deref) {} -fn require_impl_deref_path(_: impl Deref) {} -fn require_impl_deref_str(_: impl Deref) {} -fn require_impl_deref_slice(_: impl Deref) {} - -fn require_deref_str_slice, U, V: Deref>(_: T, _: V) {} -fn require_deref_slice_str, V: Deref>(_: U, _: V) {} - -fn require_as_ref_c_str>(_: T) {} -fn require_as_ref_os_str>(_: T) {} -fn require_as_ref_path>(_: T) {} -fn require_as_ref_str>(_: T) {} -fn require_as_ref_slice>(_: U) {} - -fn require_impl_as_ref_c_str(_: impl AsRef) {} -fn require_impl_as_ref_os_str(_: impl AsRef) {} -fn require_impl_as_ref_path(_: impl AsRef) {} -fn require_impl_as_ref_str(_: impl AsRef) {} -fn require_impl_as_ref_slice(_: impl AsRef<[T]>) {} - -fn require_as_ref_str_slice, U, V: AsRef<[U]>>(_: T, _: V) {} -fn require_as_ref_slice_str, V: AsRef>(_: U, _: V) {} - -// `check_files` is based on: -// https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262 -fn check_files(file_types: &[FileType]) -> bool { - for t in file_types { - let path = match get_file_path(t) { - Ok(p) => p, - Err(_) => { - return false; - }, - }; - if !path.is_file() { - return false; - } - } - true -} - -fn get_file_path(_file_type: &FileType) -> Result { - Ok(std::path::PathBuf::new()) -} - -fn require_string(_: &String) {} - -#[clippy::msrv = "1.35"] -fn _msrv_1_35() { - // `copied` was stabilized in 1.36, so clippy should use `cloned`. - let _ = &["x"][..].iter().cloned(); -} - -#[clippy::msrv = "1.36"] -fn _msrv_1_36() { - let _ = &["x"][..].iter().copied(); -} - -// https://github.com/rust-lang/rust-clippy/issues/8507 -mod issue_8507 { - #![allow(dead_code)] - - struct Opaque

(P); - - pub trait Abstracted {} - - impl

Abstracted for Opaque

{} - - fn build

(p: P) -> Opaque

- where - P: AsRef, - { - Opaque(p) - } - - // Should not lint. - fn test_str(s: &str) -> Box { - Box::new(build(s.to_string())) - } - - // Should not lint. - fn test_x(x: super::X) -> Box { - Box::new(build(x)) - } - - #[derive(Clone, Copy)] - struct Y(&'static str); - - impl AsRef for Y { - fn as_ref(&self) -> &str { - self.0 - } - } - - #[allow(clippy::to_string_trait_impl)] - impl ToString for Y { - fn to_string(&self) -> String { - self.0.to_string() - } - } - - // Should lint because Y is copy. - fn test_y(y: Y) -> Box { - Box::new(build(y)) - } -} - -// https://github.com/rust-lang/rust-clippy/issues/8759 -mod issue_8759 { - #![allow(dead_code)] - - #[derive(Default)] - struct View {} - - impl std::borrow::ToOwned for View { - type Owned = View; - fn to_owned(&self) -> Self::Owned { - View {} - } - } - - #[derive(Default)] - struct RenderWindow { - default_view: View, - } - - impl RenderWindow { - fn default_view(&self) -> &View { - &self.default_view - } - fn set_view(&mut self, _view: &View) {} - } - - fn main() { - let mut rw = RenderWindow::default(); - rw.set_view(&rw.default_view().to_owned()); - } -} - -mod issue_8759_variant { - #![allow(dead_code)] - - #[derive(Clone, Default)] - struct View {} - - #[derive(Default)] - struct RenderWindow { - default_view: View, - } - - impl RenderWindow { - fn default_view(&self) -> &View { - &self.default_view - } - fn set_view(&mut self, _view: &View) {} - } - - fn main() { - let mut rw = RenderWindow::default(); - rw.set_view(&rw.default_view().to_owned()); - } -} - -mod issue_9317 { - #![allow(dead_code)] - - struct Bytes {} - - #[allow(clippy::to_string_trait_impl)] - impl ToString for Bytes { - fn to_string(&self) -> String { - "123".to_string() - } - } - - impl AsRef<[u8]> for Bytes { - fn as_ref(&self) -> &[u8] { - &[1, 2, 3] - } - } - - fn consume>(c: C) { - let _ = c; - } - - pub fn main() { - let b = Bytes {}; - // Should not lint. - consume(b.to_string()); - } -} - -mod issue_9351 { - #![allow(dead_code)] - - use std::ops::Deref; - use std::path::{Path, PathBuf}; - - fn require_deref_path>(x: T) -> T { - x - } - - fn generic_arg_used_elsewhere>(_x: T, _y: T) {} - - fn id>(x: T) -> T { - x - } - - fn predicates_are_satisfied(_x: impl std::fmt::Write) {} - - // Should lint - fn single_return() -> impl AsRef { - id("abc") - } - - // Should not lint - fn multiple_returns(b: bool) -> impl AsRef { - if b { - return String::new(); - } - - id("abc".to_string()) - } - - struct S1(String); - - // Should not lint - fn fields1() -> S1 { - S1(id("abc".to_string())) - } - - struct S2 { - s: String, - } - - // Should not lint - fn fields2() { - let mut s = S2 { s: "abc".into() }; - s.s = id("abc".to_string()); - } - - pub fn main() { - let path = std::path::Path::new("x"); - let path_buf = path.to_owned(); - - // Should not lint. - let _x: PathBuf = require_deref_path(path.to_owned()); - generic_arg_used_elsewhere(path.to_owned(), path_buf); - predicates_are_satisfied(id("abc".to_string())); - } -} - -mod issue_9504 { - #![allow(dead_code)] - - async fn foo>(_: S) {} - async fn bar() { - foo(std::path::PathBuf::new().to_string_lossy().to_string()).await; - } -} - -mod issue_9771a { - #![allow(dead_code)] - - use std::marker::PhantomData; - - pub struct Key, V: ?Sized>(K, PhantomData); - - impl, V: ?Sized> Key { - pub fn new(key: K) -> Key { - Key(key, PhantomData) - } - } - - pub fn pkh(pkh: &[u8]) -> Key, String> { - Key::new([b"pkh-", pkh].concat().to_vec()) - } -} - -mod issue_9771b { - #![allow(dead_code)] - - pub struct Key>(K); - - pub fn from(c: &[u8]) -> Key> { - let v = [c].concat(); - Key(v.to_vec()) - } -} - -// This is a watered down version of the code in: https://github.com/oxigraph/rio -// The ICE is triggered by the call to `to_owned` on this line: -// https://github.com/oxigraph/rio/blob/66635b9ff8e5423e58932353fa40d6e64e4820f7/testsuite/src/parser_evaluator.rs#L116 -mod issue_10021 { - #![allow(unused)] - - pub struct Iri(T); - - impl> Iri { - pub fn parse(iri: T) -> Result { - unimplemented!() - } - } - - pub fn parse_w3c_rdf_test_file(url: &str) -> Result<(), ()> { - let base_iri = Iri::parse(url.to_owned())?; - Ok(()) - } -} - -mod issue_10033 { - #![allow(dead_code)] - use std::fmt::Display; - use std::ops::Deref; - - fn _main() { - let f = Foo; - - // Not actually unnecessary - this calls `Foo`'s `Display` impl, not `str`'s (even though `Foo` does - // deref to `str`) - foo(&f.to_string()); - } - - fn foo(s: &str) { - println!("{}", s); - } - - struct Foo; - - impl Deref for Foo { - type Target = str; - - fn deref(&self) -> &Self::Target { - "str" - } - } - - impl Display for Foo { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Foo") - } - } -} - -mod issue_11952 { - use core::future::{Future, IntoFuture}; - - fn foo<'a, T: AsRef<[u8]>>(x: T, y: &'a i32) -> impl 'a + Future> { - async move { - let _y = y; - Ok(()) - } - } - - fn bar() { - IntoFuture::into_future(foo([], &0)); - } -} - -fn borrow_checks() { - use std::borrow::Borrow; - use std::collections::HashSet; - - fn inner(a: &[&str]) { - let mut s = HashSet::from([vec!["a"]]); - s.remove(a); //~ ERROR: unnecessary use of `to_vec` - } - - let mut s = HashSet::from(["a".to_string()]); - s.remove("b"); //~ ERROR: unnecessary use of `to_owned` - s.remove("b"); //~ ERROR: unnecessary use of `to_string` - // Should not warn. - s.remove("b"); - - let mut s = HashSet::from([vec!["a"]]); - s.remove(["b"].as_slice()); //~ ERROR: unnecessary use of `to_vec` - s.remove((&["b"]).as_slice()); //~ ERROR: unnecessary use of `to_vec` - - // Should not warn. - s.remove(&["b"].to_vec().clone()); - s.remove(["a"].as_slice()); - - trait SetExt { - fn foo>(&self, _: &String); - } - - impl SetExt for HashSet { - fn foo>(&self, _: &String) {} - } - - // Should not lint! - HashSet::::new().foo::<&str>(&"".to_owned()); - HashSet::::new().get(&1.to_string()); -} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index 10a9727a9a79..da0c761f795b 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -7,6 +7,8 @@ )] #![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)] +//@no-rustfix: need to change the suggestion to a multipart suggestion + use std::borrow::Cow; use std::ffi::{CStr, CString, OsStr, OsString}; use std::ops::Deref; diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index 511b4ae119f8..7ab1f667d9b5 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -1,11 +1,11 @@ error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:155:64 + --> tests/ui/unnecessary_to_owned.rs:157:64 | LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:155:20 + --> tests/ui/unnecessary_to_owned.rs:157:20 | LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,55 +13,55 @@ LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()) = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]` error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:156:40 + --> tests/ui/unnecessary_to_owned.rs:158:40 | LL | require_os_str(&OsString::from("x").to_os_string()); | ^^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:156:21 + --> tests/ui/unnecessary_to_owned.rs:158:21 | LL | require_os_str(&OsString::from("x").to_os_string()); | ^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:157:48 + --> tests/ui/unnecessary_to_owned.rs:159:48 | LL | require_path(&std::path::PathBuf::from("x").to_path_buf()); | ^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:157:19 + --> tests/ui/unnecessary_to_owned.rs:159:19 | LL | require_path(&std::path::PathBuf::from("x").to_path_buf()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:158:35 + --> tests/ui/unnecessary_to_owned.rs:160:35 | LL | require_str(&String::from("x").to_string()); | ^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:158:18 + --> tests/ui/unnecessary_to_owned.rs:160:18 | LL | require_str(&String::from("x").to_string()); | ^^^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:159:39 + --> tests/ui/unnecessary_to_owned.rs:161:39 | LL | require_slice(&[String::from("x")].to_owned()); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:159:20 + --> tests/ui/unnecessary_to_owned.rs:161:20 | LL | require_slice(&[String::from("x")].to_owned()); | ^^^^^^^^^^^^^^^^^^^ error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:64:36 + --> tests/ui/unnecessary_to_owned.rs:66:36 | LL | require_c_str(&Cow::from(c_str).into_owned()); | ^^^^^^^^^^^^^ help: remove this @@ -70,415 +70,415 @@ LL | require_c_str(&Cow::from(c_str).into_owned()); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_to_owned)]` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:65:19 + --> tests/ui/unnecessary_to_owned.rs:67:19 | LL | require_c_str(&c_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_os_string` - --> tests/ui/unnecessary_to_owned.rs:67:20 + --> tests/ui/unnecessary_to_owned.rs:69:20 | LL | require_os_str(&os_str.to_os_string()); | ^^^^^^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:68:38 + --> tests/ui/unnecessary_to_owned.rs:70:38 | LL | require_os_str(&Cow::from(os_str).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:69:20 + --> tests/ui/unnecessary_to_owned.rs:71:20 | LL | require_os_str(&os_str.to_owned()); | ^^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_path_buf` - --> tests/ui/unnecessary_to_owned.rs:71:18 + --> tests/ui/unnecessary_to_owned.rs:73:18 | LL | require_path(&path.to_path_buf()); | ^^^^^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:72:34 + --> tests/ui/unnecessary_to_owned.rs:74:34 | LL | require_path(&Cow::from(path).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:73:18 + --> tests/ui/unnecessary_to_owned.rs:75:18 | LL | require_path(&path.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:75:17 + --> tests/ui/unnecessary_to_owned.rs:77:17 | LL | require_str(&s.to_string()); | ^^^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:76:30 + --> tests/ui/unnecessary_to_owned.rs:78:30 | LL | require_str(&Cow::from(s).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:77:17 + --> tests/ui/unnecessary_to_owned.rs:79:17 | LL | require_str(&s.to_owned()); | ^^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:78:17 + --> tests/ui/unnecessary_to_owned.rs:80:17 | LL | require_str(&x_ref.to_string()); | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref.as_ref()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:80:19 + --> tests/ui/unnecessary_to_owned.rs:82:19 | LL | require_slice(&slice.to_vec()); | ^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:81:36 + --> tests/ui/unnecessary_to_owned.rs:83:36 | LL | require_slice(&Cow::from(slice).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:82:19 + --> tests/ui/unnecessary_to_owned.rs:84:19 | LL | require_slice(&array.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `array.as_ref()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:83:19 + --> tests/ui/unnecessary_to_owned.rs:85:19 | LL | require_slice(&array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref.as_ref()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:84:19 + --> tests/ui/unnecessary_to_owned.rs:86:19 | LL | require_slice(&slice.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:87:42 + --> tests/ui/unnecessary_to_owned.rs:89:42 | LL | require_x(&Cow::::Owned(x.clone()).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:90:25 + --> tests/ui/unnecessary_to_owned.rs:92:25 | LL | require_deref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:91:26 + --> tests/ui/unnecessary_to_owned.rs:93:26 | LL | require_deref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:92:24 + --> tests/ui/unnecessary_to_owned.rs:94:24 | LL | require_deref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:93:23 + --> tests/ui/unnecessary_to_owned.rs:95:23 | LL | require_deref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:94:25 + --> tests/ui/unnecessary_to_owned.rs:96:25 | LL | require_deref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:96:30 + --> tests/ui/unnecessary_to_owned.rs:98:30 | LL | require_impl_deref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:97:31 + --> tests/ui/unnecessary_to_owned.rs:99:31 | LL | require_impl_deref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:98:29 + --> tests/ui/unnecessary_to_owned.rs:100:29 | LL | require_impl_deref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:99:28 + --> tests/ui/unnecessary_to_owned.rs:101:28 | LL | require_impl_deref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:100:30 + --> tests/ui/unnecessary_to_owned.rs:102:30 | LL | require_impl_deref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:102:29 + --> tests/ui/unnecessary_to_owned.rs:104:29 | LL | require_deref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:102:43 + --> tests/ui/unnecessary_to_owned.rs:104:43 | LL | require_deref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:103:29 + --> tests/ui/unnecessary_to_owned.rs:105:29 | LL | require_deref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:103:47 + --> tests/ui/unnecessary_to_owned.rs:105:47 | LL | require_deref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:105:26 + --> tests/ui/unnecessary_to_owned.rs:107:26 | LL | require_as_ref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:106:27 + --> tests/ui/unnecessary_to_owned.rs:108:27 | LL | require_as_ref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:107:25 + --> tests/ui/unnecessary_to_owned.rs:109:25 | LL | require_as_ref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:108:24 + --> tests/ui/unnecessary_to_owned.rs:110:24 | LL | require_as_ref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:109:24 + --> tests/ui/unnecessary_to_owned.rs:111:24 | LL | require_as_ref_str(x.to_owned()); | ^^^^^^^^^^^^ help: use: `&x` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:110:26 + --> tests/ui/unnecessary_to_owned.rs:112:26 | LL | require_as_ref_slice(array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:111:26 + --> tests/ui/unnecessary_to_owned.rs:113:26 | LL | require_as_ref_slice(array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:112:26 + --> tests/ui/unnecessary_to_owned.rs:114:26 | LL | require_as_ref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:114:31 + --> tests/ui/unnecessary_to_owned.rs:116:31 | LL | require_impl_as_ref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:115:32 + --> tests/ui/unnecessary_to_owned.rs:117:32 | LL | require_impl_as_ref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:116:30 + --> tests/ui/unnecessary_to_owned.rs:118:30 | LL | require_impl_as_ref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:117:29 + --> tests/ui/unnecessary_to_owned.rs:119:29 | LL | require_impl_as_ref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:118:29 + --> tests/ui/unnecessary_to_owned.rs:120:29 | LL | require_impl_as_ref_str(x.to_owned()); | ^^^^^^^^^^^^ help: use: `&x` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:119:31 + --> tests/ui/unnecessary_to_owned.rs:121:31 | LL | require_impl_as_ref_slice(array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:120:31 + --> tests/ui/unnecessary_to_owned.rs:122:31 | LL | require_impl_as_ref_slice(array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:121:31 + --> tests/ui/unnecessary_to_owned.rs:123:31 | LL | require_impl_as_ref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` -error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:123:30 - | -LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); - | ^^^^^^^^^^^^ help: use: `s` - -error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:123:44 - | -LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); - | ^^^^^^^^^^^^^^^^ help: use: `array` - -error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:124:30 - | -LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); - | ^^^^^^^^^^^^ help: use: `s` - -error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:124:44 - | -LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); - | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` - error: unnecessary use of `to_owned` --> tests/ui/unnecessary_to_owned.rs:125:30 | -LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); +LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` --> tests/ui/unnecessary_to_owned.rs:125:44 | +LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); + | ^^^^^^^^^^^^^^^^ help: use: `array` + +error: unnecessary use of `to_owned` + --> tests/ui/unnecessary_to_owned.rs:126:30 + | +LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); + | ^^^^^^^^^^^^ help: use: `s` + +error: unnecessary use of `to_owned` + --> tests/ui/unnecessary_to_owned.rs:126:44 + | +LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); + | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` + +error: unnecessary use of `to_owned` + --> tests/ui/unnecessary_to_owned.rs:127:30 + | +LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); + | ^^^^^^^^^^^^ help: use: `s` + +error: unnecessary use of `to_owned` + --> tests/ui/unnecessary_to_owned.rs:127:44 + | LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:126:30 + --> tests/ui/unnecessary_to_owned.rs:128:30 | LL | require_as_ref_slice_str(array.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:126:48 + --> tests/ui/unnecessary_to_owned.rs:128:48 | LL | require_as_ref_slice_str(array.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:127:30 + --> tests/ui/unnecessary_to_owned.rs:129:30 | LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:127:52 + --> tests/ui/unnecessary_to_owned.rs:129:52 | LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:128:30 + --> tests/ui/unnecessary_to_owned.rs:130:30 | LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:128:48 + --> tests/ui/unnecessary_to_owned.rs:130:48 | LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:130:20 + --> tests/ui/unnecessary_to_owned.rs:132:20 | LL | let _ = x.join(&x_ref.to_string()); | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:132:13 + --> tests/ui/unnecessary_to_owned.rs:134:13 | LL | let _ = slice.to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:133:13 + --> tests/ui/unnecessary_to_owned.rs:135:13 | LL | let _ = slice.to_owned().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:134:13 + --> tests/ui/unnecessary_to_owned.rs:136:13 | LL | let _ = [std::path::PathBuf::new()][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:135:13 + --> tests/ui/unnecessary_to_owned.rs:137:13 | LL | let _ = [std::path::PathBuf::new()][..].to_owned().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:137:13 + --> tests/ui/unnecessary_to_owned.rs:139:13 | LL | let _ = IntoIterator::into_iter(slice.to_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:138:13 + --> tests/ui/unnecessary_to_owned.rs:140:13 | LL | let _ = IntoIterator::into_iter(slice.to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:139:13 + --> tests/ui/unnecessary_to_owned.rs:141:13 | LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:140:13 + --> tests/ui/unnecessary_to_owned.rs:142:13 | LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: allocating a new `String` only to create a temporary `&str` from it - --> tests/ui/unnecessary_to_owned.rs:162:26 + --> tests/ui/unnecessary_to_owned.rs:164:26 | LL | let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -490,7 +490,7 @@ LL + let _ref_str: &str = core::str::from_utf8(&slice).expect("not UTF-8"); | error: allocating a new `String` only to create a temporary `&str` from it - --> tests/ui/unnecessary_to_owned.rs:163:26 + --> tests/ui/unnecessary_to_owned.rs:165:26 | LL | let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -502,7 +502,7 @@ LL + let _ref_str: &str = core::str::from_utf8(b"foo").unwrap(); | error: allocating a new `String` only to create a temporary `&str` from it - --> tests/ui/unnecessary_to_owned.rs:164:26 + --> tests/ui/unnecessary_to_owned.rs:166:26 | LL | let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -514,7 +514,7 @@ LL + let _ref_str: &str = core::str::from_utf8(b"foo".as_slice()).unwrap(); | error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:221:14 + --> tests/ui/unnecessary_to_owned.rs:223:14 | LL | for t in file_types.to_vec() { | ^^^^^^^^^^^^^^^^^^^ @@ -530,61 +530,61 @@ LL + let path = match get_file_path(t) { | error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:244:14 + --> tests/ui/unnecessary_to_owned.rs:246:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().cloned()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:249:14 + --> tests/ui/unnecessary_to_owned.rs:251:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().copied()` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:297:24 + --> tests/ui/unnecessary_to_owned.rs:299:24 | LL | Box::new(build(y.to_string())) | ^^^^^^^^^^^^^ help: use: `y` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:406:12 + --> tests/ui/unnecessary_to_owned.rs:408:12 | LL | id("abc".to_string()) | ^^^^^^^^^^^^^^^^^ help: use: `"abc"` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:549:37 + --> tests/ui/unnecessary_to_owned.rs:551:37 | LL | IntoFuture::into_future(foo([].to_vec(), &0)); | ^^^^^^^^^^^ help: use: `[]` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:559:18 + --> tests/ui/unnecessary_to_owned.rs:561:18 | LL | s.remove(&a.to_vec()); | ^^^^^^^^^^^ help: replace it with: `a` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:563:14 + --> tests/ui/unnecessary_to_owned.rs:565:14 | LL | s.remove(&"b".to_owned()); | ^^^^^^^^^^^^^^^ help: replace it with: `"b"` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:564:14 + --> tests/ui/unnecessary_to_owned.rs:566:14 | LL | s.remove(&"b".to_string()); | ^^^^^^^^^^^^^^^^ help: replace it with: `"b"` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:569:14 + --> tests/ui/unnecessary_to_owned.rs:571:14 | LL | s.remove(&["b"].to_vec()); | ^^^^^^^^^^^^^^^ help: replace it with: `["b"].as_slice()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:570:14 + --> tests/ui/unnecessary_to_owned.rs:572:14 | LL | s.remove(&(&["b"]).to_vec()); | ^^^^^^^^^^^^^^^^^^ help: replace it with: `(&["b"]).as_slice()` From 772315de7c1f68bb95de5a7eb85cb2f167834c53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Mon, 8 Jul 2024 14:30:17 +0200 Subject: [PATCH 129/734] Remove generic lifetime parameter of trait `Pattern` Use a GAT for `Searcher` associated type because this trait is always implemented for every lifetime anyway. --- library/alloc/src/str.rs | 4 +- library/alloc/src/string.rs | 27 ++-- library/alloc/tests/str.rs | 14 +- library/core/src/str/iter.rs | 90 ++++++------ library/core/src/str/mod.rs | 75 +++++----- library/core/src/str/pattern.rs | 132 +++++++++--------- tests/ui/suggestions/issue-104961.fixed | 4 +- tests/ui/suggestions/issue-104961.rs | 4 +- tests/ui/suggestions/issue-104961.stderr | 12 +- tests/ui/suggestions/issue-62843.stderr | 6 +- .../bound/assoc-fn-bound-root-obligation.rs | 12 +- .../assoc-fn-bound-root-obligation.stderr | 15 +- .../root-obligation.fixed | 2 +- .../suggest-dereferences/root-obligation.rs | 2 +- .../root-obligation.stderr | 6 +- 15 files changed, 207 insertions(+), 198 deletions(-) diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 3bb808a6c73a..94053ef83a0e 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -269,7 +269,7 @@ impl str { without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn replace<'a, P: Pattern<'a>>(&'a self, from: P, to: &str) -> String { + pub fn replace(&self, from: P, to: &str) -> String { let mut result = String::new(); let mut last_end = 0; for (start, part) in self.match_indices(from) { @@ -309,7 +309,7 @@ impl str { #[must_use = "this returns the replaced string as a new allocation, \ without modifying the original"] #[stable(feature = "str_replacen", since = "1.16.0")] - pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) -> String { + pub fn replacen(&self, pat: P, to: &str, count: usize) -> String { // Hope to reduce the times of re-allocation let mut result = String::with_capacity(32); let mut last_end = 0; diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 07ffd3e15191..0ff66167a46a 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1497,10 +1497,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "string_remove_matches", reason = "new API", issue = "72826")] - pub fn remove_matches<'a, P>(&'a mut self, pat: P) - where - P: for<'x> Pattern<'x>, - { + pub fn remove_matches(&mut self, pat: P) { use core::str::pattern::Searcher; let rejections = { @@ -2288,35 +2285,41 @@ impl<'a> Extend> for String { reason = "API not fully fleshed out and ready to be stabilized", issue = "27721" )] -impl<'a, 'b> Pattern<'a> for &'b String { - type Searcher = <&'b str as Pattern<'a>>::Searcher; +impl<'b> Pattern for &'b String { + type Searcher<'a> = <&'b str as Pattern>::Searcher<'a>; - fn into_searcher(self, haystack: &'a str) -> <&'b str as Pattern<'a>>::Searcher { + fn into_searcher(self, haystack: &str) -> <&'b str as Pattern>::Searcher<'_> { self[..].into_searcher(haystack) } #[inline] - fn is_contained_in(self, haystack: &'a str) -> bool { + fn is_contained_in(self, haystack: &str) -> bool { self[..].is_contained_in(haystack) } #[inline] - fn is_prefix_of(self, haystack: &'a str) -> bool { + fn is_prefix_of(self, haystack: &str) -> bool { self[..].is_prefix_of(haystack) } #[inline] - fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> { + fn strip_prefix_of(self, haystack: &str) -> Option<&str> { self[..].strip_prefix_of(haystack) } #[inline] - fn is_suffix_of(self, haystack: &'a str) -> bool { + fn is_suffix_of<'a>(self, haystack: &'a str) -> bool + where + Self::Searcher<'a>: core::str::pattern::ReverseSearcher<'a>, + { self[..].is_suffix_of(haystack) } #[inline] - fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> { + fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&str> + where + Self::Searcher<'a>: core::str::pattern::ReverseSearcher<'a>, + { self[..].strip_suffix_of(haystack) } } diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index 0078f5eaa3d2..de5d3991c914 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1927,12 +1927,10 @@ mod pattern { } } - fn cmp_search_to_vec<'a>( - rev: bool, - pat: impl Pattern<'a, Searcher: ReverseSearcher<'a>>, - haystack: &'a str, - right: Vec, - ) { + fn cmp_search_to_vec

(rev: bool, pat: P, haystack: &str, right: Vec) + where + P: for<'a> Pattern: ReverseSearcher<'a>>, + { let mut searcher = pat.into_searcher(haystack); let mut v = vec![]; loop { @@ -2191,9 +2189,9 @@ generate_iterator_test! { fn different_str_pattern_forwarding_lifetimes() { use std::str::pattern::Pattern; - fn foo<'a, P>(p: P) + fn foo

(p: P) where - for<'b> &'b P: Pattern<'a>, + for<'b> &'b P: Pattern, { for _ in 0..3 { "asdf".find(&p); diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 19627f28e64f..5845e3b5481a 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -411,7 +411,7 @@ macro_rules! derive_pattern_clone { (clone $t:ident with |$s:ident| $e:expr) => { impl<'a, P> Clone for $t<'a, P> where - P: Pattern<'a, Searcher: Clone>, + P: Pattern: Clone>, { fn clone(&self) -> Self { let $s = self; @@ -424,7 +424,7 @@ macro_rules! derive_pattern_clone { /// This macro generates two public iterator structs /// wrapping a private internal one that makes use of the `Pattern` API. /// -/// For all patterns `P: Pattern<'a>` the following items will be +/// For all patterns `P: Pattern` the following items will be /// generated (generics omitted): /// /// struct $forward_iterator($internal_iterator); @@ -484,12 +484,12 @@ macro_rules! generate_pattern_iterators { } => { $(#[$forward_iterator_attribute])* $(#[$common_stability_attribute])* - pub struct $forward_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>); + pub struct $forward_iterator<'a, P: Pattern>(pub(super) $internal_iterator<'a, P>); $(#[$common_stability_attribute])* impl<'a, P> fmt::Debug for $forward_iterator<'a, P> where - P: Pattern<'a, Searcher: fmt::Debug>, + P: Pattern: fmt::Debug>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple(stringify!($forward_iterator)) @@ -499,7 +499,7 @@ macro_rules! generate_pattern_iterators { } $(#[$common_stability_attribute])* - impl<'a, P: Pattern<'a>> Iterator for $forward_iterator<'a, P> { + impl<'a, P: Pattern> Iterator for $forward_iterator<'a, P> { type Item = $iterty; #[inline] @@ -511,7 +511,7 @@ macro_rules! generate_pattern_iterators { $(#[$common_stability_attribute])* impl<'a, P> Clone for $forward_iterator<'a, P> where - P: Pattern<'a, Searcher: Clone>, + P: Pattern: Clone>, { fn clone(&self) -> Self { $forward_iterator(self.0.clone()) @@ -520,12 +520,12 @@ macro_rules! generate_pattern_iterators { $(#[$reverse_iterator_attribute])* $(#[$common_stability_attribute])* - pub struct $reverse_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>); + pub struct $reverse_iterator<'a, P: Pattern>(pub(super) $internal_iterator<'a, P>); $(#[$common_stability_attribute])* impl<'a, P> fmt::Debug for $reverse_iterator<'a, P> where - P: Pattern<'a, Searcher: fmt::Debug>, + P: Pattern: fmt::Debug>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple(stringify!($reverse_iterator)) @@ -537,7 +537,7 @@ macro_rules! generate_pattern_iterators { $(#[$common_stability_attribute])* impl<'a, P> Iterator for $reverse_iterator<'a, P> where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + P: Pattern: ReverseSearcher<'a>>, { type Item = $iterty; @@ -550,7 +550,7 @@ macro_rules! generate_pattern_iterators { $(#[$common_stability_attribute])* impl<'a, P> Clone for $reverse_iterator<'a, P> where - P: Pattern<'a, Searcher: Clone>, + P: Pattern: Clone>, { fn clone(&self) -> Self { $reverse_iterator(self.0.clone()) @@ -558,12 +558,12 @@ macro_rules! generate_pattern_iterators { } #[stable(feature = "fused", since = "1.26.0")] - impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {} + impl<'a, P: Pattern> FusedIterator for $forward_iterator<'a, P> {} #[stable(feature = "fused", since = "1.26.0")] impl<'a, P> FusedIterator for $reverse_iterator<'a, P> where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + P: Pattern: ReverseSearcher<'a>>, {} generate_pattern_iterators!($($t)* with $(#[$common_stability_attribute])*, @@ -578,7 +578,7 @@ macro_rules! generate_pattern_iterators { $(#[$common_stability_attribute])* impl<'a, P> DoubleEndedIterator for $forward_iterator<'a, P> where - P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, + P: Pattern: DoubleEndedSearcher<'a>>, { #[inline] fn next_back(&mut self) -> Option<$iterty> { @@ -589,7 +589,7 @@ macro_rules! generate_pattern_iterators { $(#[$common_stability_attribute])* impl<'a, P> DoubleEndedIterator for $reverse_iterator<'a, P> where - P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, + P: Pattern: DoubleEndedSearcher<'a>>, { #[inline] fn next_back(&mut self) -> Option<$iterty> { @@ -609,17 +609,17 @@ derive_pattern_clone! { with |s| SplitInternal { matcher: s.matcher.clone(), ..*s } } -pub(super) struct SplitInternal<'a, P: Pattern<'a>> { +pub(super) struct SplitInternal<'a, P: Pattern> { pub(super) start: usize, pub(super) end: usize, - pub(super) matcher: P::Searcher, + pub(super) matcher: P::Searcher<'a>, pub(super) allow_trailing_empty: bool, pub(super) finished: bool, } impl<'a, P> fmt::Debug for SplitInternal<'a, P> where - P: Pattern<'a, Searcher: fmt::Debug>, + P: Pattern: fmt::Debug>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SplitInternal") @@ -632,7 +632,7 @@ where } } -impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { +impl<'a, P: Pattern> SplitInternal<'a, P> { #[inline] fn get_end(&mut self) -> Option<&'a str> { if !self.finished { @@ -689,7 +689,7 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { #[inline] fn next_back(&mut self) -> Option<&'a str> where - P::Searcher: ReverseSearcher<'a>, + P::Searcher<'a>: ReverseSearcher<'a>, { if self.finished { return None; @@ -726,7 +726,7 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { #[inline] fn next_back_inclusive(&mut self) -> Option<&'a str> where - P::Searcher: ReverseSearcher<'a>, + P::Searcher<'a>: ReverseSearcher<'a>, { if self.finished { return None; @@ -796,7 +796,7 @@ generate_pattern_iterators! { delegate double ended; } -impl<'a, P: Pattern<'a>> Split<'a, P> { +impl<'a, P: Pattern> Split<'a, P> { /// Returns remainder of the split string. /// /// If the iterator is empty, returns `None`. @@ -819,7 +819,7 @@ impl<'a, P: Pattern<'a>> Split<'a, P> { } } -impl<'a, P: Pattern<'a>> RSplit<'a, P> { +impl<'a, P: Pattern> RSplit<'a, P> { /// Returns remainder of the split string. /// /// If the iterator is empty, returns `None`. @@ -860,7 +860,7 @@ generate_pattern_iterators! { delegate double ended; } -impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> { +impl<'a, P: Pattern> SplitTerminator<'a, P> { /// Returns remainder of the split string. /// /// If the iterator is empty, returns `None`. @@ -883,7 +883,7 @@ impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> { } } -impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> { +impl<'a, P: Pattern> RSplitTerminator<'a, P> { /// Returns remainder of the split string. /// /// If the iterator is empty, returns `None`. @@ -911,7 +911,7 @@ derive_pattern_clone! { with |s| SplitNInternal { iter: s.iter.clone(), ..*s } } -pub(super) struct SplitNInternal<'a, P: Pattern<'a>> { +pub(super) struct SplitNInternal<'a, P: Pattern> { pub(super) iter: SplitInternal<'a, P>, /// The number of splits remaining pub(super) count: usize, @@ -919,7 +919,7 @@ pub(super) struct SplitNInternal<'a, P: Pattern<'a>> { impl<'a, P> fmt::Debug for SplitNInternal<'a, P> where - P: Pattern<'a, Searcher: fmt::Debug>, + P: Pattern: fmt::Debug>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SplitNInternal") @@ -929,7 +929,7 @@ where } } -impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { +impl<'a, P: Pattern> SplitNInternal<'a, P> { #[inline] fn next(&mut self) -> Option<&'a str> { match self.count { @@ -948,7 +948,7 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { #[inline] fn next_back(&mut self) -> Option<&'a str> where - P::Searcher: ReverseSearcher<'a>, + P::Searcher<'a>: ReverseSearcher<'a>, { match self.count { 0 => None, @@ -987,7 +987,7 @@ generate_pattern_iterators! { delegate single ended; } -impl<'a, P: Pattern<'a>> SplitN<'a, P> { +impl<'a, P: Pattern> SplitN<'a, P> { /// Returns remainder of the split string. /// /// If the iterator is empty, returns `None`. @@ -1010,7 +1010,7 @@ impl<'a, P: Pattern<'a>> SplitN<'a, P> { } } -impl<'a, P: Pattern<'a>> RSplitN<'a, P> { +impl<'a, P: Pattern> RSplitN<'a, P> { /// Returns remainder of the split string. /// /// If the iterator is empty, returns `None`. @@ -1038,18 +1038,18 @@ derive_pattern_clone! { with |s| MatchIndicesInternal(s.0.clone()) } -pub(super) struct MatchIndicesInternal<'a, P: Pattern<'a>>(pub(super) P::Searcher); +pub(super) struct MatchIndicesInternal<'a, P: Pattern>(pub(super) P::Searcher<'a>); impl<'a, P> fmt::Debug for MatchIndicesInternal<'a, P> where - P: Pattern<'a, Searcher: fmt::Debug>, + P: Pattern: fmt::Debug>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("MatchIndicesInternal").field(&self.0).finish() } } -impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { +impl<'a, P: Pattern> MatchIndicesInternal<'a, P> { #[inline] fn next(&mut self) -> Option<(usize, &'a str)> { self.0 @@ -1061,7 +1061,7 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { #[inline] fn next_back(&mut self) -> Option<(usize, &'a str)> where - P::Searcher: ReverseSearcher<'a>, + P::Searcher<'a>: ReverseSearcher<'a>, { self.0 .next_match_back() @@ -1093,18 +1093,18 @@ derive_pattern_clone! { with |s| MatchesInternal(s.0.clone()) } -pub(super) struct MatchesInternal<'a, P: Pattern<'a>>(pub(super) P::Searcher); +pub(super) struct MatchesInternal<'a, P: Pattern>(pub(super) P::Searcher<'a>); impl<'a, P> fmt::Debug for MatchesInternal<'a, P> where - P: Pattern<'a, Searcher: fmt::Debug>, + P: Pattern: fmt::Debug>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("MatchesInternal").field(&self.0).finish() } } -impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { +impl<'a, P: Pattern> MatchesInternal<'a, P> { #[inline] fn next(&mut self) -> Option<&'a str> { // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. @@ -1117,7 +1117,7 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { #[inline] fn next_back(&mut self) -> Option<&'a str> where - P::Searcher: ReverseSearcher<'a>, + P::Searcher<'a>: ReverseSearcher<'a>, { // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. self.0.next_match_back().map(|(a, b)| unsafe { @@ -1288,7 +1288,7 @@ pub struct SplitAsciiWhitespace<'a> { /// /// [`split_inclusive`]: str::split_inclusive #[stable(feature = "split_inclusive", since = "1.51.0")] -pub struct SplitInclusive<'a, P: Pattern<'a>>(pub(super) SplitInternal<'a, P>); +pub struct SplitInclusive<'a, P: Pattern>(pub(super) SplitInternal<'a, P>); #[stable(feature = "split_whitespace", since = "1.1.0")] impl<'a> Iterator for SplitWhitespace<'a> { @@ -1410,7 +1410,7 @@ impl<'a> SplitAsciiWhitespace<'a> { } #[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> { +impl<'a, P: Pattern> Iterator for SplitInclusive<'a, P> { type Item = &'a str; #[inline] @@ -1420,7 +1420,7 @@ impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> { } #[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a, P> { +impl<'a, P: Pattern: fmt::Debug>> fmt::Debug for SplitInclusive<'a, P> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SplitInclusive").field("0", &self.0).finish() } @@ -1428,14 +1428,14 @@ impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a, // FIXME(#26925) Remove in favor of `#[derive(Clone)]` #[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a, Searcher: Clone>> Clone for SplitInclusive<'a, P> { +impl<'a, P: Pattern: Clone>> Clone for SplitInclusive<'a, P> { fn clone(&self) -> Self { SplitInclusive(self.0.clone()) } } #[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>> DoubleEndedIterator +impl<'a, P: Pattern: DoubleEndedSearcher<'a>>> DoubleEndedIterator for SplitInclusive<'a, P> { #[inline] @@ -1445,9 +1445,9 @@ impl<'a, P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>> DoubleEndedIterator } #[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {} +impl<'a, P: Pattern> FusedIterator for SplitInclusive<'a, P> {} -impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> { +impl<'a, P: Pattern> SplitInclusive<'a, P> { /// Returns remainder of the split string. /// /// If the iterator is empty, returns `None`. diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 683109380439..0537b3d93c46 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -1137,7 +1137,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { + pub fn contains(&self, pat: P) -> bool { pat.is_contained_in(self) } @@ -1174,7 +1174,7 @@ impl str { /// assert!(bananas.starts_with(&['a', 'b', 'c', 'd'])); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { + pub fn starts_with(&self, pat: P) -> bool { pat.is_prefix_of(self) } @@ -1198,9 +1198,9 @@ impl str { /// assert!(!bananas.ends_with("nana")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn ends_with<'a, P>(&'a self, pat: P) -> bool + pub fn ends_with(&self, pat: P) -> bool where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { pat.is_suffix_of(self) } @@ -1249,7 +1249,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { + pub fn find(&self, pat: P) -> Option { pat.into_searcher(self).next_match().map(|(i, _)| i) } @@ -1295,9 +1295,9 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn rfind<'a, P>(&'a self, pat: P) -> Option + pub fn rfind(&self, pat: P) -> Option where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { pat.into_searcher(self).next_match_back().map(|(i, _)| i) } @@ -1417,7 +1417,7 @@ impl str { /// [`split_whitespace`]: str::split_whitespace #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { + pub fn split(&self, pat: P) -> Split<'_, P> { Split(SplitInternal { start: 0, end: self.len(), @@ -1457,7 +1457,7 @@ impl str { /// ``` #[stable(feature = "split_inclusive", since = "1.51.0")] #[inline] - pub fn split_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitInclusive<'a, P> { + pub fn split_inclusive(&self, pat: P) -> SplitInclusive<'_, P> { SplitInclusive(SplitInternal { start: 0, end: self.len(), @@ -1512,9 +1512,9 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn rsplit<'a, P>(&'a self, pat: P) -> RSplit<'a, P> + pub fn rsplit(&self, pat: P) -> RSplit<'_, P> where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { RSplit(self.split(pat).0) } @@ -1561,7 +1561,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { + pub fn split_terminator(&self, pat: P) -> SplitTerminator<'_, P> { SplitTerminator(SplitInternal { allow_trailing_empty: false, ..self.split(pat).0 }) } @@ -1607,9 +1607,9 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn rsplit_terminator<'a, P>(&'a self, pat: P) -> RSplitTerminator<'a, P> + pub fn rsplit_terminator(&self, pat: P) -> RSplitTerminator<'_, P> where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { RSplitTerminator(self.split_terminator(pat).0) } @@ -1662,7 +1662,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> { + pub fn splitn(&self, n: usize, pat: P) -> SplitN<'_, P> { SplitN(SplitNInternal { iter: self.split(pat).0, count: n }) } @@ -1711,9 +1711,9 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn rsplitn<'a, P>(&'a self, n: usize, pat: P) -> RSplitN<'a, P> + pub fn rsplitn(&self, n: usize, pat: P) -> RSplitN<'_, P> where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { RSplitN(self.splitn(n, pat).0) } @@ -1731,7 +1731,7 @@ impl str { /// ``` #[stable(feature = "str_split_once", since = "1.52.0")] #[inline] - pub fn split_once<'a, P: Pattern<'a>>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)> { + pub fn split_once(&self, delimiter: P) -> Option<(&'_ str, &'_ str)> { let (start, end) = delimiter.into_searcher(self).next_match()?; // SAFETY: `Searcher` is known to return valid indices. unsafe { Some((self.get_unchecked(..start), self.get_unchecked(end..))) } @@ -1749,9 +1749,9 @@ impl str { /// ``` #[stable(feature = "str_split_once", since = "1.52.0")] #[inline] - pub fn rsplit_once<'a, P>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)> + pub fn rsplit_once(&self, delimiter: P) -> Option<(&'_ str, &'_ str)> where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { let (start, end) = delimiter.into_searcher(self).next_match_back()?; // SAFETY: `Searcher` is known to return valid indices. @@ -1789,7 +1789,7 @@ impl str { /// ``` #[stable(feature = "str_matches", since = "1.2.0")] #[inline] - pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> { + pub fn matches(&self, pat: P) -> Matches<'_, P> { Matches(MatchesInternal(pat.into_searcher(self))) } @@ -1823,9 +1823,9 @@ impl str { /// ``` #[stable(feature = "str_matches", since = "1.2.0")] #[inline] - pub fn rmatches<'a, P>(&'a self, pat: P) -> RMatches<'a, P> + pub fn rmatches(&self, pat: P) -> RMatches<'_, P> where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { RMatches(self.matches(pat).0) } @@ -1867,7 +1867,7 @@ impl str { /// ``` #[stable(feature = "str_match_indices", since = "1.5.0")] #[inline] - pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> { + pub fn match_indices(&self, pat: P) -> MatchIndices<'_, P> { MatchIndices(MatchIndicesInternal(pat.into_searcher(self))) } @@ -1907,9 +1907,9 @@ impl str { /// ``` #[stable(feature = "str_match_indices", since = "1.5.0")] #[inline] - pub fn rmatch_indices<'a, P>(&'a self, pat: P) -> RMatchIndices<'a, P> + pub fn rmatch_indices(&self, pat: P) -> RMatchIndices<'_, P> where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { RMatchIndices(self.match_indices(pat).0) } @@ -2122,9 +2122,9 @@ impl str { #[must_use = "this returns the trimmed string as a new slice, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim_matches<'a, P>(&'a self, pat: P) -> &'a str + pub fn trim_matches(&self, pat: P) -> &str where - P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, + for<'a> P::Searcher<'a>: DoubleEndedSearcher<'a>, { let mut i = 0; let mut j = 0; @@ -2169,7 +2169,7 @@ impl str { #[must_use = "this returns the trimmed string as a new slice, \ without modifying the original"] #[stable(feature = "trim_direction", since = "1.30.0")] - pub fn trim_start_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { + pub fn trim_start_matches(&self, pat: P) -> &str { let mut i = self.len(); let mut matcher = pat.into_searcher(self); if let Some((a, _)) = matcher.next_reject() { @@ -2202,7 +2202,7 @@ impl str { #[must_use = "this returns the remaining substring as a new slice, \ without modifying the original"] #[stable(feature = "str_strip", since = "1.45.0")] - pub fn strip_prefix<'a, P: Pattern<'a>>(&'a self, prefix: P) -> Option<&'a str> { + pub fn strip_prefix(&self, prefix: P) -> Option<&str> { prefix.strip_prefix_of(self) } @@ -2229,10 +2229,9 @@ impl str { #[must_use = "this returns the remaining substring as a new slice, \ without modifying the original"] #[stable(feature = "str_strip", since = "1.45.0")] - pub fn strip_suffix<'a, P>(&'a self, suffix: P) -> Option<&'a str> + pub fn strip_suffix(&self, suffix: P) -> Option<&str> where - P: Pattern<'a>, -

>::Searcher: ReverseSearcher<'a>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { suffix.strip_suffix_of(self) } @@ -2273,9 +2272,9 @@ impl str { #[must_use = "this returns the trimmed string as a new slice, \ without modifying the original"] #[stable(feature = "trim_direction", since = "1.30.0")] - pub fn trim_end_matches<'a, P>(&'a self, pat: P) -> &'a str + pub fn trim_end_matches(&self, pat: P) -> &str where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { let mut j = 0; let mut matcher = pat.into_searcher(self); @@ -2317,7 +2316,7 @@ impl str { note = "superseded by `trim_start_matches`", suggestion = "trim_start_matches" )] - pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { + pub fn trim_left_matches(&self, pat: P) -> &str { self.trim_start_matches(pat) } @@ -2360,9 +2359,9 @@ impl str { note = "superseded by `trim_end_matches`", suggestion = "trim_end_matches" )] - pub fn trim_right_matches<'a, P>(&'a self, pat: P) -> &'a str + pub fn trim_right_matches(&self, pat: P) -> &str where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { self.trim_end_matches(pat) } diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index 8988229be2e5..33a5d45e445d 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -48,8 +48,8 @@ use crate::slice::memchr; /// A string pattern. /// -/// A `Pattern<'a>` expresses that the implementing type -/// can be used as a string pattern for searching in a [`&'a str`][str]. +/// A `Pattern` expresses that the implementing type +/// can be used as a string pattern for searching in a [`&str`][str]. /// /// For example, both `'a'` and `"aa"` are patterns that /// would match at index `1` in the string `"baaaab"`. @@ -97,38 +97,38 @@ use crate::slice::memchr; /// assert_eq!("abcdef_z".find(|ch| ch > 'd' && ch < 'y'), Some(4)); /// assert_eq!("abcddd_z".find(|ch| ch > 'd' && ch < 'y'), None); /// ``` -pub trait Pattern<'a>: Sized { +pub trait Pattern: Sized { /// Associated searcher for this pattern - type Searcher: Searcher<'a>; + type Searcher<'a>: Searcher<'a>; /// Constructs the associated searcher from /// `self` and the `haystack` to search in. - fn into_searcher(self, haystack: &'a str) -> Self::Searcher; + fn into_searcher(self, haystack: &str) -> Self::Searcher<'_>; /// Checks whether the pattern matches anywhere in the haystack #[inline] - fn is_contained_in(self, haystack: &'a str) -> bool { + fn is_contained_in(self, haystack: &str) -> bool { self.into_searcher(haystack).next_match().is_some() } /// Checks whether the pattern matches at the front of the haystack #[inline] - fn is_prefix_of(self, haystack: &'a str) -> bool { + fn is_prefix_of(self, haystack: &str) -> bool { matches!(self.into_searcher(haystack).next(), SearchStep::Match(0, _)) } /// Checks whether the pattern matches at the back of the haystack #[inline] - fn is_suffix_of(self, haystack: &'a str) -> bool + fn is_suffix_of<'a>(self, haystack: &'a str) -> bool where - Self::Searcher: ReverseSearcher<'a>, + Self::Searcher<'a>: ReverseSearcher<'a>, { matches!(self.into_searcher(haystack).next_back(), SearchStep::Match(_, j) if haystack.len() == j) } /// Removes the pattern from the front of haystack, if it matches. #[inline] - fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> { + fn strip_prefix_of(self, haystack: &str) -> Option<&str> { if let SearchStep::Match(start, len) = self.into_searcher(haystack).next() { debug_assert_eq!( start, 0, @@ -144,9 +144,9 @@ pub trait Pattern<'a>: Sized { /// Removes the pattern from the back of haystack, if it matches. #[inline] - fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> + fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&'a str> where - Self::Searcher: ReverseSearcher<'a>, + Self::Searcher<'a>: ReverseSearcher<'a>, { if let SearchStep::Match(start, end) = self.into_searcher(haystack).next_back() { debug_assert_eq!( @@ -349,7 +349,7 @@ pub trait DoubleEndedSearcher<'a>: ReverseSearcher<'a> {} // Impl for char ///////////////////////////////////////////////////////////////////////////// -/// Associated type for `>::Searcher`. +/// Associated type for `::Searcher<'a>`. #[derive(Clone, Debug)] pub struct CharSearcher<'a> { haystack: &'a str, @@ -543,11 +543,11 @@ impl<'a> DoubleEndedSearcher<'a> for CharSearcher<'a> {} /// ``` /// assert_eq!("Hello world".find('o'), Some(4)); /// ``` -impl<'a> Pattern<'a> for char { - type Searcher = CharSearcher<'a>; +impl Pattern for char { + type Searcher<'a> = CharSearcher<'a>; #[inline] - fn into_searcher(self, haystack: &'a str) -> Self::Searcher { + fn into_searcher(self, haystack: &str) -> Self::Searcher<'_> { let mut utf8_encoded = [0; 4]; let utf8_size = self .encode_utf8(&mut utf8_encoded) @@ -566,7 +566,7 @@ impl<'a> Pattern<'a> for char { } #[inline] - fn is_contained_in(self, haystack: &'a str) -> bool { + fn is_contained_in(self, haystack: &str) -> bool { if (self as u32) < 128 { haystack.as_bytes().contains(&(self as u8)) } else { @@ -576,27 +576,27 @@ impl<'a> Pattern<'a> for char { } #[inline] - fn is_prefix_of(self, haystack: &'a str) -> bool { + fn is_prefix_of(self, haystack: &str) -> bool { self.encode_utf8(&mut [0u8; 4]).is_prefix_of(haystack) } #[inline] - fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> { + fn strip_prefix_of(self, haystack: &str) -> Option<&str> { self.encode_utf8(&mut [0u8; 4]).strip_prefix_of(haystack) } #[inline] - fn is_suffix_of(self, haystack: &'a str) -> bool + fn is_suffix_of<'a>(self, haystack: &'a str) -> bool where - Self::Searcher: ReverseSearcher<'a>, + Self::Searcher<'a>: ReverseSearcher<'a>, { self.encode_utf8(&mut [0u8; 4]).is_suffix_of(haystack) } #[inline] - fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> + fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&'a str> where - Self::Searcher: ReverseSearcher<'a>, + Self::Searcher<'a>: ReverseSearcher<'a>, { self.encode_utf8(&mut [0u8; 4]).strip_suffix_of(haystack) } @@ -651,11 +651,11 @@ struct MultiCharEqSearcher<'a, C: MultiCharEq> { char_indices: super::CharIndices<'a>, } -impl<'a, C: MultiCharEq> Pattern<'a> for MultiCharEqPattern { - type Searcher = MultiCharEqSearcher<'a, C>; +impl Pattern for MultiCharEqPattern { + type Searcher<'a> = MultiCharEqSearcher<'a, C>; #[inline] - fn into_searcher(self, haystack: &'a str) -> MultiCharEqSearcher<'a, C> { + fn into_searcher(self, haystack: &str) -> MultiCharEqSearcher<'_, C> { MultiCharEqSearcher { haystack, char_eq: self.0, char_indices: haystack.char_indices() } } } @@ -710,41 +710,41 @@ impl<'a, C: MultiCharEq> DoubleEndedSearcher<'a> for MultiCharEqSearcher<'a, C> ///////////////////////////////////////////////////////////////////////////// macro_rules! pattern_methods { - ($t:ty, $pmap:expr, $smap:expr) => { - type Searcher = $t; + ($a:lifetime, $t:ty, $pmap:expr, $smap:expr) => { + type Searcher<$a> = $t; #[inline] - fn into_searcher(self, haystack: &'a str) -> $t { + fn into_searcher<$a>(self, haystack: &$a str) -> $t { ($smap)(($pmap)(self).into_searcher(haystack)) } #[inline] - fn is_contained_in(self, haystack: &'a str) -> bool { + fn is_contained_in<$a>(self, haystack: &$a str) -> bool { ($pmap)(self).is_contained_in(haystack) } #[inline] - fn is_prefix_of(self, haystack: &'a str) -> bool { + fn is_prefix_of<$a>(self, haystack: &$a str) -> bool { ($pmap)(self).is_prefix_of(haystack) } #[inline] - fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> { + fn strip_prefix_of<$a>(self, haystack: &$a str) -> Option<&$a str> { ($pmap)(self).strip_prefix_of(haystack) } #[inline] - fn is_suffix_of(self, haystack: &'a str) -> bool + fn is_suffix_of<$a>(self, haystack: &$a str) -> bool where - $t: ReverseSearcher<'a>, + $t: ReverseSearcher<$a>, { ($pmap)(self).is_suffix_of(haystack) } #[inline] - fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> + fn strip_suffix_of<$a>(self, haystack: &$a str) -> Option<&$a str> where - $t: ReverseSearcher<'a>, + $t: ReverseSearcher<$a>, { ($pmap)(self).strip_suffix_of(haystack) } @@ -786,16 +786,16 @@ macro_rules! searcher_methods { }; } -/// Associated type for `<[char; N] as Pattern<'a>>::Searcher`. +/// Associated type for `<[char; N] as Pattern>::Searcher<'a>`. #[derive(Clone, Debug)] pub struct CharArraySearcher<'a, const N: usize>( - as Pattern<'a>>::Searcher, + as Pattern>::Searcher<'a>, ); -/// Associated type for `<&[char; N] as Pattern<'a>>::Searcher`. +/// Associated type for `<&[char; N] as Pattern>::Searcher<'a>`. #[derive(Clone, Debug)] pub struct CharArrayRefSearcher<'a, 'b, const N: usize>( - as Pattern<'a>>::Searcher, + as Pattern>::Searcher<'a>, ); /// Searches for chars that are equal to any of the [`char`]s in the array. @@ -806,8 +806,8 @@ pub struct CharArrayRefSearcher<'a, 'b, const N: usize>( /// assert_eq!("Hello world".find(['o', 'l']), Some(2)); /// assert_eq!("Hello world".find(['h', 'w']), Some(6)); /// ``` -impl<'a, const N: usize> Pattern<'a> for [char; N] { - pattern_methods!(CharArraySearcher<'a, N>, MultiCharEqPattern, CharArraySearcher); +impl Pattern for [char; N] { + pattern_methods!('a, CharArraySearcher<'a, N>, MultiCharEqPattern, CharArraySearcher); } unsafe impl<'a, const N: usize> Searcher<'a> for CharArraySearcher<'a, N> { @@ -828,8 +828,8 @@ impl<'a, const N: usize> DoubleEndedSearcher<'a> for CharArraySearcher<'a, N> {} /// assert_eq!("Hello world".find(&['o', 'l']), Some(2)); /// assert_eq!("Hello world".find(&['h', 'w']), Some(6)); /// ``` -impl<'a, 'b, const N: usize> Pattern<'a> for &'b [char; N] { - pattern_methods!(CharArrayRefSearcher<'a, 'b, N>, MultiCharEqPattern, CharArrayRefSearcher); +impl<'b, const N: usize> Pattern for &'b [char; N] { + pattern_methods!('a, CharArrayRefSearcher<'a, 'b, N>, MultiCharEqPattern, CharArrayRefSearcher); } unsafe impl<'a, 'b, const N: usize> Searcher<'a> for CharArrayRefSearcher<'a, 'b, N> { @@ -848,9 +848,9 @@ impl<'a, 'b, const N: usize> DoubleEndedSearcher<'a> for CharArrayRefSearcher<'a // Todo: Change / Remove due to ambiguity in meaning. -/// Associated type for `<&[char] as Pattern<'a>>::Searcher`. +/// Associated type for `<&[char] as Pattern>::Searcher<'a>`. #[derive(Clone, Debug)] -pub struct CharSliceSearcher<'a, 'b>( as Pattern<'a>>::Searcher); +pub struct CharSliceSearcher<'a, 'b>( as Pattern>::Searcher<'a>); unsafe impl<'a, 'b> Searcher<'a> for CharSliceSearcher<'a, 'b> { searcher_methods!(forward); @@ -870,17 +870,17 @@ impl<'a, 'b> DoubleEndedSearcher<'a> for CharSliceSearcher<'a, 'b> {} /// assert_eq!("Hello world".find(&['l', 'l'] as &[_]), Some(2)); /// assert_eq!("Hello world".find(&['l', 'l'][..]), Some(2)); /// ``` -impl<'a, 'b> Pattern<'a> for &'b [char] { - pattern_methods!(CharSliceSearcher<'a, 'b>, MultiCharEqPattern, CharSliceSearcher); +impl<'b> Pattern for &'b [char] { + pattern_methods!('a, CharSliceSearcher<'a, 'b>, MultiCharEqPattern, CharSliceSearcher); } ///////////////////////////////////////////////////////////////////////////// // Impl for F: FnMut(char) -> bool ///////////////////////////////////////////////////////////////////////////// -/// Associated type for `>::Searcher`. +/// Associated type for `::Searcher<'a>`. #[derive(Clone)] -pub struct CharPredicateSearcher<'a, F>( as Pattern<'a>>::Searcher) +pub struct CharPredicateSearcher<'a, F>( as Pattern>::Searcher<'a>) where F: FnMut(char) -> bool; @@ -919,11 +919,11 @@ impl<'a, F> DoubleEndedSearcher<'a> for CharPredicateSearcher<'a, F> where F: Fn /// assert_eq!("Hello world".find(char::is_uppercase), Some(0)); /// assert_eq!("Hello world".find(|c| "aeiou".contains(c)), Some(1)); /// ``` -impl<'a, F> Pattern<'a> for F +impl Pattern for F where F: FnMut(char) -> bool, { - pattern_methods!(CharPredicateSearcher<'a, F>, MultiCharEqPattern, CharPredicateSearcher); + pattern_methods!('a, CharPredicateSearcher<'a, F>, MultiCharEqPattern, CharPredicateSearcher); } ///////////////////////////////////////////////////////////////////////////// @@ -931,8 +931,8 @@ where ///////////////////////////////////////////////////////////////////////////// /// Delegates to the `&str` impl. -impl<'a, 'b, 'c> Pattern<'a> for &'c &'b str { - pattern_methods!(StrSearcher<'a, 'b>, |&s| s, |s| s); +impl<'b, 'c> Pattern for &'c &'b str { + pattern_methods!('a, StrSearcher<'a, 'b>, |&s| s, |s| s); } ///////////////////////////////////////////////////////////////////////////// @@ -949,23 +949,23 @@ impl<'a, 'b, 'c> Pattern<'a> for &'c &'b str { /// ``` /// assert_eq!("Hello world".find("world"), Some(6)); /// ``` -impl<'a, 'b> Pattern<'a> for &'b str { - type Searcher = StrSearcher<'a, 'b>; +impl<'b> Pattern for &'b str { + type Searcher<'a> = StrSearcher<'a, 'b>; #[inline] - fn into_searcher(self, haystack: &'a str) -> StrSearcher<'a, 'b> { + fn into_searcher(self, haystack: &str) -> StrSearcher<'_, 'b> { StrSearcher::new(haystack, self) } /// Checks whether the pattern matches at the front of the haystack. #[inline] - fn is_prefix_of(self, haystack: &'a str) -> bool { + fn is_prefix_of(self, haystack: &str) -> bool { haystack.as_bytes().starts_with(self.as_bytes()) } /// Checks whether the pattern matches anywhere in the haystack #[inline] - fn is_contained_in(self, haystack: &'a str) -> bool { + fn is_contained_in(self, haystack: &str) -> bool { if self.len() == 0 { return true; } @@ -991,7 +991,7 @@ impl<'a, 'b> Pattern<'a> for &'b str { /// Removes the pattern from the front of haystack, if it matches. #[inline] - fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> { + fn strip_prefix_of(self, haystack: &str) -> Option<&str> { if self.is_prefix_of(haystack) { // SAFETY: prefix was just verified to exist. unsafe { Some(haystack.get_unchecked(self.as_bytes().len()..)) } @@ -1002,13 +1002,19 @@ impl<'a, 'b> Pattern<'a> for &'b str { /// Checks whether the pattern matches at the back of the haystack. #[inline] - fn is_suffix_of(self, haystack: &'a str) -> bool { + fn is_suffix_of<'a>(self, haystack: &'a str) -> bool + where + Self::Searcher<'a>: ReverseSearcher<'a>, + { haystack.as_bytes().ends_with(self.as_bytes()) } /// Removes the pattern from the back of haystack, if it matches. #[inline] - fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> { + fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&'a str> + where + Self::Searcher<'a>: ReverseSearcher<'a>, + { if self.is_suffix_of(haystack) { let i = haystack.len() - self.as_bytes().len(); // SAFETY: suffix was just verified to exist. @@ -1024,7 +1030,7 @@ impl<'a, 'b> Pattern<'a> for &'b str { ///////////////////////////////////////////////////////////////////////////// #[derive(Clone, Debug)] -/// Associated type for `<&str as Pattern<'a>>::Searcher`. +/// Associated type for `<&str as Pattern>::Searcher<'a>`. pub struct StrSearcher<'a, 'b> { haystack: &'a str, needle: &'b str, diff --git a/tests/ui/suggestions/issue-104961.fixed b/tests/ui/suggestions/issue-104961.fixed index 5def21b506e1..3019242880f8 100644 --- a/tests/ui/suggestions/issue-104961.fixed +++ b/tests/ui/suggestions/issue-104961.fixed @@ -2,12 +2,12 @@ fn foo(x: &str) -> bool { x.starts_with(&("hi".to_string() + " you")) - //~^ ERROR the trait bound `String: Pattern<'_>` is not satisfied [E0277] + //~^ ERROR the trait bound `String: Pattern` is not satisfied [E0277] } fn foo2(x: &str) -> bool { x.starts_with(&"hi".to_string()) - //~^ ERROR the trait bound `String: Pattern<'_>` is not satisfied [E0277] + //~^ ERROR the trait bound `String: Pattern` is not satisfied [E0277] } fn main() { diff --git a/tests/ui/suggestions/issue-104961.rs b/tests/ui/suggestions/issue-104961.rs index a09b8a887114..b315e9bab0d1 100644 --- a/tests/ui/suggestions/issue-104961.rs +++ b/tests/ui/suggestions/issue-104961.rs @@ -2,12 +2,12 @@ fn foo(x: &str) -> bool { x.starts_with("hi".to_string() + " you") - //~^ ERROR the trait bound `String: Pattern<'_>` is not satisfied [E0277] + //~^ ERROR the trait bound `String: Pattern` is not satisfied [E0277] } fn foo2(x: &str) -> bool { x.starts_with("hi".to_string()) - //~^ ERROR the trait bound `String: Pattern<'_>` is not satisfied [E0277] + //~^ ERROR the trait bound `String: Pattern` is not satisfied [E0277] } fn main() { diff --git a/tests/ui/suggestions/issue-104961.stderr b/tests/ui/suggestions/issue-104961.stderr index 3c5f86817f3a..0d229e6dada5 100644 --- a/tests/ui/suggestions/issue-104961.stderr +++ b/tests/ui/suggestions/issue-104961.stderr @@ -1,12 +1,12 @@ -error[E0277]: the trait bound `String: Pattern<'_>` is not satisfied +error[E0277]: the trait bound `String: Pattern` is not satisfied --> $DIR/issue-104961.rs:4:19 | LL | x.starts_with("hi".to_string() + " you") - | ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Pattern<'_>` is not implemented for `String` + | ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Pattern` is not implemented for `String` | | | required by a bound introduced by this call | - = note: required for `String` to implement `Pattern<'_>` + = note: required for `String` to implement `Pattern` note: required by a bound in `core::str::::starts_with` --> $SRC_DIR/core/src/str/mod.rs:LL:COL help: consider borrowing here @@ -14,15 +14,15 @@ help: consider borrowing here LL | x.starts_with(&("hi".to_string() + " you")) | ++ + -error[E0277]: the trait bound `String: Pattern<'_>` is not satisfied +error[E0277]: the trait bound `String: Pattern` is not satisfied --> $DIR/issue-104961.rs:9:19 | LL | x.starts_with("hi".to_string()) - | ----------- ^^^^^^^^^^^^^^^^ the trait `Pattern<'_>` is not implemented for `String` + | ----------- ^^^^^^^^^^^^^^^^ the trait `Pattern` is not implemented for `String` | | | required by a bound introduced by this call | - = note: required for `String` to implement `Pattern<'_>` + = note: required for `String` to implement `Pattern` note: required by a bound in `core::str::::starts_with` --> $SRC_DIR/core/src/str/mod.rs:LL:COL help: consider borrowing here diff --git a/tests/ui/suggestions/issue-62843.stderr b/tests/ui/suggestions/issue-62843.stderr index 84ab4a0edd39..c3c0360b3a9d 100644 --- a/tests/ui/suggestions/issue-62843.stderr +++ b/tests/ui/suggestions/issue-62843.stderr @@ -1,12 +1,12 @@ -error[E0277]: the trait bound `String: Pattern<'_>` is not satisfied +error[E0277]: the trait bound `String: Pattern` is not satisfied --> $DIR/issue-62843.rs:4:32 | LL | println!("{:?}", line.find(pattern)); - | ---- ^^^^^^^ the trait `Pattern<'_>` is not implemented for `String` + | ---- ^^^^^^^ the trait `Pattern` is not implemented for `String` | | | required by a bound introduced by this call | - = note: required for `String` to implement `Pattern<'_>` + = note: required for `String` to implement `Pattern` note: required by a bound in `core::str::::find` --> $SRC_DIR/core/src/str/mod.rs:LL:COL help: consider borrowing here diff --git a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs index 98825bd536e0..dc2de5bb715b 100644 --- a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs +++ b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs @@ -1,11 +1,11 @@ fn strip_lf(s: &str) -> &str { s.strip_suffix(b'\n').unwrap_or(s) - //~^ ERROR expected a `FnMut(char)` closure, found `u8` - //~| NOTE expected an `FnMut(char)` closure, found `u8` - //~| HELP the trait `FnMut(char)` is not implemented for `u8` - //~| HELP the following other types implement trait `Pattern<'a>`: - //~| NOTE required for `u8` to implement `Pattern<'_>` - + //~^ ERROR the trait bound `u8: Pattern` is not satisfied + //~| NOTE required by a bound introduced by this call + //~| NOTE the trait `FnMut(char)` is not implemented for `u8`, which is required by `u8: Pattern` + //~| HELP the following other types implement trait `Pattern`: + //~| NOTE required for `u8` to implement `Pattern` + //~| NOTE required by a bound in `core::str::::strip_suffix` } fn main() {} diff --git a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr index 49272e7d357b..8351d15fdf3b 100644 --- a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr +++ b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr @@ -1,11 +1,12 @@ -error[E0277]: expected a `FnMut(char)` closure, found `u8` - --> $DIR/assoc-fn-bound-root-obligation.rs:2:7 +error[E0277]: the trait bound `u8: Pattern` is not satisfied + --> $DIR/assoc-fn-bound-root-obligation.rs:2:20 | LL | s.strip_suffix(b'\n').unwrap_or(s) - | ^^^^^^^^^^^^ expected an `FnMut(char)` closure, found `u8` + | ------------ ^^^^^ the trait `FnMut(char)` is not implemented for `u8`, which is required by `u8: Pattern` + | | + | required by a bound introduced by this call | - = help: the trait `FnMut(char)` is not implemented for `u8`, which is required by `u8: Pattern<'_>` - = help: the following other types implement trait `Pattern<'a>`: + = help: the following other types implement trait `Pattern`: &'b String &'b [char; N] &'b [char] @@ -13,7 +14,9 @@ LL | s.strip_suffix(b'\n').unwrap_or(s) &'c &'b str [char; N] char - = note: required for `u8` to implement `Pattern<'_>` + = note: required for `u8` to implement `Pattern` +note: required by a bound in `core::str::::strip_suffix` + --> $SRC_DIR/core/src/str/mod.rs:LL:COL error: aborting due to 1 previous error diff --git a/tests/ui/traits/suggest-dereferences/root-obligation.fixed b/tests/ui/traits/suggest-dereferences/root-obligation.fixed index 072296c6b154..ad0f184dc9a4 100644 --- a/tests/ui/traits/suggest-dereferences/root-obligation.fixed +++ b/tests/ui/traits/suggest-dereferences/root-obligation.fixed @@ -4,7 +4,7 @@ fn get_vowel_count(string: &str) -> usize { string .chars() .filter(|c| "aeiou".contains(*c)) - //~^ ERROR the trait bound `&char: Pattern<'_>` is not satisfied + //~^ ERROR the trait bound `&char: Pattern` is not satisfied .count() } diff --git a/tests/ui/traits/suggest-dereferences/root-obligation.rs b/tests/ui/traits/suggest-dereferences/root-obligation.rs index e7025fe08254..a31a9955d313 100644 --- a/tests/ui/traits/suggest-dereferences/root-obligation.rs +++ b/tests/ui/traits/suggest-dereferences/root-obligation.rs @@ -4,7 +4,7 @@ fn get_vowel_count(string: &str) -> usize { string .chars() .filter(|c| "aeiou".contains(c)) - //~^ ERROR the trait bound `&char: Pattern<'_>` is not satisfied + //~^ ERROR the trait bound `&char: Pattern` is not satisfied .count() } diff --git a/tests/ui/traits/suggest-dereferences/root-obligation.stderr b/tests/ui/traits/suggest-dereferences/root-obligation.stderr index bbfbb98fba77..2f5e1c5b5377 100644 --- a/tests/ui/traits/suggest-dereferences/root-obligation.stderr +++ b/tests/ui/traits/suggest-dereferences/root-obligation.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `&char: Pattern<'_>` is not satisfied +error[E0277]: the trait bound `&char: Pattern` is not satisfied --> $DIR/root-obligation.rs:6:38 | LL | .filter(|c| "aeiou".contains(c)) - | -------- ^ the trait `Fn(char)` is not implemented for `char`, which is required by `&char: Pattern<'_>` + | -------- ^ the trait `Fn(char)` is not implemented for `char`, which is required by `&char: Pattern` | | | required by a bound introduced by this call | = note: required for `&char` to implement `FnOnce(char)` - = note: required for `&char` to implement `Pattern<'_>` + = note: required for `&char` to implement `Pattern` note: required by a bound in `core::str::::contains` --> $SRC_DIR/core/src/str/mod.rs:LL:COL help: consider dereferencing here From fae6037884ec5bd9668e1be07990f4a1fdb9de77 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 14 Jul 2024 20:21:01 +0000 Subject: [PATCH 130/734] Windows: move BSD socket shims to netc --- library/std/src/sys/pal/windows/c.rs | 97 +-------------- .../std/src/sys/pal/windows/c/bindings.txt | 1 + .../std/src/sys/pal/windows/c/windows_sys.rs | 8 ++ library/std/src/sys/pal/windows/net.rs | 112 ++++++++++++++++-- 4 files changed, 109 insertions(+), 109 deletions(-) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 296d19a926d9..84f3d6a5399b 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -8,7 +8,7 @@ use crate::ffi::CStr; use crate::mem; -use crate::os::raw::{c_char, c_int, c_uint, c_ulong, c_ushort, c_void}; +use crate::os::raw::{c_uint, c_ulong, c_ushort, c_void}; use crate::os::windows::io::{AsRawHandle, BorrowedHandle}; use crate::ptr; @@ -19,12 +19,6 @@ pub use windows_sys::*; pub type WCHAR = u16; -pub type socklen_t = c_int; -pub type ADDRESS_FAMILY = c_ushort; -pub use FD_SET as fd_set; -pub use LINGER as linger; -pub use TIMEVAL as timeval; - pub const INVALID_HANDLE_VALUE: HANDLE = ::core::ptr::without_provenance_mut(-1i32 as _); // https://learn.microsoft.com/en-us/cpp/c-runtime-library/exit-success-exit-failure?view=msvc-170 @@ -42,20 +36,6 @@ pub const INIT_ONCE_STATIC_INIT: INIT_ONCE = INIT_ONCE { Ptr: ptr::null_mut() }; pub const OBJ_DONT_REPARSE: u32 = windows_sys::OBJ_DONT_REPARSE as u32; pub const FRS_ERR_SYSVOL_POPULATE_TIMEOUT: u32 = windows_sys::FRS_ERR_SYSVOL_POPULATE_TIMEOUT as u32; -pub const AF_INET: c_int = windows_sys::AF_INET as c_int; -pub const AF_INET6: c_int = windows_sys::AF_INET6 as c_int; - -#[repr(C)] -pub struct ip_mreq { - pub imr_multiaddr: in_addr, - pub imr_interface: in_addr, -} - -#[repr(C)] -pub struct ipv6_mreq { - pub ipv6mr_multiaddr: in6_addr, - pub ipv6mr_interface: c_uint, -} // Equivalent to the `NT_SUCCESS` C preprocessor macro. // See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values @@ -127,45 +107,6 @@ pub struct MOUNT_POINT_REPARSE_BUFFER { pub PathBuffer: WCHAR, } -#[repr(C)] -pub struct SOCKADDR_STORAGE_LH { - pub ss_family: ADDRESS_FAMILY, - pub __ss_pad1: [c_char; 6], - pub __ss_align: i64, - pub __ss_pad2: [c_char; 112], -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct sockaddr_in { - pub sin_family: ADDRESS_FAMILY, - pub sin_port: c_ushort, - pub sin_addr: in_addr, - pub sin_zero: [c_char; 8], -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct sockaddr_in6 { - pub sin6_family: ADDRESS_FAMILY, - pub sin6_port: c_ushort, - pub sin6_flowinfo: c_ulong, - pub sin6_addr: in6_addr, - pub sin6_scope_id: c_ulong, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct in_addr { - pub s_addr: u32, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct in6_addr { - pub s6_addr: [u8; 16], -} - // Desktop specific functions & types cfg_if::cfg_if! { if #[cfg(not(target_vendor = "uwp"))] { @@ -205,42 +146,6 @@ pub unsafe extern "system" fn ReadFileEx( ) } -// POSIX compatibility shims. -pub unsafe fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int { - windows_sys::recv(socket, buf.cast::(), len, flags) -} -pub unsafe fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int { - windows_sys::send(socket, buf.cast::(), len, flags) -} -pub unsafe fn recvfrom( - socket: SOCKET, - buf: *mut c_void, - len: c_int, - flags: c_int, - addr: *mut SOCKADDR, - addrlen: *mut c_int, -) -> c_int { - windows_sys::recvfrom(socket, buf.cast::(), len, flags, addr, addrlen) -} -pub unsafe fn sendto( - socket: SOCKET, - buf: *const c_void, - len: c_int, - flags: c_int, - addr: *const SOCKADDR, - addrlen: c_int, -) -> c_int { - windows_sys::sendto(socket, buf.cast::(), len, flags, addr, addrlen) -} -pub unsafe fn getaddrinfo( - node: *const c_char, - service: *const c_char, - hints: *const ADDRINFOA, - res: *mut *mut ADDRINFOA, -) -> c_int { - windows_sys::getaddrinfo(node.cast::(), service.cast::(), hints, res) -} - cfg_if::cfg_if! { if #[cfg(not(target_vendor = "uwp"))] { pub unsafe fn NtReadFile( diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index 5ad4a3731d82..794e2c90c524 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2059,6 +2059,7 @@ Windows.Win32.Networking.WinSock.SOCK_RDM Windows.Win32.Networking.WinSock.SOCK_SEQPACKET Windows.Win32.Networking.WinSock.SOCK_STREAM Windows.Win32.Networking.WinSock.SOCKADDR +Windows.Win32.Networking.WinSock.SOCKADDR_STORAGE Windows.Win32.Networking.WinSock.SOCKADDR_UN Windows.Win32.Networking.WinSock.SOCKET Windows.Win32.Networking.WinSock.SOCKET_ERROR diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index fea00fec9ae5..eae0f7758606 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -2890,6 +2890,14 @@ pub struct SOCKADDR { } #[repr(C)] #[derive(Clone, Copy)] +pub struct SOCKADDR_STORAGE { + pub ss_family: ADDRESS_FAMILY, + pub __ss_pad1: [i8; 6], + pub __ss_align: i64, + pub __ss_pad2: [i8; 112], +} +#[repr(C)] +#[derive(Clone, Copy)] pub struct SOCKADDR_UN { pub sun_family: ADDRESS_FAMILY, pub sun_path: [i8; 108], diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs index d51fb56238f2..b7ecff032e4a 100644 --- a/library/std/src/sys/pal/windows/net.rs +++ b/library/std/src/sys/pal/windows/net.rs @@ -17,14 +17,100 @@ use crate::time::Duration; use core::ffi::{c_int, c_long, c_ulong, c_ushort}; +#[allow(non_camel_case_types)] pub type wrlen_t = i32; pub mod netc { - pub use crate::sys::c::ADDRESS_FAMILY as sa_family_t; - pub use crate::sys::c::ADDRINFOA as addrinfo; - pub use crate::sys::c::SOCKADDR as sockaddr; - pub use crate::sys::c::SOCKADDR_STORAGE_LH as sockaddr_storage; - pub use crate::sys::c::*; + //! BSD socket compatibility shim + //! + //! Some Windows API types are not quite what's expected by our cross-platform + //! net code. E.g. naming differences or different pointer types. + use crate::sys::c::{self, ADDRESS_FAMILY, ADDRINFOA, SOCKADDR, SOCKET}; + use core::ffi::{c_char, c_int, c_uint, c_ulong, c_ushort, c_void}; + + // re-exports from Windows API bindings. + pub use crate::sys::c::{ + bind, connect, freeaddrinfo, getpeername, getsockname, getsockopt, listen, setsockopt, + ADDRESS_FAMILY as sa_family_t, ADDRINFOA as addrinfo, IPPROTO_IP, IPPROTO_IPV6, + IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_MULTICAST_LOOP, IPV6_V6ONLY, + IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL, + SOCKADDR as sockaddr, SOCKADDR_STORAGE as sockaddr_storage, SOCK_DGRAM, SOCK_STREAM, + SOL_SOCKET, SO_BROADCAST, SO_RCVTIMEO, SO_SNDTIMEO, + }; + + #[allow(non_camel_case_types)] + pub type socklen_t = c_int; + + pub const AF_INET: i32 = c::AF_INET as i32; + pub const AF_INET6: i32 = c::AF_INET6 as i32; + + // The following two structs use a union in the generated bindings but + // our cross-platform code expects a normal field so it's redefined here. + // As a consequence, we also need to redefine other structs that use this struct. + #[repr(C)] + #[derive(Copy, Clone)] + pub struct in_addr { + pub s_addr: u32, + } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + #[repr(C)] + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + #[repr(C)] + pub struct ipv6_mreq { + pub ipv6mr_multiaddr: in6_addr, + pub ipv6mr_interface: c_uint, + } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct sockaddr_in { + pub sin_family: ADDRESS_FAMILY, + pub sin_port: c_ushort, + pub sin_addr: in_addr, + pub sin_zero: [c_char; 8], + } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct sockaddr_in6 { + pub sin6_family: ADDRESS_FAMILY, + pub sin6_port: c_ushort, + pub sin6_flowinfo: c_ulong, + pub sin6_addr: in6_addr, + pub sin6_scope_id: c_ulong, + } + + pub unsafe fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int { + unsafe { c::send(socket, buf.cast::(), len, flags) } + } + pub unsafe fn sendto( + socket: SOCKET, + buf: *const c_void, + len: c_int, + flags: c_int, + addr: *const SOCKADDR, + addrlen: c_int, + ) -> c_int { + unsafe { c::sendto(socket, buf.cast::(), len, flags, addr, addrlen) } + } + pub unsafe fn getaddrinfo( + node: *const c_char, + service: *const c_char, + hints: *const ADDRINFOA, + res: *mut *mut ADDRINFOA, + ) -> c_int { + unsafe { c::getaddrinfo(node.cast::(), service.cast::(), hints, res) } + } } pub struct Socket(OwnedSocket); @@ -102,8 +188,8 @@ where impl Socket { pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { let family = match *addr { - SocketAddr::V4(..) => c::AF_INET, - SocketAddr::V6(..) => c::AF_INET6, + SocketAddr::V4(..) => netc::AF_INET, + SocketAddr::V6(..) => netc::AF_INET6, }; let socket = unsafe { c::WSASocketW( @@ -157,7 +243,7 @@ impl Socket { return Err(io::Error::ZERO_TIMEOUT); } - let mut timeout = c::timeval { + let mut timeout = c::TIMEVAL { tv_sec: cmp::min(timeout.as_secs(), c_long::MAX as u64) as c_long, tv_usec: timeout.subsec_micros() as c_long, }; @@ -167,7 +253,7 @@ impl Socket { } let fds = { - let mut fds = unsafe { mem::zeroed::() }; + let mut fds = unsafe { mem::zeroed::() }; fds.fd_count = 1; fds.fd_array[0] = self.as_raw(); fds @@ -295,8 +381,8 @@ impl Socket { buf: &mut [u8], flags: c_int, ) -> io::Result<(usize, SocketAddr)> { - let mut storage = unsafe { mem::zeroed::() }; - let mut addrlen = mem::size_of_val(&storage) as c::socklen_t; + let mut storage = unsafe { mem::zeroed::() }; + let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t; let length = cmp::min(buf.len(), ::MAX as usize) as wrlen_t; // On unix when a socket is shut down all further reads return 0, so we @@ -399,7 +485,7 @@ impl Socket { } pub fn set_linger(&self, linger: Option) -> io::Result<()> { - let linger = c::linger { + let linger = c::LINGER { l_onoff: linger.is_some() as c_ushort, l_linger: linger.unwrap_or_default().as_secs() as c_ushort, }; @@ -408,7 +494,7 @@ impl Socket { } pub fn linger(&self) -> io::Result> { - let val: c::linger = net::getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?; + let val: c::LINGER = net::getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?; Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) } From d1a3c1daeb5514993873b8e018224a3ea531cbf3 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 15 Jul 2024 13:38:23 +0000 Subject: [PATCH 131/734] Deny more windows unsafe_op_in_unsafe_fn --- library/std/src/sys/os_str/wtf8.rs | 5 +- library/std/src/sys/pal/windows/alloc.rs | 2 - library/std/src/sys/pal/windows/fs.rs | 23 +++++---- library/std/src/sys/pal/windows/handle.rs | 63 +++++++++++++---------- library/std/src/sys/pal/windows/os.rs | 17 +++--- 5 files changed, 63 insertions(+), 47 deletions(-) diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index edb923a47501..cc00fcaf13d8 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -1,5 +1,6 @@ //! The underlying OsString/OsStr implementation on Windows is a //! wrapper around the "WTF-8" encoding; see the `wtf8` module for more. +#![deny(unsafe_op_in_unsafe_fn)] use crate::borrow::Cow; use crate::collections::TryReserveError; @@ -71,7 +72,7 @@ impl Buf { #[inline] pub unsafe fn from_encoded_bytes_unchecked(s: Vec) -> Self { - Self { inner: Wtf8Buf::from_bytes_unchecked(s) } + unsafe { Self { inner: Wtf8Buf::from_bytes_unchecked(s) } } } pub fn with_capacity(capacity: usize) -> Buf { @@ -190,7 +191,7 @@ impl Slice { #[inline] pub unsafe fn from_encoded_bytes_unchecked(s: &[u8]) -> &Slice { - mem::transmute(Wtf8::from_bytes_unchecked(s)) + unsafe { mem::transmute(Wtf8::from_bytes_unchecked(s)) } } #[track_caller] diff --git a/library/std/src/sys/pal/windows/alloc.rs b/library/std/src/sys/pal/windows/alloc.rs index 9f0194492b0a..987be6b69eec 100644 --- a/library/std/src/sys/pal/windows/alloc.rs +++ b/library/std/src/sys/pal/windows/alloc.rs @@ -1,5 +1,3 @@ -#![deny(unsafe_op_in_unsafe_fn)] - use crate::alloc::{GlobalAlloc, Layout, System}; use crate::ffi::c_void; use crate::ptr; diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 85fd9153d537..48c39392047f 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1,4 +1,3 @@ -#![allow(unsafe_op_in_unsafe_fn)] use core::ptr::addr_of; use crate::os::windows::prelude::*; @@ -795,10 +794,12 @@ impl<'a> Iterator for DirBuffIter<'a> { } unsafe fn from_maybe_unaligned<'a>(p: *const u16, len: usize) -> Cow<'a, [u16]> { - if p.is_aligned() { - Cow::Borrowed(crate::slice::from_raw_parts(p, len)) - } else { - Cow::Owned((0..len).map(|i| p.add(i).read_unaligned()).collect()) + unsafe { + if p.is_aligned() { + Cow::Borrowed(crate::slice::from_raw_parts(p, len)) + } else { + Cow::Owned((0..len).map(|i| p.add(i).read_unaligned()).collect()) + } } } @@ -897,7 +898,9 @@ impl IntoRawHandle for File { impl FromRawHandle for File { unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { - Self { handle: FromInner::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } + unsafe { + Self { handle: FromInner::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } + } } } @@ -1427,10 +1430,12 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { _hDestinationFile: c::HANDLE, lpData: *const c_void, ) -> u32 { - if dwStreamNumber == 1 { - *(lpData as *mut i64) = StreamBytesTransferred; + unsafe { + if dwStreamNumber == 1 { + *(lpData as *mut i64) = StreamBytesTransferred; + } + c::PROGRESS_CONTINUE } - c::PROGRESS_CONTINUE } let pfrom = maybe_verbatim(from)?; let pto = maybe_verbatim(to)?; diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs index ae9ea8ff584e..e63f5c9dec29 100644 --- a/library/std/src/sys/pal/windows/handle.rs +++ b/library/std/src/sys/pal/windows/handle.rs @@ -1,5 +1,4 @@ #![unstable(issue = "none", feature = "windows_handle")] -#![allow(unsafe_op_in_unsafe_fn)] #[cfg(test)] mod tests; @@ -73,7 +72,7 @@ impl IntoRawHandle for Handle { impl FromRawHandle for Handle { unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { - Self(FromRawHandle::from_raw_handle(raw_handle)) + unsafe { Self(FromRawHandle::from_raw_handle(raw_handle)) } } } @@ -142,19 +141,23 @@ impl Handle { buf: &mut [u8], overlapped: *mut c::OVERLAPPED, ) -> io::Result> { - let len = cmp::min(buf.len(), u32::MAX as usize) as u32; - let mut amt = 0; - let res = - cvt(c::ReadFile(self.as_raw_handle(), buf.as_mut_ptr(), len, &mut amt, overlapped)); - match res { - Ok(_) => Ok(Some(amt as usize)), - Err(e) => { - if e.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) { - Ok(None) - } else if e.raw_os_error() == Some(c::ERROR_BROKEN_PIPE as i32) { - Ok(Some(0)) - } else { - Err(e) + // SAFETY: We have exclusive access to the buffer and it's up to the caller to + // ensure the OVERLAPPED pointer is valid for the lifetime of this function. + unsafe { + let len = cmp::min(buf.len(), u32::MAX as usize) as u32; + let mut amt = 0; + let res = + cvt(c::ReadFile(self.as_raw_handle(), buf.as_mut_ptr(), len, &mut amt, overlapped)); + match res { + Ok(_) => Ok(Some(amt as usize)), + Err(e) => { + if e.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) { + Ok(None) + } else if e.raw_os_error() == Some(c::ERROR_BROKEN_PIPE as i32) { + Ok(Some(0)) + } else { + Err(e) + } } } } @@ -230,20 +233,24 @@ impl Handle { // The length is clamped at u32::MAX. let len = cmp::min(len, u32::MAX as usize) as u32; - let status = c::NtReadFile( - self.as_handle(), - ptr::null_mut(), - None, - ptr::null_mut(), - &mut io_status, - buf, - len, - offset.map(|n| n as _).as_ref(), - None, - ); + // SAFETY: It's up to the caller to ensure `buf` is writeable up to + // the provided `len`. + let status = unsafe { + c::NtReadFile( + self.as_handle(), + ptr::null_mut(), + None, + ptr::null_mut(), + &mut io_status, + buf, + len, + offset.map(|n| n as _).as_ref(), + None, + ) + }; let status = if status == c::STATUS_PENDING { - c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE); + unsafe { c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE) }; io_status.status() } else { status @@ -261,7 +268,7 @@ impl Handle { status if c::nt_success(status) => Ok(io_status.Information), status => { - let error = c::RtlNtStatusToDosError(status); + let error = unsafe { c::RtlNtStatusToDosError(status) }; Err(io::Error::from_raw_os_error(error as _)) } } diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 0a9279e50ba1..f1f4d3a5d26e 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -1,7 +1,6 @@ //! Implementation of `std::os` functionality for Windows. #![allow(nonstandard_style)] -#![allow(unsafe_op_in_unsafe_fn)] #[cfg(test)] mod tests; @@ -305,15 +304,21 @@ pub fn getenv(k: &OsStr) -> Option { } pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - let k = to_u16s(k)?; - let v = to_u16s(v)?; + // SAFETY: We ensure that k and v are null-terminated wide strings. + unsafe { + let k = to_u16s(k)?; + let v = to_u16s(v)?; - cvt(c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr())).map(drop) + cvt(c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr())).map(drop) + } } pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { - let v = to_u16s(n)?; - cvt(c::SetEnvironmentVariableW(v.as_ptr(), ptr::null())).map(drop) + // SAFETY: We ensure that v is a null-terminated wide strings. + unsafe { + let v = to_u16s(n)?; + cvt(c::SetEnvironmentVariableW(v.as_ptr(), ptr::null())).map(drop) + } } pub fn temp_dir() -> PathBuf { From 37295e6268c7d6dd4290899d40b06b11284b2aab Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 15 Jul 2024 13:39:05 +0000 Subject: [PATCH 132/734] Some Windows functions are safe --- library/std/src/sys/pal/windows/io.rs | 29 +++++++++---------- .../std/src/sys/pal/windows/stack_overflow.rs | 19 +++++++----- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/library/std/src/sys/pal/windows/io.rs b/library/std/src/sys/pal/windows/io.rs index 86d457db50a3..bf3dfdfdd3e7 100644 --- a/library/std/src/sys/pal/windows/io.rs +++ b/library/std/src/sys/pal/windows/io.rs @@ -1,4 +1,3 @@ -#![allow(unsafe_op_in_unsafe_fn)] use crate::marker::PhantomData; use crate::mem::size_of; use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle}; @@ -81,19 +80,17 @@ impl<'a> IoSliceMut<'a> { } pub fn is_terminal(h: &impl AsHandle) -> bool { - unsafe { handle_is_console(h.as_handle()) } + handle_is_console(h.as_handle()) } -unsafe fn handle_is_console(handle: BorrowedHandle<'_>) -> bool { - let handle = handle.as_raw_handle(); - +fn handle_is_console(handle: BorrowedHandle<'_>) -> bool { // A null handle means the process has no console. - if handle.is_null() { + if handle.as_raw_handle().is_null() { return false; } let mut out = 0; - if c::GetConsoleMode(handle, &mut out) != 0 { + if unsafe { c::GetConsoleMode(handle.as_raw_handle(), &mut out) != 0 } { // False positives aren't possible. If we got a console then we definitely have a console. return true; } @@ -102,9 +99,9 @@ unsafe fn handle_is_console(handle: BorrowedHandle<'_>) -> bool { msys_tty_on(handle) } -unsafe fn msys_tty_on(handle: c::HANDLE) -> bool { +fn msys_tty_on(handle: BorrowedHandle<'_>) -> bool { // Early return if the handle is not a pipe. - if c::GetFileType(handle) != c::FILE_TYPE_PIPE { + if unsafe { c::GetFileType(handle.as_raw_handle()) != c::FILE_TYPE_PIPE } { return false; } @@ -120,12 +117,14 @@ unsafe fn msys_tty_on(handle: c::HANDLE) -> bool { } let mut name_info = FILE_NAME_INFO { FileNameLength: 0, FileName: [0; c::MAX_PATH as usize] }; // Safety: buffer length is fixed. - let res = c::GetFileInformationByHandleEx( - handle, - c::FileNameInfo, - core::ptr::addr_of_mut!(name_info) as *mut c_void, - size_of::() as u32, - ); + let res = unsafe { + c::GetFileInformationByHandleEx( + handle.as_raw_handle(), + c::FileNameInfo, + core::ptr::addr_of_mut!(name_info) as *mut c_void, + size_of::() as u32, + ) + }; if res == 0 { return false; } diff --git a/library/std/src/sys/pal/windows/stack_overflow.rs b/library/std/src/sys/pal/windows/stack_overflow.rs index ea89429cb83c..467e21ab56a2 100644 --- a/library/std/src/sys/pal/windows/stack_overflow.rs +++ b/library/std/src/sys/pal/windows/stack_overflow.rs @@ -1,18 +1,18 @@ #![cfg_attr(test, allow(dead_code))] -#![allow(unsafe_op_in_unsafe_fn)] use crate::sys::c; use crate::thread; /// Reserve stack space for use in stack overflow exceptions. -pub unsafe fn reserve_stack() { - let result = c::SetThreadStackGuarantee(&mut 0x5000); +pub fn reserve_stack() { + let result = unsafe { c::SetThreadStackGuarantee(&mut 0x5000) }; // Reserving stack space is not critical so we allow it to fail in the released build of libstd. // We still use debug assert here so that CI will test that we haven't made a mistake calling the function. debug_assert_ne!(result, 0, "failed to reserve stack space for exception handling"); } unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> i32 { + // SAFETY: It's up to the caller (which in this case is the OS) to ensure that `ExceptionInfo` is valid. unsafe { let rec = &(*(*ExceptionInfo).ExceptionRecord); let code = rec.ExceptionCode; @@ -27,11 +27,14 @@ unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POIN } } -pub unsafe fn init() { - let result = c::AddVectoredExceptionHandler(0, Some(vectored_handler)); - // Similar to the above, adding the stack overflow handler is allowed to fail - // but a debug assert is used so CI will still test that it normally works. - debug_assert!(!result.is_null(), "failed to install exception handler"); +pub fn init() { + // SAFETY: `vectored_handler` has the correct ABI and is safe to call during exception handling. + unsafe { + let result = c::AddVectoredExceptionHandler(0, Some(vectored_handler)); + // Similar to the above, adding the stack overflow handler is allowed to fail + // but a debug assert is used so CI will still test that it normally works. + debug_assert!(!result.is_null(), "failed to install exception handler"); + } // Set the thread stack guarantee for the main thread. reserve_stack(); } From 59222346549ff66230d26a489705a27725e526b5 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 15 Jul 2024 13:50:58 +0000 Subject: [PATCH 133/734] allow(unsafe_op_in_unsafe_fn) on some functions These need to get their safety story straight --- library/std/src/sys/pal/windows/pipe.rs | 4 +++- library/std/src/sys/pal/windows/thread.rs | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index d8b785f027c7..19364617e741 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -1,4 +1,3 @@ -#![allow(unsafe_op_in_unsafe_fn)] use crate::os::windows::prelude::*; use crate::ffi::OsStr; @@ -325,6 +324,7 @@ impl AnonPipe { /// [`ReadFileEx`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfileex /// [`WriteFileEx`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefileex /// [Asynchronous Procedure Call]: https://docs.microsoft.com/en-us/windows/win32/sync/asynchronous-procedure-calls + #[allow(unsafe_op_in_unsafe_fn)] unsafe fn alertable_io_internal( &self, io: AlertableIoFn, @@ -561,6 +561,7 @@ impl<'a> Drop for AsyncPipe<'a> { } } +#[allow(unsafe_op_in_unsafe_fn)] unsafe fn slice_to_end(v: &mut Vec) -> &mut [u8] { if v.capacity() == 0 { v.reserve(16); @@ -568,5 +569,6 @@ unsafe fn slice_to_end(v: &mut Vec) -> &mut [u8] { if v.capacity() == v.len() { v.reserve(1); } + // FIXME: Isn't this just spare_capacity_mut but worse? slice::from_raw_parts_mut(v.as_mut_ptr().add(v.len()), v.capacity() - v.len()) } diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs index 3648272a343a..2bf6ccc6eef6 100644 --- a/library/std/src/sys/pal/windows/thread.rs +++ b/library/std/src/sys/pal/windows/thread.rs @@ -1,4 +1,3 @@ -#![allow(unsafe_op_in_unsafe_fn)] use crate::ffi::CStr; use crate::io; use crate::num::NonZero; @@ -23,6 +22,8 @@ pub struct Thread { impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements + #[allow(unsafe_op_in_unsafe_fn)] + // FIXME: check the internal safety pub unsafe fn new(stack: usize, p: Box) -> io::Result { let p = Box::into_raw(Box::new(p)); @@ -70,7 +71,7 @@ impl Thread { /// /// `name` must end with a zero value pub unsafe fn set_name_wide(name: &[u16]) { - c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr()); + unsafe { c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr()) }; } pub fn join(self) { From 4264548283dbaabb854e903994e4055215a956b8 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 15 Jul 2024 21:16:17 +0700 Subject: [PATCH 134/734] Add regression test for issue 13077 --- tests/ui/needless_option_as_deref.fixed | 14 ++++++++++++++ tests/ui/needless_option_as_deref.rs | 14 ++++++++++++++ tests/ui/needless_option_as_deref.stderr | 8 +++++++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/tests/ui/needless_option_as_deref.fixed b/tests/ui/needless_option_as_deref.fixed index 58f56eba0f53..7bde155582bf 100644 --- a/tests/ui/needless_option_as_deref.fixed +++ b/tests/ui/needless_option_as_deref.fixed @@ -52,3 +52,17 @@ struct S<'a> { fn from_field<'a>(s: &'a mut S<'a>) -> Option<&'a mut usize> { s.opt.as_deref_mut() } + +mod issue_non_copy_13077 { + pub fn something(mut maybe_side_effect: Option<&mut String>) { + for _ in 0..10 { + let _ = S { field: other(maybe_side_effect) }; + } + } + + fn other(_maybe_side_effect: Option<&mut String>) { + unimplemented!() + } + + pub struct S { pub field: () } +} diff --git a/tests/ui/needless_option_as_deref.rs b/tests/ui/needless_option_as_deref.rs index 842e025f669b..ab06a38f742e 100644 --- a/tests/ui/needless_option_as_deref.rs +++ b/tests/ui/needless_option_as_deref.rs @@ -52,3 +52,17 @@ struct S<'a> { fn from_field<'a>(s: &'a mut S<'a>) -> Option<&'a mut usize> { s.opt.as_deref_mut() } + +mod issue_non_copy_13077 { + pub fn something(mut maybe_side_effect: Option<&mut String>) { + for _ in 0..10 { + let _ = S { field: other(maybe_side_effect.as_deref_mut()) }; + } + } + + fn other(_maybe_side_effect: Option<&mut String>) { + unimplemented!() + } + + pub struct S { pub field: () } +} diff --git a/tests/ui/needless_option_as_deref.stderr b/tests/ui/needless_option_as_deref.stderr index a05d0aa9276a..3211062af913 100644 --- a/tests/ui/needless_option_as_deref.stderr +++ b/tests/ui/needless_option_as_deref.stderr @@ -19,5 +19,11 @@ error: derefed type is same as origin LL | let _ = x.as_deref_mut(); | ^^^^^^^^^^^^^^^^ help: try: `x` -error: aborting due to 3 previous errors +error: derefed type is same as origin + --> tests/ui/needless_option_as_deref.rs:59:38 + | +LL | let _ = S { field: other(maybe_side_effect.as_deref_mut()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_side_effect` + +error: aborting due to 4 previous errors From dcee2e8a0fb95887284b7779f2fd809f148722c5 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 15 Jul 2024 15:56:17 +0000 Subject: [PATCH 135/734] Dont stop find loop node at struct field node --- clippy_utils/src/lib.rs | 2 +- tests/ui/needless_option_as_deref.fixed | 8 ++++++-- tests/ui/needless_option_as_deref.rs | 8 ++++++-- tests/ui/needless_option_as_deref.stderr | 8 +------- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 8a6750c89976..0156e223c8d4 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1407,7 +1407,7 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>( ExprKind::Closure { .. } | ExprKind::Loop(..) => return Some(e), _ => (), }, - Node::Stmt(_) | Node::Block(_) | Node::LetStmt(_) | Node::Arm(_) => (), + Node::Stmt(_) | Node::Block(_) | Node::LetStmt(_) | Node::Arm(_) | Node::ExprField(_) => (), _ => break, } } diff --git a/tests/ui/needless_option_as_deref.fixed b/tests/ui/needless_option_as_deref.fixed index 7bde155582bf..84eaf12fc139 100644 --- a/tests/ui/needless_option_as_deref.fixed +++ b/tests/ui/needless_option_as_deref.fixed @@ -56,7 +56,9 @@ fn from_field<'a>(s: &'a mut S<'a>) -> Option<&'a mut usize> { mod issue_non_copy_13077 { pub fn something(mut maybe_side_effect: Option<&mut String>) { for _ in 0..10 { - let _ = S { field: other(maybe_side_effect) }; + let _ = S { + field: other(maybe_side_effect.as_deref_mut()), + }; } } @@ -64,5 +66,7 @@ mod issue_non_copy_13077 { unimplemented!() } - pub struct S { pub field: () } + pub struct S { + pub field: (), + } } diff --git a/tests/ui/needless_option_as_deref.rs b/tests/ui/needless_option_as_deref.rs index ab06a38f742e..fff1e45d846f 100644 --- a/tests/ui/needless_option_as_deref.rs +++ b/tests/ui/needless_option_as_deref.rs @@ -56,7 +56,9 @@ fn from_field<'a>(s: &'a mut S<'a>) -> Option<&'a mut usize> { mod issue_non_copy_13077 { pub fn something(mut maybe_side_effect: Option<&mut String>) { for _ in 0..10 { - let _ = S { field: other(maybe_side_effect.as_deref_mut()) }; + let _ = S { + field: other(maybe_side_effect.as_deref_mut()), + }; } } @@ -64,5 +66,7 @@ mod issue_non_copy_13077 { unimplemented!() } - pub struct S { pub field: () } + pub struct S { + pub field: (), + } } diff --git a/tests/ui/needless_option_as_deref.stderr b/tests/ui/needless_option_as_deref.stderr index 3211062af913..a05d0aa9276a 100644 --- a/tests/ui/needless_option_as_deref.stderr +++ b/tests/ui/needless_option_as_deref.stderr @@ -19,11 +19,5 @@ error: derefed type is same as origin LL | let _ = x.as_deref_mut(); | ^^^^^^^^^^^^^^^^ help: try: `x` -error: derefed type is same as origin - --> tests/ui/needless_option_as_deref.rs:59:38 - | -LL | let _ = S { field: other(maybe_side_effect.as_deref_mut()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_side_effect` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors From 247ad3385cb96d816da02edfb6393cc1952e5673 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 15 Jul 2024 12:40:06 -0400 Subject: [PATCH 136/734] Use dep: for crate dependencies --- compiler/rustc/Cargo.toml | 2 +- compiler/rustc_abi/Cargo.toml | 8 ++++---- compiler/rustc_ast_ir/Cargo.toml | 8 ++++---- compiler/rustc_data_structures/Cargo.toml | 2 +- compiler/rustc_index/Cargo.toml | 6 +++++- compiler/rustc_interface/Cargo.toml | 9 +++++++-- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_next_trait_solver/Cargo.toml | 6 +++--- compiler/rustc_query_system/Cargo.toml | 2 +- compiler/rustc_transmute/Cargo.toml | 14 +++++++------- compiler/rustc_type_ir/Cargo.toml | 8 ++++---- 11 files changed, 38 insertions(+), 29 deletions(-) diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml index 3cb56a7d3121..5008069542f1 100644 --- a/compiler/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -27,7 +27,7 @@ features = ['unprefixed_malloc_on_supported_platforms'] [features] # tidy-alphabetical-start -jemalloc = ['jemalloc-sys'] +jemalloc = ['dep:jemalloc-sys'] llvm = ['rustc_driver_impl/llvm'] max_level_info = ['rustc_driver_impl/max_level_info'] rustc_use_parallel_compiler = ['rustc_driver_impl/rustc_use_parallel_compiler'] diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml index 5031e7a6705f..7448f066d0ac 100644 --- a/compiler/rustc_abi/Cargo.toml +++ b/compiler/rustc_abi/Cargo.toml @@ -21,10 +21,10 @@ default = ["nightly", "randomize"] # rust-analyzer depends on this crate and we therefore require it to built on a stable toolchain # without depending on rustc_data_structures, rustc_macros and rustc_serialize nightly = [ - "rustc_data_structures", + "dep:rustc_data_structures", + "dep:rustc_macros", + "dep:rustc_serialize", "rustc_index/nightly", - "rustc_macros", - "rustc_serialize", ] -randomize = ["rand", "rand_xoshiro", "nightly"] +randomize = ["dep:rand", "dep:rand_xoshiro", "nightly"] # tidy-alphabetical-end diff --git a/compiler/rustc_ast_ir/Cargo.toml b/compiler/rustc_ast_ir/Cargo.toml index a78c91e0615b..1905574073f1 100644 --- a/compiler/rustc_ast_ir/Cargo.toml +++ b/compiler/rustc_ast_ir/Cargo.toml @@ -14,8 +14,8 @@ rustc_span = { path = "../rustc_span", optional = true } [features] default = ["nightly"] nightly = [ - "rustc_serialize", - "rustc_data_structures", - "rustc_macros", - "rustc_span", + "dep:rustc_serialize", + "dep:rustc_data_structures", + "dep:rustc_macros", + "dep:rustc_span", ] diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index e5e733439ea0..3794a6e043c6 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -56,5 +56,5 @@ portable-atomic = "1.5.1" [features] # tidy-alphabetical-start -rustc_use_parallel_compiler = ["indexmap/rustc-rayon", "rustc-rayon"] +rustc_use_parallel_compiler = ["indexmap/rustc-rayon", "dep:rustc-rayon"] # tidy-alphabetical-end diff --git a/compiler/rustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml index 3a4c813b5d41..92ea3f278dc4 100644 --- a/compiler/rustc_index/Cargo.toml +++ b/compiler/rustc_index/Cargo.toml @@ -15,5 +15,9 @@ smallvec = "1.8.1" [features] # tidy-alphabetical-start default = ["nightly"] -nightly = ["rustc_serialize", "rustc_macros", "rustc_index_macros/nightly"] +nightly = [ + "dep:rustc_serialize", + "dep:rustc_macros", + "rustc_index_macros/nightly", +] # tidy-alphabetical-end diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 4b3b0728f385..b5abf145d6b5 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -53,6 +53,11 @@ tracing = "0.1" [features] # tidy-alphabetical-start -llvm = ['rustc_codegen_llvm'] -rustc_use_parallel_compiler = ['rustc-rayon', 'rustc-rayon-core', 'rustc_query_impl/rustc_use_parallel_compiler', 'rustc_errors/rustc_use_parallel_compiler'] +llvm = ['dep:rustc_codegen_llvm'] +rustc_use_parallel_compiler = [ + 'dep:rustc-rayon', + 'dep:rustc-rayon-core', + 'rustc_query_impl/rustc_use_parallel_compiler', + 'rustc_errors/rustc_use_parallel_compiler' +] # tidy-alphabetical-end diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 3dc592980fdb..290ebde87128 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -40,5 +40,5 @@ tracing = "0.1" [features] # tidy-alphabetical-start -rustc_use_parallel_compiler = ["rustc-rayon-core"] +rustc_use_parallel_compiler = ["dep:rustc-rayon-core"] # tidy-alphabetical-end diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 07cd4ae68d9a..79d2107b2a0a 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -20,10 +20,10 @@ tracing = "0.1" [features] default = ["nightly"] nightly = [ + "dep:rustc_data_structures", + "dep:rustc_macros", + "dep:rustc_serialize", "rustc_ast_ir/nightly", - "rustc_data_structures", "rustc_index/nightly", - "rustc_macros", - "rustc_serialize", "rustc_type_ir/nightly", ] diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index 4d845ab0d07b..2f42fa47728c 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -26,5 +26,5 @@ tracing = "0.1" [features] # tidy-alphabetical-start -rustc_use_parallel_compiler = ["rustc-rayon-core"] +rustc_use_parallel_compiler = ["dep:rustc-rayon-core"] # tidy-alphabetical-end diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml index 79939d62a51a..4732e968f6b4 100644 --- a/compiler/rustc_transmute/Cargo.toml +++ b/compiler/rustc_transmute/Cargo.toml @@ -18,13 +18,13 @@ tracing = "0.1" [features] rustc = [ - "rustc_hir", - "rustc_infer", - "rustc_macros", - "rustc_middle", - "rustc_span", - "rustc_target", - "rustc_ast_ir", + "dep:rustc_hir", + "dep:rustc_infer", + "dep:rustc_macros", + "dep:rustc_middle", + "dep:rustc_span", + "dep:rustc_target", + "dep:rustc_ast_ir", ] [dev-dependencies] diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index e4bf6069caf3..769e350b835c 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -22,12 +22,12 @@ tracing = "0.1" [features] default = ["nightly"] nightly = [ + "dep:rustc_serialize", + "dep:rustc_span", + "dep:rustc_data_structures", + "dep:rustc_macros", "smallvec/may_dangle", "smallvec/union", "rustc_index/nightly", - "rustc_serialize", - "rustc_span", - "rustc_data_structures", - "rustc_macros", "rustc_ast_ir/nightly" ] From 324d2e51ee16f56cc82485694f18a92b2eb315f3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 15 Jul 2024 12:44:24 -0400 Subject: [PATCH 137/734] Fix feature gating on rustc_index to not use implicit features --- compiler/rustc_index/src/vec.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index b866c8b8433d..346ce945bf94 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -1,4 +1,4 @@ -#[cfg(feature = "rustc_serialize")] +#[cfg(feature = "nightly")] use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::borrow::{Borrow, BorrowMut}; @@ -322,14 +322,14 @@ impl From<[T; N]> for IndexVec { } } -#[cfg(feature = "rustc_serialize")] +#[cfg(feature = "nightly")] impl> Encodable for IndexVec { fn encode(&self, s: &mut S) { Encodable::encode(&self.raw, s); } } -#[cfg(feature = "rustc_serialize")] +#[cfg(feature = "nightly")] impl> Decodable for IndexVec { fn decode(d: &mut D) -> Self { IndexVec::from_raw(Vec::::decode(d)) From 7e1c4afb1d4e6bbdff772ccc5589e183490775ed Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 15 Jul 2024 13:01:20 -0400 Subject: [PATCH 138/734] The rustc crate feature is called jemalloc --- compiler/rustc/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs index 7ba58406ef1a..29766fc9d87c 100644 --- a/compiler/rustc/src/main.rs +++ b/compiler/rustc/src/main.rs @@ -34,7 +34,7 @@ fn main() { // See the comment at the top of this file for an explanation of this. - #[cfg(feature = "jemalloc-sys")] + #[cfg(feature = "jemalloc")] { use std::os::raw::{c_int, c_void}; From 8edf9b808427dfbe4425b49d213351f907f58b40 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 20 Mar 2024 20:30:04 -0400 Subject: [PATCH 139/734] Item bounds can reference self projections and still be object safe --- .../src/traits/object_safety.rs | 120 ++++++++++++------ .../item-bounds-can-reference-self.rs | 11 ++ 2 files changed, 89 insertions(+), 42 deletions(-) create mode 100644 tests/ui/object-safety/item-bounds-can-reference-self.rs diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 1c6993bdd372..29c18512e6d9 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -12,16 +12,16 @@ use super::elaborate; use crate::infer::TyCtxtInferExt; use crate::traits::query::evaluate_obligation::InferCtxtExt; -use crate::traits::{self, Obligation, ObligationCause}; +use crate::traits::{Obligation, ObligationCause}; use rustc_errors::FatalError; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::query::Providers; +use rustc_middle::ty::GenericArgs; use rustc_middle::ty::{ self, EarlyBinder, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; -use rustc_middle::ty::{GenericArg, GenericArgs}; use rustc_middle::ty::{TypeVisitableExt, Upcast}; use rustc_span::symbol::Symbol; use rustc_span::Span; @@ -195,7 +195,13 @@ fn predicates_reference_self( .predicates .iter() .map(|&(predicate, sp)| (predicate.instantiate_supertrait(tcx, trait_ref), sp)) - .filter_map(|predicate| predicate_references_self(tcx, predicate)) + .filter_map(|(clause, sp)| { + // Super predicates cannot allow self projections, since they're + // impossible to make into existential bounds without eager resolution + // or something. + // e.g. `trait A: B`. + predicate_references_self(tcx, trait_def_id, clause, sp, AllowSelfProjections::No) + }) .collect() } @@ -204,20 +210,25 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) .flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied()) - .filter_map(|c| predicate_references_self(tcx, c)) + .filter_map(|(clause, sp)| { + // Item bounds *can* have self projections, since they never get + // their self type erased. + predicate_references_self(tcx, trait_def_id, clause, sp, AllowSelfProjections::Yes) + }) .collect() } fn predicate_references_self<'tcx>( tcx: TyCtxt<'tcx>, - (predicate, sp): (ty::Clause<'tcx>, Span), + trait_def_id: DefId, + predicate: ty::Clause<'tcx>, + sp: Span, + allow_self_projections: AllowSelfProjections, ) -> Option { - let self_ty = tcx.types.self_param; - let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk().any(|arg| arg == self_ty.into()); match predicate.kind().skip_binder() { ty::ClauseKind::Trait(ref data) => { // In the case of a trait predicate, we can skip the "self" type. - data.trait_ref.args[1..].iter().any(has_self_ty).then_some(sp) + data.trait_ref.args[1..].iter().any(|&arg| contains_illegal_self_type_reference(tcx, trait_def_id, arg, allow_self_projections)).then_some(sp) } ty::ClauseKind::Projection(ref data) => { // And similarly for projections. This should be redundant with @@ -235,9 +246,9 @@ fn predicate_references_self<'tcx>( // // This is ALT2 in issue #56288, see that for discussion of the // possible alternatives. - data.projection_term.args[1..].iter().any(has_self_ty).then_some(sp) + data.projection_term.args[1..].iter().any(|&arg| contains_illegal_self_type_reference(tcx, trait_def_id, arg, allow_self_projections)).then_some(sp) } - ty::ClauseKind::ConstArgHasType(_ct, ty) => has_self_ty(&ty.into()).then_some(sp), + ty::ClauseKind::ConstArgHasType(_ct, ty) => contains_illegal_self_type_reference(tcx, trait_def_id, ty, allow_self_projections).then_some(sp), ty::ClauseKind::WellFormed(..) | ty::ClauseKind::TypeOutlives(..) @@ -383,7 +394,12 @@ fn virtual_call_violations_for_method<'tcx>( let mut errors = Vec::new(); for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) { - if contains_illegal_self_type_reference(tcx, trait_def_id, sig.rebind(input_ty)) { + if contains_illegal_self_type_reference( + tcx, + trait_def_id, + sig.rebind(input_ty), + AllowSelfProjections::Yes, + ) { let span = if let Some(hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(sig, _), .. @@ -396,7 +412,12 @@ fn virtual_call_violations_for_method<'tcx>( errors.push(MethodViolationCode::ReferencesSelfInput(span)); } } - if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) { + if contains_illegal_self_type_reference( + tcx, + trait_def_id, + sig.output(), + AllowSelfProjections::Yes, + ) { errors.push(MethodViolationCode::ReferencesSelfOutput); } if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) { @@ -482,7 +503,7 @@ fn virtual_call_violations_for_method<'tcx>( return false; } - contains_illegal_self_type_reference(tcx, trait_def_id, pred) + contains_illegal_self_type_reference(tcx, trait_def_id, pred, AllowSelfProjections::Yes) }) { errors.push(MethodViolationCode::WhereClauseReferencesSelf); } @@ -711,10 +732,17 @@ fn receiver_is_dispatchable<'tcx>( infcx.predicate_must_hold_modulo_regions(&obligation) } +#[derive(Copy, Clone)] +enum AllowSelfProjections { + Yes, + No, +} + fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable>>( tcx: TyCtxt<'tcx>, trait_def_id: DefId, value: T, + allow_self_projections: AllowSelfProjections, ) -> bool { // This is somewhat subtle. In general, we want to forbid // references to `Self` in the argument and return types, @@ -759,6 +787,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable>>( tcx: TyCtxt<'tcx>, trait_def_id: DefId, supertraits: Option>, + allow_self_projections: AllowSelfProjections, } impl<'tcx> TypeVisitor> for IllegalSelfTypeVisitor<'tcx> { @@ -780,39 +809,41 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable>>( ControlFlow::Continue(()) } ty::Alias(ty::Projection, ref data) => { - // This is a projected type `::X`. + match self.allow_self_projections { + AllowSelfProjections::Yes => { + // This is a projected type `::X`. - // Compute supertraits of current trait lazily. - if self.supertraits.is_none() { - let trait_ref = - ty::Binder::dummy(ty::TraitRef::identity(self.tcx, self.trait_def_id)); - self.supertraits = Some( - traits::supertraits(self.tcx, trait_ref).map(|t| t.def_id()).collect(), - ); - } + // Compute supertraits of current trait lazily. + if self.supertraits.is_none() { + self.supertraits = + Some(self.tcx.supertrait_def_ids(self.trait_def_id).collect()); + } - // Determine whether the trait reference `Foo as - // SomeTrait` is in fact a supertrait of the - // current trait. In that case, this type is - // legal, because the type `X` will be specified - // in the object type. Note that we can just use - // direct equality here because all of these types - // are part of the formal parameter listing, and - // hence there should be no inference variables. - let is_supertrait_of_current_trait = self - .supertraits - .as_ref() - .unwrap() - .contains(&data.trait_ref(self.tcx).def_id); + // Determine whether the trait reference `Foo as + // SomeTrait` is in fact a supertrait of the + // current trait. In that case, this type is + // legal, because the type `X` will be specified + // in the object type. Note that we can just use + // direct equality here because all of these types + // are part of the formal parameter listing, and + // hence there should be no inference variables. + let is_supertrait_of_current_trait = self + .supertraits + .as_ref() + .unwrap() + .contains(&data.trait_ref(self.tcx).def_id); - // only walk contained types if it's not a super trait - if is_supertrait_of_current_trait { - ControlFlow::Continue(()) - } else { - t.super_visit_with(self) // POSSIBLY reporting an error + // only walk contained types if it's not a super trait + if is_supertrait_of_current_trait { + ControlFlow::Continue(()) + } else { + t.super_visit_with(self) // POSSIBLY reporting an error + } + } + AllowSelfProjections::No => t.super_visit_with(self), } } - _ => t.super_visit_with(self), // walk contained types, if any + _ => t.super_visit_with(self), } } @@ -824,7 +855,12 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable>>( } value - .visit_with(&mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits: None }) + .visit_with(&mut IllegalSelfTypeVisitor { + tcx, + trait_def_id, + supertraits: None, + allow_self_projections, + }) .is_break() } diff --git a/tests/ui/object-safety/item-bounds-can-reference-self.rs b/tests/ui/object-safety/item-bounds-can-reference-self.rs new file mode 100644 index 000000000000..4ae982e8f951 --- /dev/null +++ b/tests/ui/object-safety/item-bounds-can-reference-self.rs @@ -0,0 +1,11 @@ +//@ check-pass + +pub trait Foo { + type X: PartialEq; + type Y: PartialEq; + type Z: PartialEq; +} + +fn uwu(x: &dyn Foo) {} + +fn main() {} From 172cf9bef3411d479a0be98827647150cce48afd Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 6 Jun 2024 14:40:56 -0400 Subject: [PATCH 140/734] Fix unsoundness when associated types dont actually come from supertraits --- .../src/traits/object_safety.rs | 274 ++++++++++-------- .../almost-supertrait-associated-type.rs | 60 ++++ .../almost-supertrait-associated-type.stderr | 55 ++++ 3 files changed, 274 insertions(+), 115 deletions(-) create mode 100644 tests/ui/object-safety/almost-supertrait-associated-type.rs create mode 100644 tests/ui/object-safety/almost-supertrait-associated-type.stderr diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 29c18512e6d9..ec19cf276681 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -12,17 +12,16 @@ use super::elaborate; use crate::infer::TyCtxtInferExt; use crate::traits::query::evaluate_obligation::InferCtxtExt; -use crate::traits::{Obligation, ObligationCause}; +use crate::traits::{util, Obligation, ObligationCause}; use rustc_errors::FatalError; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::query::Providers; -use rustc_middle::ty::GenericArgs; use rustc_middle::ty::{ - self, EarlyBinder, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeSuperVisitable, - TypeVisitable, TypeVisitor, + self, EarlyBinder, ExistentialPredicateStableCmpExt as _, GenericArgs, Ty, TyCtxt, + TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, Upcast, }; -use rustc_middle::ty::{TypeVisitableExt, Upcast}; use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_target::abi::Abi; @@ -738,122 +737,50 @@ enum AllowSelfProjections { No, } +/// This is somewhat subtle. In general, we want to forbid +/// references to `Self` in the argument and return types, +/// since the value of `Self` is erased. However, there is one +/// exception: it is ok to reference `Self` in order to access +/// an associated type of the current trait, since we retain +/// the value of those associated types in the object type +/// itself. +/// +/// ```rust,ignore (example) +/// trait SuperTrait { +/// type X; +/// } +/// +/// trait Trait : SuperTrait { +/// type Y; +/// fn foo(&self, x: Self) // bad +/// fn foo(&self) -> Self // bad +/// fn foo(&self) -> Option // bad +/// fn foo(&self) -> Self::Y // OK, desugars to next example +/// fn foo(&self) -> ::Y // OK +/// fn foo(&self) -> Self::X // OK, desugars to next example +/// fn foo(&self) -> ::X // OK +/// } +/// ``` +/// +/// However, it is not as simple as allowing `Self` in a projected +/// type, because there are illegal ways to use `Self` as well: +/// +/// ```rust,ignore (example) +/// trait Trait : SuperTrait { +/// ... +/// fn foo(&self) -> ::X; +/// } +/// ``` +/// +/// Here we will not have the type of `X` recorded in the +/// object type, and we cannot resolve `Self as SomeOtherTrait` +/// without knowing what `Self` is. fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable>>( tcx: TyCtxt<'tcx>, trait_def_id: DefId, value: T, allow_self_projections: AllowSelfProjections, ) -> bool { - // This is somewhat subtle. In general, we want to forbid - // references to `Self` in the argument and return types, - // since the value of `Self` is erased. However, there is one - // exception: it is ok to reference `Self` in order to access - // an associated type of the current trait, since we retain - // the value of those associated types in the object type - // itself. - // - // ```rust - // trait SuperTrait { - // type X; - // } - // - // trait Trait : SuperTrait { - // type Y; - // fn foo(&self, x: Self) // bad - // fn foo(&self) -> Self // bad - // fn foo(&self) -> Option // bad - // fn foo(&self) -> Self::Y // OK, desugars to next example - // fn foo(&self) -> ::Y // OK - // fn foo(&self) -> Self::X // OK, desugars to next example - // fn foo(&self) -> ::X // OK - // } - // ``` - // - // However, it is not as simple as allowing `Self` in a projected - // type, because there are illegal ways to use `Self` as well: - // - // ```rust - // trait Trait : SuperTrait { - // ... - // fn foo(&self) -> ::X; - // } - // ``` - // - // Here we will not have the type of `X` recorded in the - // object type, and we cannot resolve `Self as SomeOtherTrait` - // without knowing what `Self` is. - - struct IllegalSelfTypeVisitor<'tcx> { - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - supertraits: Option>, - allow_self_projections: AllowSelfProjections, - } - - impl<'tcx> TypeVisitor> for IllegalSelfTypeVisitor<'tcx> { - type Result = ControlFlow<()>; - - fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { - match t.kind() { - ty::Param(_) => { - if t == self.tcx.types.self_param { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } - } - ty::Alias(ty::Projection, ref data) - if self.tcx.is_impl_trait_in_trait(data.def_id) => - { - // We'll deny these later in their own pass - ControlFlow::Continue(()) - } - ty::Alias(ty::Projection, ref data) => { - match self.allow_self_projections { - AllowSelfProjections::Yes => { - // This is a projected type `::X`. - - // Compute supertraits of current trait lazily. - if self.supertraits.is_none() { - self.supertraits = - Some(self.tcx.supertrait_def_ids(self.trait_def_id).collect()); - } - - // Determine whether the trait reference `Foo as - // SomeTrait` is in fact a supertrait of the - // current trait. In that case, this type is - // legal, because the type `X` will be specified - // in the object type. Note that we can just use - // direct equality here because all of these types - // are part of the formal parameter listing, and - // hence there should be no inference variables. - let is_supertrait_of_current_trait = self - .supertraits - .as_ref() - .unwrap() - .contains(&data.trait_ref(self.tcx).def_id); - - // only walk contained types if it's not a super trait - if is_supertrait_of_current_trait { - ControlFlow::Continue(()) - } else { - t.super_visit_with(self) // POSSIBLY reporting an error - } - } - AllowSelfProjections::No => t.super_visit_with(self), - } - } - _ => t.super_visit_with(self), - } - } - - fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result { - // Constants can only influence object safety if they are generic and reference `Self`. - // This is only possible for unevaluated constants, so we walk these here. - self.tcx.expand_abstract_consts(ct).super_visit_with(self) - } - } - value .visit_with(&mut IllegalSelfTypeVisitor { tcx, @@ -864,6 +791,123 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable>>( .is_break() } +struct IllegalSelfTypeVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + supertraits: Option>>, + allow_self_projections: AllowSelfProjections, +} + +impl<'tcx> TypeVisitor> for IllegalSelfTypeVisitor<'tcx> { + type Result = ControlFlow<()>; + + fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { + match t.kind() { + ty::Param(_) => { + if t == self.tcx.types.self_param { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + } + ty::Alias(ty::Projection, ref data) if self.tcx.is_impl_trait_in_trait(data.def_id) => { + // We'll deny these later in their own pass + ControlFlow::Continue(()) + } + ty::Alias(ty::Projection, ref data) => { + match self.allow_self_projections { + AllowSelfProjections::Yes => { + // This is a projected type `::X`. + + // Compute supertraits of current trait lazily. + if self.supertraits.is_none() { + self.supertraits = Some( + util::supertraits( + self.tcx, + ty::Binder::dummy(ty::TraitRef::identity( + self.tcx, + self.trait_def_id, + )), + ) + .map(|trait_ref| { + self.tcx.erase_regions( + self.tcx.instantiate_bound_regions_with_erased(trait_ref), + ) + }) + .collect(), + ); + } + + // Determine whether the trait reference `Foo as + // SomeTrait` is in fact a supertrait of the + // current trait. In that case, this type is + // legal, because the type `X` will be specified + // in the object type. Note that we can just use + // direct equality here because all of these types + // are part of the formal parameter listing, and + // hence there should be no inference variables. + let is_supertrait_of_current_trait = + self.supertraits.as_ref().unwrap().contains( + &data.trait_ref(self.tcx).fold_with( + &mut EraseEscapingBoundRegions { + tcx: self.tcx, + binder: ty::INNERMOST, + }, + ), + ); + + // only walk contained types if it's not a super trait + if is_supertrait_of_current_trait { + ControlFlow::Continue(()) + } else { + t.super_visit_with(self) // POSSIBLY reporting an error + } + } + AllowSelfProjections::No => t.super_visit_with(self), + } + } + _ => t.super_visit_with(self), + } + } + + fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result { + // Constants can only influence object safety if they are generic and reference `Self`. + // This is only possible for unevaluated constants, so we walk these here. + self.tcx.expand_abstract_consts(ct).super_visit_with(self) + } +} + +struct EraseEscapingBoundRegions<'tcx> { + tcx: TyCtxt<'tcx>, + binder: ty::DebruijnIndex, +} + +impl<'tcx> TypeFolder> for EraseEscapingBoundRegions<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_binder(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T> + where + T: TypeFoldable>, + { + self.binder.shift_in(1); + let result = t.super_fold_with(self); + self.binder.shift_out(1); + result + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + if let ty::ReBound(debruijn, _) = *r + && debruijn < self.binder + { + r + } else { + self.tcx.lifetimes.re_erased + } + } +} + pub fn contains_illegal_impl_trait_in_trait<'tcx>( tcx: TyCtxt<'tcx>, fn_def_id: DefId, diff --git a/tests/ui/object-safety/almost-supertrait-associated-type.rs b/tests/ui/object-safety/almost-supertrait-associated-type.rs new file mode 100644 index 000000000000..963cdff526ee --- /dev/null +++ b/tests/ui/object-safety/almost-supertrait-associated-type.rs @@ -0,0 +1,60 @@ +// Test for fixed unsoundness in #126079. +// Enforces that the associated types that are object safe + +use std::marker::PhantomData; + +fn transmute(t: T) -> U { + (&PhantomData:: as &dyn Foo).transmute(t) + //~^ ERROR the trait `Foo` cannot be made into an object + //~| ERROR the trait `Foo` cannot be made into an object +} + +struct ActuallySuper; +struct NotActuallySuper; +trait Super { + type Assoc; +} + +trait Dyn { + type Out; +} +impl Dyn for dyn Foo + '_ { +//~^ ERROR the trait `Foo` cannot be made into an object + type Out = U; +} +impl + ?Sized, U> Super for S { + type Assoc = U; +} + +trait Foo: Super +where + ::Assoc: Super +{ + fn transmute(&self, t: T) -> >::Assoc; +} + +trait Mirror { + type Assoc: ?Sized; +} +impl Mirror for T { + type Assoc = T; +} + +impl Foo for PhantomData { + fn transmute(&self, t: T) -> T { + t + } +} +impl Super for PhantomData { + type Assoc = T; +} +impl Super for PhantomData { + type Assoc = T; +} + +fn main() { + let x = String::from("hello, world"); + let s = transmute::<&str, &'static str>(x.as_str()); + drop(x); + println!("> {s}"); +} diff --git a/tests/ui/object-safety/almost-supertrait-associated-type.stderr b/tests/ui/object-safety/almost-supertrait-associated-type.stderr new file mode 100644 index 000000000000..97a51c2f3816 --- /dev/null +++ b/tests/ui/object-safety/almost-supertrait-associated-type.stderr @@ -0,0 +1,55 @@ +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/almost-supertrait-associated-type.rs:21:20 + | +LL | impl Dyn for dyn Foo + '_ { + | ^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/almost-supertrait-associated-type.rs:33:34 + | +LL | trait Foo: Super + | --- this trait cannot be made into an object... +... +LL | fn transmute(&self, t: T) -> >::Assoc; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `transmute` references the `Self` type in its return type + = help: consider moving `transmute` to another trait + = help: only type `std::marker::PhantomData` implements the trait, consider using it directly instead + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/almost-supertrait-associated-type.rs:7:27 + | +LL | (&PhantomData:: as &dyn Foo).transmute(t) + | ^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/almost-supertrait-associated-type.rs:33:34 + | +LL | trait Foo: Super + | --- this trait cannot be made into an object... +... +LL | fn transmute(&self, t: T) -> >::Assoc; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `transmute` references the `Self` type in its return type + = help: consider moving `transmute` to another trait + = help: only type `std::marker::PhantomData` implements the trait, consider using it directly instead + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/almost-supertrait-associated-type.rs:7:6 + | +LL | (&PhantomData:: as &dyn Foo).transmute(t) + | ^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/almost-supertrait-associated-type.rs:33:34 + | +LL | trait Foo: Super + | --- this trait cannot be made into an object... +... +LL | fn transmute(&self, t: T) -> >::Assoc; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `transmute` references the `Self` type in its return type + = help: consider moving `transmute` to another trait + = help: only type `std::marker::PhantomData` implements the trait, consider using it directly instead + = note: required for the cast from `&PhantomData` to `&dyn Foo` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0038`. From f6fe7e49a2bc2ad14513aa609b67e188470309f6 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Sun, 14 Jul 2024 22:17:28 +0300 Subject: [PATCH 141/734] lib: replace some `mem::forget`'s with `ManuallyDrop` --- library/alloc/src/rc.rs | 45 +++++++++---------- library/alloc/src/sync.rs | 36 +++++++-------- library/core/src/task/wake.rs | 15 +++---- library/proc_macro/src/bridge/buffer.rs | 11 +++-- library/proc_macro/src/bridge/client.rs | 4 +- library/std/src/os/fd/owned.rs | 6 +-- library/std/src/os/solid/io.rs | 6 +-- library/std/src/os/windows/io/handle.rs | 6 +-- library/std/src/os/windows/io/socket.rs | 7 +-- library/std/src/sys/pal/hermit/thread.rs | 6 +-- library/std/src/sys/pal/sgx/abi/tls/mod.rs | 4 +- .../src/sys/pal/sgx/abi/usercalls/alloc.rs | 7 ++- library/std/src/sys/pal/sgx/fd.rs | 10 ++--- library/std/src/sys/pal/teeos/thread.rs | 16 +++---- library/std/src/sys/pal/unix/thread.rs | 14 +++--- library/std/src/sys/pal/wasi/thread.rs | 10 ++--- library/std/src/thread/mod.rs | 9 ++-- .../libc_pthread_mutex_deadlock.stderr | 2 +- ..._pthread_rwlock_write_read_deadlock.stderr | 2 +- ...pthread_rwlock_write_write_deadlock.stderr | 2 +- 20 files changed, 87 insertions(+), 131 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 9982c8ea6dcb..bfe3ea208001 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -259,7 +259,7 @@ use core::intrinsics::abort; #[cfg(not(no_global_oom_handling))] use core::iter; use core::marker::{PhantomData, Unsize}; -use core::mem::{self, align_of_val_raw, forget, ManuallyDrop}; +use core::mem::{self, align_of_val_raw, ManuallyDrop}; use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; #[cfg(not(no_global_oom_handling))] @@ -908,19 +908,18 @@ impl Rc { #[stable(feature = "rc_unique", since = "1.4.0")] pub fn try_unwrap(this: Self) -> Result { if Rc::strong_count(&this) == 1 { - unsafe { - let val = ptr::read(&*this); // copy the contained object - let alloc = ptr::read(&this.alloc); // copy the allocator + let this = ManuallyDrop::new(this); - // Indicate to Weaks that they can't be promoted by decrementing - // the strong count, and then remove the implicit "strong weak" - // pointer while also handling drop logic by just crafting a - // fake Weak. - this.inner().dec_strong(); - let _weak = Weak { ptr: this.ptr, alloc }; - forget(this); - Ok(val) - } + let val: T = unsafe { ptr::read(&**this) }; // copy the contained object + let alloc: A = unsafe { ptr::read(&this.alloc) }; // copy the allocator + + // Indicate to Weaks that they can't be promoted by decrementing + // the strong count, and then remove the implicit "strong weak" + // pointer while also handling drop logic by just crafting a + // fake Weak. + this.inner().dec_strong(); + let _weak = Weak { ptr: this.ptr, alloc }; + Ok(val) } else { Err(this) } @@ -1354,9 +1353,8 @@ impl Rc { #[stable(feature = "rc_raw", since = "1.17.0")] #[rustc_never_returns_null_ptr] pub fn into_raw(this: Self) -> *const T { - let ptr = Self::as_ptr(&this); - mem::forget(this); - ptr + let this = ManuallyDrop::new(this); + Self::as_ptr(&*this) } /// Consumes the `Rc`, returning the wrapped pointer and allocator. @@ -2127,7 +2125,7 @@ impl Rc<[T]> { } // All clear. Forget the guard so it doesn't free the new RcBox. - forget(guard); + mem::forget(guard); Self::from_ptr(ptr) } @@ -3080,9 +3078,7 @@ impl Weak { #[must_use = "losing the pointer will leak memory"] #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn into_raw(self) -> *const T { - let result = self.as_ptr(); - mem::forget(self); - result + mem::ManuallyDrop::new(self).as_ptr() } /// Consumes the `Weak`, returning the wrapped pointer and allocator. @@ -3762,10 +3758,11 @@ impl UniqueRcUninit { /// # Safety /// /// The data must have been initialized (by writing to [`Self::data_ptr()`]). - unsafe fn into_rc(mut self) -> Rc { - let ptr = self.ptr; - let alloc = self.alloc.take().unwrap(); - mem::forget(self); + unsafe fn into_rc(self) -> Rc { + let mut this = ManuallyDrop::new(self); + let ptr = this.ptr; + let alloc = this.alloc.take().unwrap(); + // SAFETY: The pointer is valid as per `UniqueRcUninit::new`, and the caller is responsible // for having initialized the data. unsafe { Rc::from_ptr_in(ptr.as_ptr(), alloc) } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index a905a1e6b7e6..c36b8f6a1ac8 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -20,7 +20,7 @@ use core::intrinsics::abort; #[cfg(not(no_global_oom_handling))] use core::iter; use core::marker::{PhantomData, Unsize}; -use core::mem::{self, align_of_val_raw}; +use core::mem::{self, align_of_val_raw, ManuallyDrop}; use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, Receiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; use core::pin::Pin; @@ -960,16 +960,14 @@ impl Arc { acquire!(this.inner().strong); - unsafe { - let elem = ptr::read(&this.ptr.as_ref().data); - let alloc = ptr::read(&this.alloc); // copy the allocator + let this = ManuallyDrop::new(this); + let elem: T = unsafe { ptr::read(&this.ptr.as_ref().data) }; + let alloc: A = unsafe { ptr::read(&this.alloc) }; // copy the allocator - // Make a weak pointer to clean up the implicit strong-weak reference - let _weak = Weak { ptr: this.ptr, alloc }; - mem::forget(this); + // Make a weak pointer to clean up the implicit strong-weak reference + let _weak = Weak { ptr: this.ptr, alloc }; - Ok(elem) - } + Ok(elem) } /// Returns the inner value, if the `Arc` has exactly one strong reference. @@ -1493,9 +1491,8 @@ impl Arc { #[stable(feature = "rc_raw", since = "1.17.0")] #[rustc_never_returns_null_ptr] pub fn into_raw(this: Self) -> *const T { - let ptr = Self::as_ptr(&this); - mem::forget(this); - ptr + let this = ManuallyDrop::new(this); + Self::as_ptr(&*this) } /// Consumes the `Arc`, returning the wrapped pointer and allocator. @@ -2801,9 +2798,7 @@ impl Weak { #[must_use = "losing the pointer will leak memory"] #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn into_raw(self) -> *const T { - let result = self.as_ptr(); - mem::forget(self); - result + ManuallyDrop::new(self).as_ptr() } /// Consumes the `Weak`, returning the wrapped pointer and allocator. @@ -3875,13 +3870,14 @@ impl UniqueArcUninit { /// # Safety /// /// The data must have been initialized (by writing to [`Self::data_ptr()`]). - unsafe fn into_arc(mut self) -> Arc { - let ptr = self.ptr; - let alloc = self.alloc.take().unwrap(); - mem::forget(self); + unsafe fn into_arc(self) -> Arc { + let mut this = ManuallyDrop::new(self); + let ptr = this.ptr.as_ptr(); + let alloc = this.alloc.take().unwrap(); + // SAFETY: The pointer is valid as per `UniqueArcUninit::new`, and the caller is responsible // for having initialized the data. - unsafe { Arc::from_ptr_in(ptr.as_ptr(), alloc) } + unsafe { Arc::from_ptr_in(ptr, alloc) } } } diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 86a965f68e08..e785d75a63d7 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -1,10 +1,9 @@ #![stable(feature = "futures_api", since = "1.36.0")] -use crate::mem::transmute; - use crate::any::Any; use crate::fmt; use crate::marker::PhantomData; +use crate::mem::{transmute, ManuallyDrop}; use crate::panic::AssertUnwindSafe; use crate::ptr; @@ -465,16 +464,14 @@ impl Waker { pub fn wake(self) { // The actual wakeup call is delegated through a virtual function call // to the implementation which is defined by the executor. - let wake = self.waker.vtable.wake; - let data = self.waker.data; // Don't call `drop` -- the waker will be consumed by `wake`. - crate::mem::forget(self); + let this = ManuallyDrop::new(self); // SAFETY: This is safe because `Waker::from_raw` is the only way // to initialize `wake` and `data` requiring the user to acknowledge // that the contract of `RawWaker` is upheld. - unsafe { (wake)(data) }; + unsafe { (this.waker.vtable.wake)(this.waker.data) }; } /// Wake up the task associated with this `Waker` without consuming the `Waker`. @@ -726,16 +723,14 @@ impl LocalWaker { pub fn wake(self) { // The actual wakeup call is delegated through a virtual function call // to the implementation which is defined by the executor. - let wake = self.waker.vtable.wake; - let data = self.waker.data; // Don't call `drop` -- the waker will be consumed by `wake`. - crate::mem::forget(self); + let this = ManuallyDrop::new(self); // SAFETY: This is safe because `Waker::from_raw` is the only way // to initialize `wake` and `data` requiring the user to acknowledge // that the contract of `RawWaker` is upheld. - unsafe { (wake)(data) }; + unsafe { (this.waker.vtable.wake)(this.waker.data) }; } /// Wake up the task associated with this `LocalWaker` without consuming the `LocalWaker`. diff --git a/library/proc_macro/src/bridge/buffer.rs b/library/proc_macro/src/bridge/buffer.rs index 149767bf7052..78fcd1999b2f 100644 --- a/library/proc_macro/src/bridge/buffer.rs +++ b/library/proc_macro/src/bridge/buffer.rs @@ -1,7 +1,7 @@ //! Buffer management for same-process client<->server communication. use std::io::{self, Write}; -use std::mem; +use std::mem::{self, ManuallyDrop}; use std::ops::{Deref, DerefMut}; use std::slice; @@ -129,17 +129,16 @@ impl Drop for Buffer { } impl From> for Buffer { - fn from(mut v: Vec) -> Self { + fn from(v: Vec) -> Self { + let mut v = ManuallyDrop::new(v); let (data, len, capacity) = (v.as_mut_ptr(), v.len(), v.capacity()); - mem::forget(v); // This utility function is nested in here because it can *only* // be safely called on `Buffer`s created by *this* `proc_macro`. fn to_vec(b: Buffer) -> Vec { unsafe { - let Buffer { data, len, capacity, .. } = b; - mem::forget(b); - Vec::from_raw_parts(data, len, capacity) + let b = ManuallyDrop::new(b); + Vec::from_raw_parts(b.data, b.len, b.capacity) } } diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index faca745e56f7..9658fc4840f6 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -51,9 +51,7 @@ macro_rules! define_client_handles { impl Encode for $oty { fn encode(self, w: &mut Writer, s: &mut S) { - let handle = self.handle; - mem::forget(self); - handle.encode(w, s); + mem::ManuallyDrop::new(self).handle.encode(w, s); } } diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index a1f83029d272..800f3b0274fa 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -8,7 +8,7 @@ use crate::fmt; use crate::fs; use crate::io; use crate::marker::PhantomData; -use crate::mem::forget; +use crate::mem::ManuallyDrop; #[cfg(not(any(target_arch = "wasm32", target_env = "sgx", target_os = "hermit")))] use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; @@ -141,9 +141,7 @@ impl AsRawFd for OwnedFd { impl IntoRawFd for OwnedFd { #[inline] fn into_raw_fd(self) -> RawFd { - let fd = self.fd; - forget(self); - fd + ManuallyDrop::new(self).fd } } diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs index 19b4fe22093c..34fd745d4f9b 100644 --- a/library/std/src/os/solid/io.rs +++ b/library/std/src/os/solid/io.rs @@ -49,7 +49,7 @@ use crate::fmt; use crate::marker::PhantomData; -use crate::mem::forget; +use crate::mem::ManuallyDrop; use crate::net; use crate::sys; use crate::sys_common::{self, AsInner, FromInner, IntoInner}; @@ -149,9 +149,7 @@ impl AsRawFd for OwnedFd { impl IntoRawFd for OwnedFd { #[inline] fn into_raw_fd(self) -> RawFd { - let fd = self.fd; - forget(self); - fd + ManuallyDrop::new(self).fd } } diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index a9d1983dce61..9865386e753d 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -7,7 +7,7 @@ use crate::fmt; use crate::fs; use crate::io; use crate::marker::PhantomData; -use crate::mem::{forget, ManuallyDrop}; +use crate::mem::ManuallyDrop; use crate::ptr; use crate::sys; use crate::sys::cvt; @@ -319,9 +319,7 @@ impl AsRawHandle for OwnedHandle { impl IntoRawHandle for OwnedHandle { #[inline] fn into_raw_handle(self) -> RawHandle { - let handle = self.handle; - forget(self); - handle + ManuallyDrop::new(self).handle } } diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 6ffdf907c8ed..a0a0cd2d2a3f 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -6,8 +6,7 @@ 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::mem::{self, ManuallyDrop}; use crate::sys; #[cfg(not(target_vendor = "uwp"))] use crate::sys::cvt; @@ -191,9 +190,7 @@ impl AsRawSocket for OwnedSocket { impl IntoRawSocket for OwnedSocket { #[inline] fn into_raw_socket(self) -> RawSocket { - let socket = self.socket; - forget(self); - socket + ManuallyDrop::new(self).socket } } diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs index a244b953d2a4..3723f03081c1 100644 --- a/library/std/src/sys/pal/hermit/thread.rs +++ b/library/std/src/sys/pal/hermit/thread.rs @@ -3,7 +3,7 @@ use super::hermit_abi; use crate::ffi::CStr; use crate::io; -use crate::mem; +use crate::mem::ManuallyDrop; use crate::num::NonZero; use crate::ptr; use crate::time::Duration; @@ -90,9 +90,7 @@ impl Thread { #[inline] pub fn into_id(self) -> Tid { - let id = self.tid; - mem::forget(self); - id + ManuallyDrop::new(self).tid } } diff --git a/library/std/src/sys/pal/sgx/abi/tls/mod.rs b/library/std/src/sys/pal/sgx/abi/tls/mod.rs index 8a9ea4ac00df..bab59a3422d1 100644 --- a/library/std/src/sys/pal/sgx/abi/tls/mod.rs +++ b/library/std/src/sys/pal/sgx/abi/tls/mod.rs @@ -95,8 +95,8 @@ impl Tls { #[allow(unused)] pub unsafe fn activate_persistent(self: Box) { // FIXME: Needs safety information. See entry.S for `set_tls_ptr` definition. - unsafe { set_tls_ptr(core::ptr::addr_of!(*self) as _) }; - mem::forget(self); + let ptr = Box::into_raw(self).cast_const().cast::(); + unsafe { set_tls_ptr(ptr) }; } unsafe fn current<'a>() -> &'a Tls { diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs index f99cea360f1f..b625636752cc 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs @@ -5,7 +5,7 @@ use crate::cell::UnsafeCell; use crate::cmp; use crate::convert::TryInto; use crate::intrinsics; -use crate::mem; +use crate::mem::{self, ManuallyDrop}; use crate::ops::{CoerceUnsized, Deref, DerefMut, Index, IndexMut}; use crate::ptr::{self, NonNull}; use crate::slice; @@ -176,6 +176,7 @@ unsafe impl UserSafe for [T] { /// are used solely to indicate intent: a mutable reference is for writing to /// user memory, an immutable reference for reading from user memory. #[unstable(feature = "sgx_platform", issue = "56975")] +#[repr(transparent)] pub struct UserRef(UnsafeCell); /// An owned type in userspace memory. `User` is equivalent to `Box` in /// enclave memory. Access to the memory is only allowed by copying to avoid @@ -266,9 +267,7 @@ where /// Converts this value into a raw pointer. The value will no longer be /// automatically freed. pub fn into_raw(self) -> *mut T { - let ret = self.0; - mem::forget(self); - ret.as_ptr() as _ + ManuallyDrop::new(self).0.as_ptr() as _ } } diff --git a/library/std/src/sys/pal/sgx/fd.rs b/library/std/src/sys/pal/sgx/fd.rs index b3686d0e2832..c41b527cff79 100644 --- a/library/std/src/sys/pal/sgx/fd.rs +++ b/library/std/src/sys/pal/sgx/fd.rs @@ -2,7 +2,7 @@ use fortanix_sgx_abi::Fd; use super::abi::usercalls; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::mem; +use crate::mem::ManuallyDrop; use crate::sys::{AsInner, FromInner, IntoInner}; #[derive(Debug)] @@ -21,9 +21,7 @@ impl FileDesc { /// Extracts the actual file descriptor without closing it. pub fn into_raw(self) -> Fd { - let fd = self.fd; - mem::forget(self); - fd + ManuallyDrop::new(self).fd } pub fn read(&self, buf: &mut [u8]) -> io::Result { @@ -70,9 +68,7 @@ impl AsInner for FileDesc { impl IntoInner for FileDesc { fn into_inner(self) -> Fd { - let fd = self.fd; - mem::forget(self); - fd + ManuallyDrop::new(self).fd } } diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs index f4723b2ea46b..ef40eba4df2b 100644 --- a/library/std/src/sys/pal/teeos/thread.rs +++ b/library/std/src/sys/pal/teeos/thread.rs @@ -1,9 +1,7 @@ -use core::convert::TryInto; - use crate::cmp; use crate::ffi::CStr; use crate::io; -use crate::mem; +use crate::mem::{self, ManuallyDrop}; use crate::num::NonZero; use crate::ptr; use crate::sys::os; @@ -113,11 +111,9 @@ impl Thread { /// must join, because no pthread_detach supported pub fn join(self) { - unsafe { - let ret = libc::pthread_join(self.id, ptr::null_mut()); - mem::forget(self); - assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret)); - } + let id = self.into_id(); + let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; + assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret)); } pub fn id(&self) -> libc::pthread_t { @@ -125,9 +121,7 @@ impl Thread { } pub fn into_id(self) -> libc::pthread_t { - let id = self.id; - mem::forget(self); - id + ManuallyDrop::new(self).id } } diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 619f4e4121e7..483697b8597f 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -1,7 +1,7 @@ use crate::cmp; use crate::ffi::CStr; use crate::io; -use crate::mem; +use crate::mem::{self, ManuallyDrop}; use crate::num::NonZero; use crate::ptr; use crate::sys::{os, stack_overflow}; @@ -268,11 +268,9 @@ impl Thread { } pub fn join(self) { - unsafe { - let ret = libc::pthread_join(self.id, ptr::null_mut()); - mem::forget(self); - assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret)); - } + let id = self.into_id(); + let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; + assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret)); } pub fn id(&self) -> libc::pthread_t { @@ -280,9 +278,7 @@ impl Thread { } pub fn into_id(self) -> libc::pthread_t { - let id = self.id; - mem::forget(self); - id + ManuallyDrop::new(self).id } } diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs index 975eef2451f4..2a3a39aafa70 100644 --- a/library/std/src/sys/pal/wasi/thread.rs +++ b/library/std/src/sys/pal/wasi/thread.rs @@ -172,12 +172,10 @@ impl Thread { pub fn join(self) { cfg_if::cfg_if! { if #[cfg(target_feature = "atomics")] { - unsafe { - let ret = libc::pthread_join(self.id, ptr::null_mut()); - mem::forget(self); - if ret != 0 { - rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret)); - } + let id = mem::ManuallyDrop::new(self).id; + let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; + if ret != 0 { + rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret)); } } else { self.0 diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index c8ee365392f8..73bf56237082 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -165,7 +165,7 @@ use crate::ffi::{CStr, CString}; use crate::fmt; use crate::io; use crate::marker::PhantomData; -use crate::mem::{self, forget}; +use crate::mem::{self, forget, ManuallyDrop}; use crate::num::NonZero; use crate::panic; use crate::panicking; @@ -514,11 +514,10 @@ impl Builder { MaybeDangling(mem::MaybeUninit::new(x)) } fn into_inner(self) -> T { - // SAFETY: we are always initialized. - let ret = unsafe { self.0.assume_init_read() }; // Make sure we don't drop. - mem::forget(self); - ret + let this = ManuallyDrop::new(self); + // SAFETY: we are always initialized. + unsafe { this.0.assume_init_read() } } } impl Drop for MaybeDangling { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr index 987d0fc4c2d0..079c1729b600 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr @@ -10,7 +10,7 @@ LL | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _ error: deadlock: the evaluated program deadlocked --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC | -LL | let ret = libc::pthread_join(self.id, ptr::null_mut()); +LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ the evaluated program deadlocked | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr index bc9b15f293ef..d03c6402d64f 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr @@ -10,7 +10,7 @@ LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu error: deadlock: the evaluated program deadlocked --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC | -LL | let ret = libc::pthread_join(self.id, ptr::null_mut()); +LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ the evaluated program deadlocked | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr index 66c142bbc5c8..73c5e77a1bce 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr @@ -10,7 +10,7 @@ LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu error: deadlock: the evaluated program deadlocked --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC | -LL | let ret = libc::pthread_join(self.id, ptr::null_mut()); +LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ the evaluated program deadlocked | = note: BACKTRACE: From 0d508bb0cd681bf15f7861670cd38a1b352d2e40 Mon Sep 17 00:00:00 2001 From: Mohammad Omidvar Date: Mon, 15 Jul 2024 19:54:47 +0000 Subject: [PATCH 142/734] Introduce and provide a hook for `should_codegen_locally` --- compiler/rustc_middle/src/hooks/mod.rs | 4 ++++ compiler/rustc_monomorphize/src/collector.rs | 15 +++++++++++++-- compiler/rustc_monomorphize/src/lib.rs | 3 ++- compiler/rustc_monomorphize/src/partitioning.rs | 4 +++- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index bf10a71dbaec..75dc685a16ae 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -103,6 +103,10 @@ declare_hooks! { /// Create a list-like THIR representation for debugging. hook thir_flat(key: LocalDefId) -> String; + + /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we + /// can just link to the upstream crate and therefore don't need a mono item. + hook should_codegen_locally(instance: crate::ty::Instance<'tcx>) -> bool; } #[cold] diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index bfd505c06726..27d27885ea8d 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -228,6 +228,7 @@ use rustc_middle::ty::{ self, AssocKind, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, VtblEntry, }; +use rustc_middle::util::Providers; use rustc_middle::{bug, span_bug}; use rustc_session::config::EntryFnType; use rustc_session::Limit; @@ -930,7 +931,7 @@ fn visit_instance_use<'tcx>( /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we /// can just link to the upstream crate and therefore don't need a mono item. -pub(crate) fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool { +pub(crate) fn should_codegen_locally_hook<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -> bool { let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() else { return true; }; @@ -946,7 +947,7 @@ pub(crate) fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance } if tcx.is_reachable_non_generic(def_id) - || instance.polymorphize(tcx).upstream_monomorphization(tcx).is_some() + || instance.polymorphize(*tcx).upstream_monomorphization(*tcx).is_some() { // We can link to the item in question, no instance needed in this crate. return false; @@ -967,6 +968,12 @@ pub(crate) fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance true } +/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we +/// can just link to the upstream crate and therefore don't need a mono item. +pub(crate) fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool { + tcx.should_codegen_locally(instance) +} + /// For a given pair of source and target type that occur in an unsizing coercion, /// this function finds the pair of types that determines the vtable linking /// them. @@ -1613,3 +1620,7 @@ pub(crate) fn collect_crate_mono_items<'tcx>( (mono_items, state.usage_map.into_inner()) } + +pub fn provide(providers: &mut Providers) { + providers.hooks.should_codegen_locally = should_codegen_locally_hook; +} diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index aa3b4cd5b678..d169f0860663 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -5,12 +5,13 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::bug; -use rustc_middle::query::{Providers, TyCtxtAt}; +use rustc_middle::query::TyCtxtAt; use rustc_middle::traits; use rustc_middle::ty::adjustment::CustomCoerceUnsized; use rustc_middle::ty::Instance; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{self, Ty}; +use rustc_middle::util::Providers; use rustc_span::def_id::DefId; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::ErrorGuaranteed; diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 9a7c488833a1..8c7c5e0074ab 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -112,9 +112,9 @@ use rustc_middle::mir::mono::{ CodegenUnit, CodegenUnitNameBuilder, InstantiationMode, Linkage, MonoItem, MonoItemData, Visibility, }; -use rustc_middle::query::Providers; use rustc_middle::ty::print::{characteristic_def_id_of_type, with_no_trimmed_paths}; use rustc_middle::ty::{self, visit::TypeVisitableExt, InstanceKind, TyCtxt}; +use rustc_middle::util::Providers; use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath}; use rustc_session::CodegenUnits; use rustc_span::symbol::Symbol; @@ -1314,4 +1314,6 @@ pub fn provide(providers: &mut Providers) { .find(|cgu| cgu.name() == name) .unwrap_or_else(|| panic!("failed to find cgu with name {name:?}")) }; + + collector::provide(providers); } From 14430e66be02266ca59bdddd38d88a27f2e02917 Mon Sep 17 00:00:00 2001 From: Mohammad Omidvar Date: Mon, 15 Jul 2024 19:58:44 +0000 Subject: [PATCH 143/734] Use the hook on tcx instead of the local function --- compiler/rustc_monomorphize/src/collector.rs | 40 +++++++++----------- compiler/rustc_monomorphize/src/lib.rs | 4 +- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 27d27885ea8d..3655a677ba0a 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -400,7 +400,7 @@ fn collect_items_rec<'tcx>( let instance = Instance::mono(tcx, def_id); // Sanity check whether this ended up being collected accidentally - debug_assert!(should_codegen_locally(tcx, instance)); + debug_assert!(tcx.should_codegen_locally(instance)); let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { bug!() }; // Nested statics have no type. @@ -432,7 +432,7 @@ fn collect_items_rec<'tcx>( } MonoItem::Fn(instance) => { // Sanity check whether this ended up being collected accidentally - debug_assert!(should_codegen_locally(tcx, instance)); + debug_assert!(tcx.should_codegen_locally(instance)); // Keep track of the monomorphization recursion depth recursion_depth_reset = Some(check_recursion_limit( @@ -476,7 +476,7 @@ fn collect_items_rec<'tcx>( } hir::InlineAsmOperand::SymStatic { path: _, def_id } => { let instance = Instance::mono(tcx, *def_id); - if should_codegen_locally(tcx, instance) { + if tcx.should_codegen_locally(instance) { trace!("collecting static {:?}", def_id); used_items.push(dummy_spanned(MonoItem::Static(*def_id))); } @@ -713,7 +713,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { if let ty::Closure(def_id, args) = *source_ty.kind() { let instance = Instance::resolve_closure(self.tcx, def_id, args, ty::ClosureKind::FnOnce); - if should_codegen_locally(self.tcx, instance) { + if self.tcx.should_codegen_locally(instance) { self.used_items.push(create_fn_mono_item(self.tcx, instance, span)); } } else { @@ -723,7 +723,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { mir::Rvalue::ThreadLocalRef(def_id) => { assert!(self.tcx.is_thread_local_static(def_id)); let instance = Instance::mono(self.tcx, def_id); - if should_codegen_locally(self.tcx, instance) { + if self.tcx.should_codegen_locally(instance) { trace!("collecting thread-local static {:?}", def_id); self.used_items.push(respan(span, MonoItem::Static(def_id))); } @@ -750,7 +750,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { let tcx = self.tcx; let push_mono_lang_item = |this: &mut Self, lang_item: LangItem| { let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, Some(source))); - if should_codegen_locally(tcx, instance) { + if tcx.should_codegen_locally(instance) { this.used_items.push(create_fn_mono_item(tcx, instance, source)); } }; @@ -784,7 +784,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { } mir::InlineAsmOperand::SymStatic { def_id } => { let instance = Instance::mono(self.tcx, def_id); - if should_codegen_locally(self.tcx, instance) { + if self.tcx.should_codegen_locally(instance) { trace!("collecting asm sym static {:?}", def_id); self.used_items.push(respan(source, MonoItem::Static(def_id))); } @@ -874,7 +874,7 @@ fn visit_instance_use<'tcx>( output: &mut MonoItems<'tcx>, ) { debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call); - if !should_codegen_locally(tcx, instance) { + if !tcx.should_codegen_locally(instance) { return; } if let ty::InstanceKind::Intrinsic(def_id) = instance.def { @@ -886,13 +886,13 @@ fn visit_instance_use<'tcx>( // codegen a call to that function without generating code for the function itself. let def_id = tcx.require_lang_item(LangItem::PanicNounwind, None); let panic_instance = Instance::mono(tcx, def_id); - if should_codegen_locally(tcx, panic_instance) { + if tcx.should_codegen_locally(panic_instance) { output.push(create_fn_mono_item(tcx, panic_instance, source)); } } else if tcx.has_attr(def_id, sym::rustc_intrinsic) { // Codegen the fallback body of intrinsics with fallback bodies let instance = ty::Instance::new(def_id, instance.args); - if should_codegen_locally(tcx, instance) { + if tcx.should_codegen_locally(instance) { output.push(create_fn_mono_item(tcx, instance, source)); } } @@ -931,7 +931,7 @@ fn visit_instance_use<'tcx>( /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we /// can just link to the upstream crate and therefore don't need a mono item. -pub(crate) fn should_codegen_locally_hook<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -> bool { +fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -> bool { let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() else { return true; }; @@ -968,12 +968,6 @@ pub(crate) fn should_codegen_locally_hook<'tcx>(tcx: TyCtxtAt<'tcx>, instance: I true } -/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we -/// can just link to the upstream crate and therefore don't need a mono item. -pub(crate) fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool { - tcx.should_codegen_locally(instance) -} - /// For a given pair of source and target type that occur in an unsizing coercion, /// this function finds the pair of types that determines the vtable linking /// them. @@ -1134,7 +1128,7 @@ fn create_mono_items_for_vtable_methods<'tcx>( None } VtblEntry::Method(instance) => { - Some(*instance).filter(|instance| should_codegen_locally(tcx, *instance)) + Some(*instance).filter(|instance| tcx.should_codegen_locally(*instance)) } }) .map(|item| create_fn_mono_item(tcx, item, source)); @@ -1151,7 +1145,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt GlobalAlloc::Static(def_id) => { assert!(!tcx.is_thread_local_static(def_id)); let instance = Instance::mono(tcx, def_id); - if should_codegen_locally(tcx, instance) { + if tcx.should_codegen_locally(instance) { trace!("collecting static {:?}", def_id); output.push(dummy_spanned(MonoItem::Static(def_id))); } @@ -1169,7 +1163,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt } } GlobalAlloc::Function { instance, .. } => { - if should_codegen_locally(tcx, instance) { + if tcx.should_codegen_locally(instance) { trace!("collecting {:?} with {:#?}", alloc_id, instance); output.push(create_fn_mono_item(tcx, instance, DUMMY_SP)); } @@ -1291,7 +1285,7 @@ fn visit_mentioned_item<'tcx>( if let ty::Closure(def_id, args) = *source_ty.kind() { let instance = Instance::resolve_closure(tcx, def_id, args, ty::ClosureKind::FnOnce); - if should_codegen_locally(tcx, instance) { + if tcx.should_codegen_locally(instance) { output.push(create_fn_mono_item(tcx, instance, span)); } } else { @@ -1564,7 +1558,7 @@ fn create_mono_items_for_default_impls<'tcx>( let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args, DUMMY_SP); let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP); - if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, instance) { + if mono_item.node.is_instantiable(tcx) && tcx.should_codegen_locally(instance) { output.push(mono_item); } } @@ -1622,5 +1616,5 @@ pub(crate) fn collect_crate_mono_items<'tcx>( } pub fn provide(providers: &mut Providers) { - providers.hooks.should_codegen_locally = should_codegen_locally_hook; + providers.hooks.should_codegen_locally = should_codegen_locally; } diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index d169f0860663..e5a63a98ff47 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -22,8 +22,6 @@ mod partitioning; mod polymorphize; mod util; -use collector::should_codegen_locally; - rustc_fluent_macro::fluent_messages! { "../messages.ftl" } fn custom_coerce_unsize_info<'tcx>( @@ -73,7 +71,7 @@ pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>( !def_id.is_local() && tcx.is_compiler_builtins(LOCAL_CRATE) && !is_llvm_intrinsic(tcx, def_id) - && !should_codegen_locally(tcx, instance) + && !tcx.should_codegen_locally(instance) } pub fn provide(providers: &mut Providers) { From c370bf44d84a2e83617712de81ac602f59acc63a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 15 Jul 2024 12:11:49 -0700 Subject: [PATCH 144/734] Don't use stage0 compiler for wasm-component-ld Switch it to using a just-built standard library which enables it to be cross compiled. Additionally allow it access to `min_specialization` which `ahash`, a dependency, wants. --- src/bootstrap/src/core/build_steps/compile.rs | 2 +- src/bootstrap/src/core/build_steps/tool.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 5650fea1b812..175ef52b33fc 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1837,7 +1837,7 @@ impl Step for Assemble { // `wasm32-wasip2` target of Rust. let wasm_component_ld_exe = builder.ensure(crate::core::build_steps::tool::WasmComponentLd { - compiler: build_compiler.with_stage(0), + compiler: build_compiler, target: target_compiler.host, }); builder.copy_link( diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index d62166d8f047..7bc410b9e887 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -337,7 +337,7 @@ bootstrap_tool!( RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = "test"; CoverageDump, "src/tools/coverage-dump", "coverage-dump"; RustcPerfWrapper, "src/tools/rustc-perf-wrapper", "rustc-perf-wrapper"; - WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld"; + WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld", is_unstable_tool = true, allow_features = "min_specialization"; ); #[derive(Debug, Clone, Hash, PartialEq, Eq)] From 489a77831ce61e3e3679f4fbcf93be42d3922e52 Mon Sep 17 00:00:00 2001 From: apoisternex Date: Sun, 14 Jul 2024 18:36:10 -0300 Subject: [PATCH 145/734] fix [`excessive_precision`] suggestions on float literal written in scientific notation fixes: #12954 changelog: fix [`excessive_precision`] suggestions on float literal written in scientific notation --- clippy_utils/src/numeric_literal.rs | 2 ++ tests/ui/excessive_precision.fixed | 4 ++++ tests/ui/excessive_precision.rs | 4 ++++ tests/ui/excessive_precision.stderr | 8 +++++++- 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/clippy_utils/src/numeric_literal.rs b/clippy_utils/src/numeric_literal.rs index bbe4149fe2ab..c5a34160e3da 100644 --- a/clippy_utils/src/numeric_literal.rs +++ b/clippy_utils/src/numeric_literal.rs @@ -164,6 +164,8 @@ impl<'a> NumericLiteral<'a> { if !exponent.is_empty() && exponent != "0" { output.push_str(separator); Self::group_digits(&mut output, exponent, group_size, true, false); + } else if exponent == "0" && self.fraction.is_none() && self.suffix.is_none() { + output.push_str(".0"); } } diff --git a/tests/ui/excessive_precision.fixed b/tests/ui/excessive_precision.fixed index cc5531035309..372f64f7d99e 100644 --- a/tests/ui/excessive_precision.fixed +++ b/tests/ui/excessive_precision.fixed @@ -78,4 +78,8 @@ fn main() { const NEG_INF1: f32 = -1.0e+33f32; const NEG_INF2: f64 = -1.0e+3300f64; const NEG_INF3: f32 = -3.40282357e+38_f32; + + // issue #12954 + const _: f64 = 3.0; + const _: f64 = 3.0000000000000000; } diff --git a/tests/ui/excessive_precision.rs b/tests/ui/excessive_precision.rs index fff986a8296c..1e40efbf2452 100644 --- a/tests/ui/excessive_precision.rs +++ b/tests/ui/excessive_precision.rs @@ -78,4 +78,8 @@ fn main() { const NEG_INF1: f32 = -1.0e+33f32; const NEG_INF2: f64 = -1.0e+3300f64; const NEG_INF3: f32 = -3.40282357e+38_f32; + + // issue #12954 + const _: f64 = 3.0000000000000000e+00; + const _: f64 = 3.0000000000000000; } diff --git a/tests/ui/excessive_precision.stderr b/tests/ui/excessive_precision.stderr index 22dd96e53bdb..6d8e166a649d 100644 --- a/tests/ui/excessive_precision.stderr +++ b/tests/ui/excessive_precision.stderr @@ -91,5 +91,11 @@ error: float has excessive precision LL | let _ = 1.000_000_000_000_001e-324_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0_f64` -error: aborting due to 15 previous errors +error: float has excessive precision + --> tests/ui/excessive_precision.rs:83:20 + | +LL | const _: f64 = 3.0000000000000000e+00; + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `3.0` + +error: aborting due to 16 previous errors From 1aad89d11ca9e52fa0442c75bb3d9dee9635cbb7 Mon Sep 17 00:00:00 2001 From: Charles Celerier Date: Wed, 10 Jul 2024 03:22:44 +0000 Subject: [PATCH 146/734] Add match arm for Fuchsia status code upon an abort in a test This change adds ZX_TASK_RETCODE_EXCEPTION_KILL as an expected status code upon an abort in a test on Fuchsia. Tests fixes #127539 --- library/test/src/test_result.rs | 11 +++++++++++ .../test-attrs/test-panic-abort-nocapture.run.stderr | 4 ++-- tests/ui/test-attrs/test-panic-abort.run.stdout | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/library/test/src/test_result.rs b/library/test/src/test_result.rs index bb32c70d6631..cecf747f5311 100644 --- a/library/test/src/test_result.rs +++ b/library/test/src/test_result.rs @@ -21,6 +21,14 @@ pub const TR_OK: i32 = 50; #[cfg(windows)] const STATUS_ABORTED: i32 = 0xC0000409u32 as i32; +// On Zircon (the Fuchsia kernel), an abort from userspace calls the +// LLVM implementation of __builtin_trap(), e.g., ud2 on x86, which +// raises a kernel exception. If a userspace process does not +// otherwise arrange exception handling, the kernel kills the process +// with this return code. +#[cfg(target_os = "fuchsia")] +const ZX_TASK_RETCODE_EXCEPTION_KILL: i32 = -1028; + #[derive(Debug, Clone, PartialEq)] pub enum TestResult { TrOk, @@ -105,6 +113,9 @@ pub fn get_result_from_exit_code( } None => unreachable!("status.code() returned None but status.signal() was None"), }, + // Upon an abort, Fuchsia returns the status code ZX_TASK_RETCODE_EXCEPTION_KILL. + #[cfg(target_os = "fuchsia")] + Some(ZX_TASK_RETCODE_EXCEPTION_KILL) => TestResult::TrFailed, #[cfg(not(unix))] None => TestResult::TrFailedMsg(format!("unknown return code")), #[cfg(any(windows, unix))] diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr index 4c94518d4d19..16001b3eecd4 100644 --- a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr +++ b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr @@ -1,9 +1,9 @@ -thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:35:5: +thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:34:5: assertion `left == right` failed left: 2 right: 4 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:29:5: +thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:28:5: assertion `left == right` failed left: 2 right: 4 diff --git a/tests/ui/test-attrs/test-panic-abort.run.stdout b/tests/ui/test-attrs/test-panic-abort.run.stdout index 25105f38fcf7..f5d14e77da96 100644 --- a/tests/ui/test-attrs/test-panic-abort.run.stdout +++ b/tests/ui/test-attrs/test-panic-abort.run.stdout @@ -17,7 +17,7 @@ hello, world testing123 ---- it_fails stderr ---- testing321 -thread 'main' panicked at $DIR/test-panic-abort.rs:40:5: +thread 'main' panicked at $DIR/test-panic-abort.rs:39:5: assertion `left == right` failed left: 2 right: 5 From deb8ebb39b1fa8ab1436bf224df434273a6c58c6 Mon Sep 17 00:00:00 2001 From: Charles Celerier Date: Wed, 10 Jul 2024 03:43:15 +0000 Subject: [PATCH 147/734] Update name of Windows abort constant to match platform documentation --- library/test/src/test_result.rs | 4 ++-- tests/ui/test-attrs/test-panic-abort-nocapture.rs | 1 - tests/ui/test-attrs/test-panic-abort.rs | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/library/test/src/test_result.rs b/library/test/src/test_result.rs index cecf747f5311..98c54f038da6 100644 --- a/library/test/src/test_result.rs +++ b/library/test/src/test_result.rs @@ -19,7 +19,7 @@ pub const TR_OK: i32 = 50; // On Windows we use __fastfail to abort, which is documented to use this // exception code. #[cfg(windows)] -const STATUS_ABORTED: i32 = 0xC0000409u32 as i32; +const STATUS_FAIL_FAST_EXCEPTION: i32 = 0xC0000409u32 as i32; // On Zircon (the Fuchsia kernel), an abort from userspace calls the // LLVM implementation of __builtin_trap(), e.g., ud2 on x86, which @@ -104,7 +104,7 @@ pub fn get_result_from_exit_code( let result = match status.code() { Some(TR_OK) => TestResult::TrOk, #[cfg(windows)] - Some(STATUS_ABORTED) => TestResult::TrFailed, + Some(STATUS_FAIL_FAST_EXCEPTION) => TestResult::TrFailed, #[cfg(unix)] None => match status.signal() { Some(libc::SIGABRT) => TestResult::TrFailed, diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.rs b/tests/ui/test-attrs/test-panic-abort-nocapture.rs index c2c3d6d547d6..f3485d9c1fa9 100644 --- a/tests/ui/test-attrs/test-panic-abort-nocapture.rs +++ b/tests/ui/test-attrs/test-panic-abort-nocapture.rs @@ -10,7 +10,6 @@ //@ ignore-wasm no panic or subprocess support //@ ignore-emscripten no panic or subprocess support //@ ignore-sgx no subprocess support -//@ ignore-fuchsia code returned as ZX_TASK_RETCODE_EXCEPTION_KILL, FIXME (#127539) #![cfg(test)] diff --git a/tests/ui/test-attrs/test-panic-abort.rs b/tests/ui/test-attrs/test-panic-abort.rs index 0c44acaffd77..84740161a708 100644 --- a/tests/ui/test-attrs/test-panic-abort.rs +++ b/tests/ui/test-attrs/test-panic-abort.rs @@ -10,7 +10,6 @@ //@ ignore-wasm no panic or subprocess support //@ ignore-emscripten no panic or subprocess support //@ ignore-sgx no subprocess support -//@ ignore-fuchsia code returned as ZX_TASK_RETCODE_EXCEPTION_KILL, FIXME (#127539) #![cfg(test)] #![feature(test)] From 9b80250abb8ebf9f49f51593aee6a7308e0ac3b4 Mon Sep 17 00:00:00 2001 From: Mohammad Omidvar Date: Mon, 15 Jul 2024 23:43:52 +0000 Subject: [PATCH 148/734] Move compiler_builtin check to the use case --- .../rustc_codegen_cranelift/src/abi/mod.rs | 2 +- compiler/rustc_codegen_cranelift/src/base.rs | 2 +- compiler/rustc_codegen_cranelift/src/lib.rs | 1 - compiler/rustc_codegen_ssa/src/base.rs | 28 ++++++++++++++++ compiler/rustc_codegen_ssa/src/mir/block.rs | 3 +- compiler/rustc_monomorphize/src/lib.rs | 32 ------------------- 6 files changed, 31 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index fa0de6f9de5e..698981ae1536 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -10,12 +10,12 @@ use std::mem; use cranelift_codegen::ir::{ArgumentPurpose, SigRef}; use cranelift_codegen::isa::CallConv; use cranelift_module::ModuleError; +use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::TypeVisitableExt; -use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_session::Session; use rustc_span::source_map::Spanned; use rustc_target::abi::call::{Conv, FnAbi, PassMode}; diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 5adbbb09ac85..9bc7b57c5374 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -5,13 +5,13 @@ use cranelift_codegen::CodegenError; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use cranelift_module::ModuleError; use rustc_ast::InlineAsmOptions; +use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::TypeVisitableExt; -use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization; use crate::constant::ConstantCx; use crate::debuginfo::{FunctionDebugContext, TypeDebugContext}; diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 192e6c91ea38..8d3d5ac98e1e 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -24,7 +24,6 @@ extern crate rustc_hir; extern crate rustc_incremental; extern crate rustc_index; extern crate rustc_metadata; -extern crate rustc_monomorphize; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 137f14fe706c..399ac4858505 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -806,6 +806,34 @@ pub fn codegen_crate( ongoing_codegen } +/// Returns whether a call from the current crate to the [`Instance`] would produce a call +/// from `compiler_builtins` to a symbol the linker must resolve. +/// +/// Such calls from `compiler_bultins` are effectively impossible for the linker to handle. Some +/// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is +/// not guaranteed. So we used this function in codegen backends to ensure we do not generate any +/// unlinkable calls. +/// +/// Note that calls to LLVM intrinsics are uniquely okay because they won't make it to the linker. +pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, +) -> bool { + fn is_llvm_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + if let Some(name) = tcx.codegen_fn_attrs(def_id).link_name { + name.as_str().starts_with("llvm.") + } else { + false + } + } + + let def_id = instance.def_id(); + !def_id.is_local() + && tcx.is_compiler_builtins(LOCAL_CRATE) + && !is_llvm_intrinsic(tcx, def_id) + && !tcx.should_codegen_locally(instance) +} + impl CrateInfo { pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo { let crate_types = tcx.crate_types().to_vec(); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 6a5525dc2b34..c9c8f02c491b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -3,7 +3,7 @@ use super::operand::OperandValue::{Immediate, Pair, Ref, ZeroSized}; use super::place::{PlaceRef, PlaceValue}; use super::{CachedLlbb, FunctionCx, LocalRef}; -use crate::base; +use crate::base::{self, is_call_from_compiler_builtins_to_upstream_monomorphization}; use crate::common::{self, IntPredicate}; use crate::errors::CompilerBuiltinsCannotCall; use crate::meth; @@ -18,7 +18,6 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, span_bug}; -use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_session::config::OptLevel; use rustc_span::{source_map::Spanned, sym, Span}; use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg}; diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index e5a63a98ff47..fc6e8e0d14fd 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -8,12 +8,8 @@ use rustc_middle::bug; use rustc_middle::query::TyCtxtAt; use rustc_middle::traits; use rustc_middle::ty::adjustment::CustomCoerceUnsized; -use rustc_middle::ty::Instance; -use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{self, Ty}; use rustc_middle::util::Providers; -use rustc_span::def_id::DefId; -use rustc_span::def_id::LOCAL_CRATE; use rustc_span::ErrorGuaranteed; mod collector; @@ -46,34 +42,6 @@ fn custom_coerce_unsize_info<'tcx>( } } -/// Returns whether a call from the current crate to the [`Instance`] would produce a call -/// from `compiler_builtins` to a symbol the linker must resolve. -/// -/// Such calls from `compiler_bultins` are effectively impossible for the linker to handle. Some -/// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is -/// not guaranteed. So we used this function in codegen backends to ensure we do not generate any -/// unlinkable calls. -/// -/// Note that calls to LLVM intrinsics are uniquely okay because they won't make it to the linker. -pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>( - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, -) -> bool { - fn is_llvm_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - if let Some(name) = tcx.codegen_fn_attrs(def_id).link_name { - name.as_str().starts_with("llvm.") - } else { - false - } - } - - let def_id = instance.def_id(); - !def_id.is_local() - && tcx.is_compiler_builtins(LOCAL_CRATE) - && !is_llvm_intrinsic(tcx, def_id) - && !tcx.should_codegen_locally(instance) -} - pub fn provide(providers: &mut Providers) { partitioning::provide(providers); polymorphize::provide(providers); From e86fbcfd7048dba4eb9b6461069f476d273a3b64 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 8 Jul 2024 21:03:08 -0400 Subject: [PATCH 149/734] Move rustc_infer::infer::error_reporting to rustc_infer::error_reporting::infer --- .../src/diagnostics/bound_region_errors.rs | 2 +- .../src/diagnostics/region_errors.rs | 4 +- compiler/rustc_hir_analysis/src/check/mod.rs | 2 +- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 10 +- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 4 +- compiler/rustc_hir_typeck/src/method/probe.rs | 4 +- compiler/rustc_hir_typeck/src/writeback.rs | 4 +- .../infer}/mod.rs | 45 +- .../nice_region_error/different_lifetimes.rs | 11 +- .../nice_region_error/find_anon_type.rs | 0 .../mismatched_static_lifetime.rs | 4 +- .../infer}/nice_region_error/mod.rs | 6 +- .../nice_region_error/named_anon_conflict.rs | 8 +- .../nice_region_error/placeholder_error.rs | 4 +- .../nice_region_error/placeholder_relation.rs | 9 +- .../nice_region_error/static_impl_trait.rs | 4 +- .../trait_impl_difference.rs | 4 +- .../infer}/nice_region_error/util.rs | 6 +- .../src/error_reporting/infer/note.rs | 421 ++++++++++++++++++ .../infer}/note_and_explain.rs | 0 .../infer}/region.rs | 2 +- .../infer}/sub_relations.rs | 0 .../infer}/suggest.rs | 2 +- .../rustc_infer/src/error_reporting/mod.rs | 1 + compiler/rustc_infer/src/errors/mod.rs | 7 +- .../src/errors/note_and_explain.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 5 +- .../{error_reporting => }/need_type_info.rs | 2 +- compiler/rustc_infer/src/lib.rs | 1 + .../src/error_reporting/traits/ambiguity.rs | 3 +- .../traits/fulfillment_errors.rs | 4 +- .../src/error_reporting/traits/mod.rs | 2 +- .../traits/on_unimplemented.rs | 2 +- .../src/error_reporting/traits/overflow.rs | 2 +- .../src/error_reporting/traits/suggestions.rs | 2 +- .../clippy/tests/ui/track-diagnostics.stderr | 2 +- tests/rustdoc-ui/track-diagnostics.stderr | 2 +- 38 files changed, 508 insertions(+), 87 deletions(-) rename compiler/rustc_infer/src/{infer/error_reporting => error_reporting/infer}/mod.rs (99%) rename compiler/rustc_infer/src/{infer/error_reporting => error_reporting/infer}/nice_region_error/different_lifetimes.rs (94%) rename compiler/rustc_infer/src/{infer/error_reporting => error_reporting/infer}/nice_region_error/find_anon_type.rs (100%) rename compiler/rustc_infer/src/{infer/error_reporting => error_reporting/infer}/nice_region_error/mismatched_static_lifetime.rs (97%) rename compiler/rustc_infer/src/{infer/error_reporting => error_reporting/infer}/nice_region_error/mod.rs (94%) rename compiler/rustc_infer/src/{infer/error_reporting => error_reporting/infer}/nice_region_error/named_anon_conflict.rs (94%) rename compiler/rustc_infer/src/{infer/error_reporting => error_reporting/infer}/nice_region_error/placeholder_error.rs (99%) rename compiler/rustc_infer/src/{infer/error_reporting => error_reporting/infer}/nice_region_error/placeholder_relation.rs (94%) rename compiler/rustc_infer/src/{infer/error_reporting => error_reporting/infer}/nice_region_error/static_impl_trait.rs (99%) rename compiler/rustc_infer/src/{infer/error_reporting => error_reporting/infer}/nice_region_error/trait_impl_difference.rs (97%) rename compiler/rustc_infer/src/{infer/error_reporting => error_reporting/infer}/nice_region_error/util.rs (97%) create mode 100644 compiler/rustc_infer/src/error_reporting/infer/note.rs rename compiler/rustc_infer/src/{infer/error_reporting => error_reporting/infer}/note_and_explain.rs (100%) rename compiler/rustc_infer/src/{infer/error_reporting => error_reporting/infer}/region.rs (99%) rename compiler/rustc_infer/src/{infer/error_reporting => error_reporting/infer}/sub_relations.rs (100%) rename compiler/rustc_infer/src/{infer/error_reporting => error_reporting/infer}/suggest.rs (99%) create mode 100644 compiler/rustc_infer/src/error_reporting/mod.rs rename compiler/rustc_infer/src/infer/{error_reporting => }/need_type_info.rs (99%) diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 8bf3e670ff22..4cd0d9cb294f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -1,7 +1,7 @@ use rustc_errors::Diag; use rustc_hir::def_id::LocalDefId; +use rustc_infer::error_reporting::infer::nice_region_error::NiceRegionError; use rustc_infer::infer::canonical::Canonical; -use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError; use rustc_infer::infer::region_constraints::Constraint; use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_infer::infer::RegionVariableOrigin; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 55147ee337fd..6cf797b4761b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -10,11 +10,11 @@ use rustc_hir::GenericBound::Trait; use rustc_hir::QPath::Resolved; use rustc_hir::WherePredicate::BoundPredicate; use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate}; -use rustc_infer::infer::error_reporting::nice_region_error::{ +use rustc_infer::error_reporting::infer::nice_region_error::{ self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params, HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor, }; -use rustc_infer::infer::error_reporting::region::unexpected_hidden_region_diagnostic; +use rustc_infer::error_reporting::infer::region::unexpected_hidden_region_diagnostic; use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound}; use rustc_middle::bug; use rustc_middle::hir::place::PlaceBase; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 6a36938dd1d5..9fef31acef8a 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -82,7 +82,7 @@ use rustc_errors::{pluralize, struct_span_code_err, Diag}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_index::bit_set::BitSet; -use rustc_infer::infer::error_reporting::ObligationCauseExt as _; +use rustc_infer::error_reporting::infer::ObligationCauseExt as _; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, TyCtxtInferExt as _}; use rustc_infer::traits::ObligationCause; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index ea9567f4e3dc..6da3f1dd1141 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -19,7 +19,7 @@ use rustc_hir_analysis::hir_ty_lowering::{ GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason, }; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; -use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; +use rustc_infer::infer::need_type_info::TypeAnnotationNeeded; use rustc_infer::infer::{DefineOpaqueTypes, InferResult}; use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; @@ -1519,7 +1519,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { let e = self.tainted_by_errors().unwrap_or_else(|| { self.err_ctxt() - .emit_inference_failure_err(self.body_id, sp, ty.into(), E0282, true) + .emit_inference_failure_err( + self.body_id, + sp, + ty.into(), + TypeAnnotationNeeded::E0282, + true, + ) .emit() }); let err = Ty::new_error(self.tcx, e); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 9c5880912393..a3e95480b3d7 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -29,7 +29,7 @@ use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt; use rustc_hir_analysis::check::potentially_plural_count; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_index::IndexVec; -use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt}; +use rustc_infer::error_reporting::infer::{FailureCode, ObligationCauseExt}; use rustc_infer::infer::TypeTrace; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_middle::ty::adjustment::AllowTwoPhase; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index b5796fbd48a8..3fe87c03e743 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -15,9 +15,9 @@ use hir::def_id::CRATE_DEF_ID; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason}; +use rustc_infer::error_reporting::infer::sub_relations::SubRelations; +use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_infer::infer; -use rustc_infer::infer::error_reporting::sub_relations::SubRelations; -use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::Session; use rustc_span::symbol::Ident; diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 6a7af5510e07..71b41e285377 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -12,7 +12,7 @@ use rustc_hir::HirId; use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_infer::infer::canonical::OriginalQueryValues; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; -use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; +use rustc_infer::infer::need_type_info::TypeAnnotationNeeded; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_infer::traits::ObligationCauseCode; @@ -441,7 +441,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.body_id, span, ty.into(), - E0282, + TypeAnnotationNeeded::E0282, !raw_ptr_call, ); if raw_ptr_call { diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index e800c1a97d9e..611854ce2afd 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -8,7 +8,7 @@ use rustc_errors::{ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::HirId; -use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; +use rustc_infer::infer::need_type_info::TypeAnnotationNeeded; use rustc_middle::span_bug; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; @@ -783,7 +783,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { self.fcx.tcx.hir().body_owner_def_id(self.body.id()), self.span.to_span(self.fcx.tcx), p.into(), - E0282, + TypeAnnotationNeeded::E0282, false, ) .emit() diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/error_reporting/infer/mod.rs similarity index 99% rename from compiler/rustc_infer/src/infer/error_reporting/mod.rs rename to compiler/rustc_infer/src/error_reporting/infer/mod.rs index bb1285ee8135..ddd5818203cf 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/mod.rs @@ -45,17 +45,11 @@ //! ported to this system, and which relies on string concatenation at the //! time of error detection. -use super::{InferCtxt, TypeTrace, ValuePairs}; +use std::borrow::Cow; +use std::ops::{ControlFlow, Deref}; +use std::path::PathBuf; +use std::{cmp, fmt, iter}; -use crate::errors::{ObligationCauseFailureCode, TypeErrorAdditionalDiags}; -use crate::infer; -use crate::infer::ExpectedFound; -use crate::traits::{ - IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, - PredicateObligation, -}; - -use crate::infer::relate::{self, RelateResult, TypeRelation}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ pluralize, Applicability, Diag, DiagCtxtHandle, DiagStyledString, IntoDiagArg, StringPart, @@ -68,6 +62,7 @@ use rustc_hir::{self as hir}; use rustc_macros::extension; use rustc_middle::bug; use rustc_middle::dep_graph::DepContext; +use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError, PrintTraitRefExt as _}; use rustc_middle::ty::{ @@ -76,18 +71,21 @@ use rustc_middle::ty::{ }; use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; -use std::borrow::Cow; -use std::ops::{ControlFlow, Deref}; -use std::path::PathBuf; -use std::{cmp, fmt, iter}; + +use crate::errors::{ObligationCauseFailureCode, TypeErrorAdditionalDiags}; +use crate::infer; +use crate::infer::relate::{self, RelateResult, TypeRelation}; +use crate::infer::{InferCtxt, TypeTrace, ValuePairs}; +use crate::traits::{ + IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, + PredicateObligation, +}; mod note_and_explain; mod suggest; -pub(crate) mod need_type_info; -pub mod sub_relations; -pub use need_type_info::TypeAnnotationNeeded; pub mod region; +pub mod sub_relations; pub mod nice_region_error; @@ -1242,7 +1240,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Some(values) => { let values = self.resolve_vars_if_possible(values); let (is_simple_error, exp_found) = match values { - ValuePairs::Terms(infer::ExpectedFound { expected, found }) => { + ValuePairs::Terms(ExpectedFound { expected, found }) => { match (expected.unpack(), found.unpack()) { (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => { let is_simple_err = expected.is_simple_text(self.tcx) @@ -1254,7 +1252,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ( is_simple_err, - Mismatch::Variable(infer::ExpectedFound { expected, found }), + Mismatch::Variable(ExpectedFound { expected, found }), ) } (ty::TermKind::Const(_), ty::TermKind::Const(_)) => { @@ -1263,13 +1261,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => (false, Mismatch::Fixed("type")), } } - ValuePairs::PolySigs(infer::ExpectedFound { expected, found }) => { + ValuePairs::PolySigs(ExpectedFound { expected, found }) => { OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span) .report(diag); (false, Mismatch::Fixed("signature")) } ValuePairs::TraitRefs(_) => (false, Mismatch::Fixed("trait")), - ValuePairs::Aliases(infer::ExpectedFound { expected, .. }) => { + ValuePairs::Aliases(ExpectedFound { expected, .. }) => { (false, Mismatch::Fixed(self.tcx.def_descr(expected.def_id))) } ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")), @@ -1303,9 +1301,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; if let Some((sp, msg)) = secondary_span { if swap_secondary_and_primary { - let terr = if let Some(infer::ValuePairs::Terms(infer::ExpectedFound { - expected, - .. + let terr = if let Some(infer::ValuePairs::Terms(ExpectedFound { + expected, .. })) = values { Cow::from(format!("expected this to be `{expected}`")) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/different_lifetimes.rs similarity index 94% rename from compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs rename to compiler/rustc_infer/src/error_reporting/infer/nice_region_error/different_lifetimes.rs index cbeec591960b..74dcde03639d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/different_lifetimes.rs @@ -1,21 +1,20 @@ //! Error Reporting for Anonymous Region Lifetime Errors //! where both the regions are anonymous. +use crate::error_reporting::infer::nice_region_error::find_anon_type::find_anon_type; +use crate::error_reporting::infer::nice_region_error::util::AnonymousParamInfo; +use crate::error_reporting::infer::nice_region_error::NiceRegionError; use crate::errors::AddLifetimeParamsSuggestion; use crate::errors::LifetimeMismatch; use crate::errors::LifetimeMismatchLabels; -use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type; -use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo; -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::lexical_region_resolve::RegionResolutionError; +use crate::infer::RegionResolutionError; use crate::infer::SubregionOrigin; -use crate::infer::TyCtxt; use rustc_errors::Subdiagnostic; use rustc_errors::{Diag, ErrorGuaranteed}; use rustc_hir::def_id::LocalDefId; use rustc_hir::Ty; -use rustc_middle::ty::Region; +use rustc_middle::ty::{Region, TyCtxt}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when both the concerned regions are anonymous. diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/find_anon_type.rs similarity index 100% rename from compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs rename to compiler/rustc_infer/src/error_reporting/infer/nice_region_error/find_anon_type.rs diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs similarity index 97% rename from compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs rename to compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs index 7996b4bf65b4..550cc455e018 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs @@ -1,12 +1,12 @@ //! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate //! to hold. +use crate::error_reporting::infer::nice_region_error::NiceRegionError; use crate::errors::{note_and_explain, IntroducesStaticBecauseUnmetLifetimeReq}; use crate::errors::{ DoesNotOutliveStaticFromImpl, ImplicitStaticLifetimeSubdiag, MismatchedStaticLifetime, }; -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::lexical_region_resolve::RegionResolutionError; +use crate::infer::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::ObligationCauseCode; use rustc_data_structures::fx::FxIndexSet; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mod.rs similarity index 94% rename from compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs rename to compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mod.rs index cffdfa887523..ced4c384f026 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mod.rs @@ -1,6 +1,6 @@ -use crate::infer::error_reporting::TypeErrCtxt; -use crate::infer::lexical_region_resolve::RegionResolutionError; -use crate::infer::lexical_region_resolve::RegionResolutionError::*; +use crate::error_reporting::infer::TypeErrCtxt; +use crate::infer::RegionResolutionError; +use crate::infer::RegionResolutionError::*; use rustc_errors::{Diag, ErrorGuaranteed}; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::{self, TyCtxt}; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs similarity index 94% rename from compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs rename to compiler/rustc_infer/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs index 85624c9ca73d..d1802d2f5eeb 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs @@ -1,11 +1,9 @@ //! Error Reporting for Anonymous Region Lifetime Errors //! where one region is named and the other is anonymous. -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::{ - errors::ExplicitLifetimeRequired, - infer::error_reporting::nice_region_error::find_anon_type::find_anon_type, -}; +use crate::error_reporting::infer::nice_region_error::find_anon_type::find_anon_type; +use crate::error_reporting::infer::nice_region_error::NiceRegionError; +use crate::errors::ExplicitLifetimeRequired; use rustc_errors::Diag; use rustc_middle::ty; use rustc_span::symbol::kw; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_error.rs similarity index 99% rename from compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs rename to compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_error.rs index 80b7e3b4fa50..476ac3f1720b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -1,9 +1,9 @@ +use crate::error_reporting::infer::nice_region_error::NiceRegionError; use crate::errors::{ ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes, TraitPlaceholderMismatch, TyOrSig, }; -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::lexical_region_resolve::RegionResolutionError; +use crate::infer::RegionResolutionError; use crate::infer::ValuePairs; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCause, ObligationCauseCode}; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_relation.rs similarity index 94% rename from compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs rename to compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_relation.rs index a3f306802de0..e9f17a3e3e2d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_relation.rs @@ -1,9 +1,6 @@ -use crate::{ - errors::PlaceholderRelationLfNotSatisfied, - infer::{ - error_reporting::nice_region_error::NiceRegionError, RegionResolutionError, SubregionOrigin, - }, -}; +use crate::error_reporting::infer::nice_region_error::NiceRegionError; +use crate::errors::PlaceholderRelationLfNotSatisfied; +use crate::infer::{RegionResolutionError, SubregionOrigin}; use rustc_data_structures::intern::Interned; use rustc_errors::Diag; use rustc_middle::ty::{self, RePlaceholder, Region}; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/static_impl_trait.rs similarity index 99% rename from compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs rename to compiler/rustc_infer/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index 9973646aecd6..ce157ff3dc8d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -1,11 +1,11 @@ //! Error Reporting for static impl Traits. +use crate::error_reporting::infer::nice_region_error::NiceRegionError; use crate::errors::{ ButCallingIntroduces, ButNeedsToSatisfy, DynTraitConstraintSuggestion, MoreTargeted, ReqIntroducedLocations, }; -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::lexical_region_resolve::RegionResolutionError; +use crate::infer::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_data_structures::fx::FxIndexSet; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs similarity index 97% rename from compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs rename to compiler/rustc_infer/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs index 7f3e23716f98..c58c7e135517 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs @@ -1,8 +1,8 @@ //! Error Reporting for `impl` items that do not match the obligations from their `trait`. +use crate::error_reporting::infer::nice_region_error::NiceRegionError; use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff}; -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::lexical_region_resolve::RegionResolutionError; +use crate::infer::RegionResolutionError; use crate::infer::{Subtype, ValuePairs}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/util.rs similarity index 97% rename from compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs rename to compiler/rustc_infer/src/error_reporting/infer/nice_region_error/util.rs index 83145e4f7b27..30fa98c55265 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/util.rs @@ -1,13 +1,13 @@ //! Helper functions corresponding to lifetime errors due to //! anonymous regions. -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::TyCtxt; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_middle::ty::{self, Binder, Region, Ty, TypeFoldable}; +use rustc_middle::ty::{self, Binder, Region, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; +use crate::error_reporting::infer::nice_region_error::NiceRegionError; + /// Information about the anonymous region we are searching for. #[derive(Debug)] pub struct AnonymousParamInfo<'tcx> { diff --git a/compiler/rustc_infer/src/error_reporting/infer/note.rs b/compiler/rustc_infer/src/error_reporting/infer/note.rs new file mode 100644 index 000000000000..aeb3049c2ae9 --- /dev/null +++ b/compiler/rustc_infer/src/error_reporting/infer/note.rs @@ -0,0 +1,421 @@ +use crate::error_reporting::infer::{note_and_explain_region, TypeErrCtxt}; +use crate::errors::{ + note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, + RefLongerThanData, RegionOriginNote, WhereClauseSuggestions, +}; +use crate::fluent_generated as fluent; +use crate::infer::{self, SubregionOrigin}; +use rustc_errors::{Diag, Subdiagnostic}; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_middle::traits::ObligationCauseCode; +use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::{self, IsSuggestable, Region, Ty}; +use rustc_span::symbol::kw; + +use super::ObligationCauseAsDiagArg; + +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { + pub(super) fn note_region_origin(&self, err: &mut Diag<'_>, origin: &SubregionOrigin<'tcx>) { + match *origin { + infer::Subtype(ref trace) => RegionOriginNote::WithRequirement { + span: trace.cause.span, + requirement: ObligationCauseAsDiagArg(trace.cause.clone()), + expected_found: self.values_str(trace.values).map(|(e, f, _)| (e, f)), + } + .add_to_diag(err), + infer::Reborrow(span) => { + RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diag(err) + } + infer::RelateObjectBound(span) => { + RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound } + .add_to_diag(err); + } + infer::ReferenceOutlivesReferent(ty, span) => { + RegionOriginNote::WithName { + span, + msg: fluent::infer_reference_outlives_referent, + name: &self.ty_to_string(ty), + continues: false, + } + .add_to_diag(err); + } + infer::RelateParamBound(span, ty, opt_span) => { + RegionOriginNote::WithName { + span, + msg: fluent::infer_relate_param_bound, + name: &self.ty_to_string(ty), + continues: opt_span.is_some(), + } + .add_to_diag(err); + if let Some(span) = opt_span { + RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 } + .add_to_diag(err); + } + } + infer::RelateRegionParamBound(span) => { + RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound } + .add_to_diag(err); + } + infer::CompareImplItemObligation { span, .. } => { + RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation } + .add_to_diag(err); + } + infer::CheckAssociatedTypeBounds { ref parent, .. } => { + self.note_region_origin(err, parent); + } + infer::AscribeUserTypeProvePredicate(span) => { + RegionOriginNote::Plain { + span, + msg: fluent::infer_ascribe_user_type_prove_predicate, + } + .add_to_diag(err); + } + } + } + + pub(super) fn report_concrete_failure( + &self, + generic_param_scope: LocalDefId, + origin: SubregionOrigin<'tcx>, + sub: Region<'tcx>, + sup: Region<'tcx>, + ) -> Diag<'a> { + let mut err = match origin { + infer::Subtype(box trace) => { + let terr = TypeError::RegionsDoesNotOutlive(sup, sub); + let mut err = self.report_and_explain_type_error(trace, terr); + match (*sub, *sup) { + (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {} + (ty::RePlaceholder(_), _) => { + note_and_explain_region( + self.tcx, + &mut err, + generic_param_scope, + "", + sup, + " doesn't meet the lifetime requirements", + None, + ); + } + (_, ty::RePlaceholder(_)) => { + note_and_explain_region( + self.tcx, + &mut err, + generic_param_scope, + "the required lifetime does not necessarily outlive ", + sub, + "", + None, + ); + } + _ => { + note_and_explain_region( + self.tcx, + &mut err, + generic_param_scope, + "", + sup, + "...", + None, + ); + note_and_explain_region( + self.tcx, + &mut err, + generic_param_scope, + "...does not necessarily outlive ", + sub, + "", + None, + ); + } + } + err + } + infer::Reborrow(span) => { + let reference_valid = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sub, + None, + note_and_explain::PrefixKind::RefValidFor, + note_and_explain::SuffixKind::Continues, + ); + let content_valid = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sup, + None, + note_and_explain::PrefixKind::ContentValidFor, + note_and_explain::SuffixKind::Empty, + ); + self.dcx().create_err(OutlivesContent { + span, + notes: reference_valid.into_iter().chain(content_valid).collect(), + }) + } + infer::RelateObjectBound(span) => { + let object_valid = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sub, + None, + note_and_explain::PrefixKind::TypeObjValidFor, + note_and_explain::SuffixKind::Empty, + ); + let pointer_valid = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sup, + None, + note_and_explain::PrefixKind::SourcePointerValidFor, + note_and_explain::SuffixKind::Empty, + ); + self.dcx().create_err(OutlivesBound { + span, + notes: object_valid.into_iter().chain(pointer_valid).collect(), + }) + } + infer::RelateParamBound(span, ty, opt_span) => { + let prefix = match *sub { + ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy, + _ => note_and_explain::PrefixKind::TypeOutlive, + }; + let suffix = if opt_span.is_some() { + note_and_explain::SuffixKind::ReqByBinding + } else { + note_and_explain::SuffixKind::Empty + }; + let note = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sub, + opt_span, + prefix, + suffix, + ); + self.dcx().create_err(FulfillReqLifetime { + span, + ty: self.resolve_vars_if_possible(ty), + note, + }) + } + infer::RelateRegionParamBound(span) => { + let param_instantiated = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sup, + None, + note_and_explain::PrefixKind::LfParamInstantiatedWith, + note_and_explain::SuffixKind::Empty, + ); + let param_must_outlive = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sub, + None, + note_and_explain::PrefixKind::LfParamMustOutlive, + note_and_explain::SuffixKind::Empty, + ); + self.dcx().create_err(LfBoundNotSatisfied { + span, + notes: param_instantiated.into_iter().chain(param_must_outlive).collect(), + }) + } + infer::ReferenceOutlivesReferent(ty, span) => { + let pointer_valid = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sub, + None, + note_and_explain::PrefixKind::PointerValidFor, + note_and_explain::SuffixKind::Empty, + ); + let data_valid = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sup, + None, + note_and_explain::PrefixKind::DataValidFor, + note_and_explain::SuffixKind::Empty, + ); + self.dcx().create_err(RefLongerThanData { + span, + ty: self.resolve_vars_if_possible(ty), + notes: pointer_valid.into_iter().chain(data_valid).collect(), + }) + } + infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => { + let mut err = self.infcx.report_extra_impl_obligation( + span, + impl_item_def_id, + trait_item_def_id, + &format!("`{sup}: {sub}`"), + ); + // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause + if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) + && generics.where_clause_span.contains(span) + { + self.suggest_copy_trait_method_bounds( + trait_item_def_id, + impl_item_def_id, + &mut err, + ); + } + err + } + infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => { + let mut err = self.report_concrete_failure(generic_param_scope, *parent, sub, sup); + + // Don't mention the item name if it's an RPITIT, since that'll just confuse + // folks. + if !self.tcx.is_impl_trait_in_trait(impl_item_def_id.to_def_id()) { + let trait_item_span = self.tcx.def_span(trait_item_def_id); + let item_name = self.tcx.item_name(impl_item_def_id.to_def_id()); + err.span_label( + trait_item_span, + format!("definition of `{item_name}` from trait"), + ); + } + + self.suggest_copy_trait_method_bounds( + trait_item_def_id, + impl_item_def_id, + &mut err, + ); + err + } + infer::AscribeUserTypeProvePredicate(span) => { + let instantiated = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sup, + None, + note_and_explain::PrefixKind::LfInstantiatedWith, + note_and_explain::SuffixKind::Empty, + ); + let must_outlive = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sub, + None, + note_and_explain::PrefixKind::LfMustOutlive, + note_and_explain::SuffixKind::Empty, + ); + self.dcx().create_err(LfBoundNotSatisfied { + span, + notes: instantiated.into_iter().chain(must_outlive).collect(), + }) + } + }; + if sub.is_error() || sup.is_error() { + err.downgrade_to_delayed_bug(); + } + err + } + + pub fn suggest_copy_trait_method_bounds( + &self, + trait_item_def_id: DefId, + impl_item_def_id: LocalDefId, + err: &mut Diag<'_>, + ) { + // FIXME(compiler-errors): Right now this is only being used for region + // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches, + // but right now it's not really very smart when it comes to implicit `Sized` + // predicates and bounds on the trait itself. + + let Some(impl_def_id) = self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx) + else { + return; + }; + let Some(trait_ref) = self.tcx.impl_trait_ref(impl_def_id) else { + return; + }; + let trait_args = trait_ref + .instantiate_identity() + // Replace the explicit self type with `Self` for better suggestion rendering + .with_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper)) + .args; + let trait_item_args = ty::GenericArgs::identity_for_item(self.tcx, impl_item_def_id) + .rebase_onto(self.tcx, impl_def_id, trait_args); + + let Ok(trait_predicates) = + self.tcx + .explicit_predicates_of(trait_item_def_id) + .instantiate_own(self.tcx, trait_item_args) + .map(|(pred, _)| { + if pred.is_suggestable(self.tcx, false) { + Ok(pred.to_string()) + } else { + Err(()) + } + }) + .collect::, ()>>() + else { + return; + }; + + let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else { + return; + }; + + let suggestion = if trait_predicates.is_empty() { + WhereClauseSuggestions::Remove { span: generics.where_clause_span } + } else { + let space = if generics.where_clause_span.is_empty() { " " } else { "" }; + WhereClauseSuggestions::CopyPredicates { + span: generics.where_clause_span, + space, + trait_predicates: trait_predicates.join(", "), + } + }; + err.subdiagnostic(suggestion); + } + + pub(super) fn report_placeholder_failure( + &self, + generic_param_scope: LocalDefId, + placeholder_origin: SubregionOrigin<'tcx>, + sub: Region<'tcx>, + sup: Region<'tcx>, + ) -> Diag<'a> { + // I can't think how to do better than this right now. -nikomatsakis + debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure"); + match placeholder_origin { + infer::Subtype(box ref trace) + if matches!( + &trace.cause.code().peel_derives(), + ObligationCauseCode::WhereClause(..) + | ObligationCauseCode::WhereClauseInExpr(..) + ) => + { + // Hack to get around the borrow checker because trace.cause has an `Rc`. + if let ObligationCauseCode::WhereClause(_, span) + | ObligationCauseCode::WhereClauseInExpr(_, span, ..) = + &trace.cause.code().peel_derives() + && !span.is_dummy() + { + let span = *span; + self.report_concrete_failure(generic_param_scope, placeholder_origin, sub, sup) + .with_span_note(span, "the lifetime requirement is introduced here") + } else { + unreachable!( + "control flow ensures we have a `BindingObligation` or `WhereClauseInExpr` here..." + ) + } + } + infer::Subtype(box trace) => { + let terr = TypeError::RegionsPlaceholderMismatch; + return self.report_and_explain_type_error(trace, terr); + } + _ => { + return self.report_concrete_failure( + generic_param_scope, + placeholder_origin, + sub, + sup, + ); + } + } + } +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/error_reporting/infer/note_and_explain.rs similarity index 100% rename from compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs rename to compiler/rustc_infer/src/error_reporting/infer/note_and_explain.rs diff --git a/compiler/rustc_infer/src/infer/error_reporting/region.rs b/compiler/rustc_infer/src/error_reporting/infer/region.rs similarity index 99% rename from compiler/rustc_infer/src/infer/error_reporting/region.rs rename to compiler/rustc_infer/src/error_reporting/infer/region.rs index 191cb23184da..093d2d3d743d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/region.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/region.rs @@ -18,12 +18,12 @@ use rustc_type_ir::Upcast as _; use super::nice_region_error::find_anon_type; use super::{nice_region_error, ObligationCauseAsDiagArg}; +use crate::error_reporting::infer::{ObligationCauseExt as _, TypeErrCtxt}; use crate::errors::{ self, note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, RefLongerThanData, RegionOriginNote, WhereClauseSuggestions, }; use crate::fluent_generated as fluent; -use crate::infer::error_reporting::{ObligationCauseExt as _, TypeErrCtxt}; use crate::infer::region_constraints::GenericKind; use crate::infer::{self, InferCtxt, RegionResolutionError, RegionVariableOrigin, SubregionOrigin}; diff --git a/compiler/rustc_infer/src/infer/error_reporting/sub_relations.rs b/compiler/rustc_infer/src/error_reporting/infer/sub_relations.rs similarity index 100% rename from compiler/rustc_infer/src/infer/error_reporting/sub_relations.rs rename to compiler/rustc_infer/src/error_reporting/infer/sub_relations.rs diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/error_reporting/infer/suggest.rs similarity index 99% rename from compiler/rustc_infer/src/infer/error_reporting/suggest.rs rename to compiler/rustc_infer/src/error_reporting/infer/suggest.rs index 13b145296a7c..4d11ab9fac68 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/suggest.rs @@ -1,4 +1,4 @@ -use crate::infer::error_reporting::hir::Path; +use crate::error_reporting::infer::hir::Path; use core::ops::ControlFlow; use hir::def::CtorKind; use hir::intravisit::{walk_expr, walk_stmt, Visitor}; diff --git a/compiler/rustc_infer/src/error_reporting/mod.rs b/compiler/rustc_infer/src/error_reporting/mod.rs new file mode 100644 index 000000000000..132485ec6615 --- /dev/null +++ b/compiler/rustc_infer/src/error_reporting/mod.rs @@ -0,0 +1 @@ +pub mod infer; diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index ce1b0f86d034..f849a1a73224 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -15,11 +15,10 @@ use rustc_span::symbol::kw; use rustc_span::Symbol; use rustc_span::{symbol::Ident, BytePos, Span}; +use crate::error_reporting::infer::nice_region_error::placeholder_error::Highlighted; +use crate::error_reporting::infer::ObligationCauseAsDiagArg; use crate::fluent_generated as fluent; -use crate::infer::error_reporting::{ - need_type_info::UnderspecifiedArgKind, nice_region_error::placeholder_error::Highlighted, - ObligationCauseAsDiagArg, -}; +use crate::infer::need_type_info::UnderspecifiedArgKind; use std::path::PathBuf; diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index 4fbeb0ec1024..d71b7f3c264e 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -1,5 +1,5 @@ +use crate::error_reporting::infer::nice_region_error::find_anon_type; use crate::fluent_generated as fluent; -use crate::infer::error_reporting::nice_region_error::find_anon_type; use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, SubdiagMessageOp, Subdiagnostic}; use rustc_hir::def_id::LocalDefId; use rustc_middle::bug; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index a0be545d46fe..cfef1f130156 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -11,9 +11,9 @@ pub use BoundRegionConversionTime::*; pub use RegionVariableOrigin::*; pub use SubregionOrigin::*; +use crate::error_reporting::infer::TypeErrCtxt; use crate::infer::relate::RelateResult; use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine}; -use error_reporting::TypeErrCtxt; use free_regions::RegionRelations; use lexical_region_resolve::LexicalRegionResolutions; use opaque_types::OpaqueTypeStorage; @@ -54,7 +54,6 @@ use type_variable::TypeVariableOrigin; pub mod at; pub mod canonical; mod context; -pub mod error_reporting; pub mod free_regions; mod freshen; mod lexical_region_resolve; @@ -66,6 +65,8 @@ pub mod relate; pub mod resolve; pub(crate) mod snapshot; pub mod type_variable; +// FIXME(error_reporting): Where should we put this? +pub mod need_type_info; #[must_use] #[derive(Debug)] diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/need_type_info.rs similarity index 99% rename from compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs rename to compiler/rustc_infer/src/infer/need_type_info.rs index 084aebc296f8..4f3dcd9043fd 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/need_type_info.rs @@ -1,8 +1,8 @@ +use crate::error_reporting::infer::TypeErrCtxt; use crate::errors::{ AmbiguousImpl, AmbiguousReturn, AnnotationRequired, InferenceBadError, SourceKindMultiSuggestion, SourceKindSubdiag, }; -use crate::infer::error_reporting::TypeErrCtxt; use crate::infer::InferCtxt; use rustc_errors::{codes::*, Diag, IntoDiagArg}; use rustc_hir as hir; diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index b65ac8596675..02ebf933f532 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -34,6 +34,7 @@ #[macro_use] extern crate tracing; +pub mod error_reporting; mod errors; pub mod infer; pub mod traits; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index c301deac6164..deab0451ccb6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -8,7 +8,8 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor as _; use rustc_hir::LangItem; -use rustc_infer::infer::error_reporting::{TypeAnnotationNeeded, TypeErrCtxt}; +use rustc_infer::error_reporting::infer::TypeErrCtxt; +use rustc_infer::infer::need_type_info::TypeAnnotationNeeded; use rustc_infer::infer::{BoundRegionConversionTime, InferCtxt}; use rustc_infer::traits::util::elaborate; use rustc_infer::traits::{ diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 2e6247b46401..0d040ddbacb2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -4,7 +4,6 @@ use crate::error_reporting::traits::infer_ctxt_ext::InferCtxtExt; use crate::errors::{ AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, }; -use crate::infer::error_reporting::TyCategory; use crate::infer::InferCtxtExt as _; use crate::infer::{self, InferCtxt}; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -25,7 +24,8 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::Node; use rustc_hir::{self as hir, LangItem}; -use rustc_infer::infer::error_reporting::TypeErrCtxt; +use rustc_infer::error_reporting::infer::TyCategory; +use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_infer::infer::{InferOk, TypeTrace}; use rustc_macros::extension; use rustc_middle::traits::select::OverflowError; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 2131e236401e..16dfa27b75aa 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -11,7 +11,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, LangItem}; -use rustc_infer::infer::error_reporting::TypeErrCtxt; +use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_infer::traits::{ Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError, }; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index e90fe8fb94dd..a448e1924c8f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -3,7 +3,6 @@ use crate::error_reporting::traits::fulfillment_errors::InferCtxtPrivExt; use crate::errors::{ EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, }; -use crate::infer::error_reporting::TypeErrCtxt; use crate::infer::InferCtxtExt; use rustc_ast::AttrArgs; use rustc_ast::AttrArgsEq; @@ -14,6 +13,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_macros::{extension, LintDiagnostic}; use rustc_middle::bug; use rustc_middle::ty::print::PrintTraitRefExt as _; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs index 061a5a4be207..fe1771f9096b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs @@ -5,7 +5,7 @@ use rustc_errors::{ }; use rustc_hir::def::Namespace; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_infer::infer::error_reporting::TypeErrCtxt; +use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_infer::traits::{Obligation, PredicateObligation}; use rustc_macros::extension; use rustc_middle::ty::print::{FmtPrinter, Print}; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 2cf808f962f0..2dfbdbd90fc1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -23,7 +23,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::is_range_literal; use rustc_hir::lang_items::LangItem; use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node}; -use rustc_infer::infer::error_reporting::TypeErrCtxt; +use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk}; use rustc_macros::extension; use rustc_middle::hir::map; diff --git a/src/tools/clippy/tests/ui/track-diagnostics.stderr b/src/tools/clippy/tests/ui/track-diagnostics.stderr index 410e80f25280..3c7577dd003c 100644 --- a/src/tools/clippy/tests/ui/track-diagnostics.stderr +++ b/src/tools/clippy/tests/ui/track-diagnostics.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | const S: A = B; | ^ expected `A`, found `B` --Ztrack-diagnostics: created at compiler/rustc_infer/src/infer/error_reporting/mod.rs:LL:CC +-Ztrack-diagnostics: created at compiler/rustc_infer/src/error_reporting/infer/mod.rs:LL:CC error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/track-diagnostics.stderr b/tests/rustdoc-ui/track-diagnostics.stderr index 131adfd588c2..f7f3e368a3c1 100644 --- a/tests/rustdoc-ui/track-diagnostics.stderr +++ b/tests/rustdoc-ui/track-diagnostics.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | const S: A = B; | ^ expected `A`, found `B` --Ztrack-diagnostics: created at compiler/rustc_infer/src/infer/error_reporting/mod.rs:LL:CC +-Ztrack-diagnostics: created at compiler/rustc_infer/src/error_reporting/infer/mod.rs:LL:CC error: aborting due to 1 previous error From c1c945a350ab7c2d82013f46fc94d332d2964516 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 8 Jul 2024 21:03:08 -0400 Subject: [PATCH 150/734] Move rustc_infer::infer::error_reporting to rustc_infer::error_reporting::infer --- tests/ui/track-diagnostics.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/track-diagnostics.stderr b/tests/ui/track-diagnostics.stderr index 410e80f25280..3c7577dd003c 100644 --- a/tests/ui/track-diagnostics.stderr +++ b/tests/ui/track-diagnostics.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | const S: A = B; | ^ expected `A`, found `B` --Ztrack-diagnostics: created at compiler/rustc_infer/src/infer/error_reporting/mod.rs:LL:CC +-Ztrack-diagnostics: created at compiler/rustc_infer/src/error_reporting/infer/mod.rs:LL:CC error: aborting due to 1 previous error From 3924493a1070b5407a2203e99e4856af7e37f7d5 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 15 Jul 2024 16:20:37 -0700 Subject: [PATCH 151/734] rustdoc: make sidebar highlight cover whole click target --- src/librustdoc/html/static/css/rustdoc.css | 43 +++++++++++++++++++++- tests/rustdoc-gui/huge-logo.goml | 4 +- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 940f444dde1f..cb8b82e8bde0 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -564,7 +564,7 @@ ul.block, .block li { /* extend click target to far edge of screen (mile wide bar) */ border-left: solid var(--sidebar-elems-left-padding) transparent; margin-left: calc(-0.25rem - var(--sidebar-elems-left-padding)); - background-clip: padding-box; + background-clip: border-box; } .sidebar h2 { @@ -641,11 +641,50 @@ ul.block, .block li { text-align: center; } +.sidebar-crate .logo-container img { + /* When in a horizontal logo lockup, the highlight color of the crate name menu item + extends underneath the actual logo (in a vertical lockup, that background highlight + extends to the left edge of the screen). + + To prevent a weird-looking colored band from appearing under the logo, cover it up + with the sidebar's background. Additionally, the crate name extends slightly above + the logo, so that its highlight has a bit of space to let the ascenders breath while + also having those ascenders meet exactly with the top of the logo. + + In ANSI art, make it look like this: + | ┌─────┐ + | (R) │ std │ + | └─────┘ + + Not like this (which would happen without the z-index): + | ┌────────┐ + | (│ std │ + | └────────┘ + + Not like this (which would happen without the background): + | ┌────────┐ + | (R) std │ + | └────────┘ + + Nor like this (which would happen without the negative margin): + | ─────────┐ + | (R) │ std │ + | └─────┘ + */ + margin-top: -16px; + border-top: solid 16px transparent; + box-sizing: content-box; + position: relative; + background-color: var(--sidebar-background-color); + background-clip: border-box; + z-index: 1; +} + .sidebar-crate h2 a { display: block; /* extend click target to far edge of screen (mile wide bar) */ border-left: solid var(--sidebar-elems-left-padding) transparent; - background-clip: padding-box; + background-clip: border-box; margin: 0 calc(-24px + 0.25rem) 0 calc(-0.2rem - var(--sidebar-elems-left-padding)); /* Align the sidebar crate link with the search bar, which have different font sizes. diff --git a/tests/rustdoc-gui/huge-logo.goml b/tests/rustdoc-gui/huge-logo.goml index 6fc45ede181e..01999401e607 100644 --- a/tests/rustdoc-gui/huge-logo.goml +++ b/tests/rustdoc-gui/huge-logo.goml @@ -5,8 +5,8 @@ go-to: "file://" + |DOC_PATH| + "/huge_logo/index.html" set-window-size: (1280, 1024) // offsetWidth = width of sidebar + left and right margins assert-property: (".sidebar-crate .logo-container", {"offsetWidth": "96", "offsetHeight": 48}) -// offsetWidth = width of sidebar -assert-property: (".sidebar-crate .logo-container img", {"offsetWidth": "48", "offsetHeight": 48}) +// offsetWidth = width of sidebar, offsetHeight = height + top padding +assert-property: (".sidebar-crate .logo-container img", {"offsetWidth": "48", "offsetHeight": 64}) set-window-size: (400, 600) // offset = size + margin From e37b92ffd8b0fa490566416fbf6d0479734a8b83 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 7 Jul 2024 23:29:18 +1000 Subject: [PATCH 152/734] Use an iterator to find `expand_until` This makes it easier to see that the split point is always the index after the found item, or the whole list if no stopping point was found. --- .../rustc_mir_build/src/build/matches/mod.rs | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 841ef2719c99..7ad453be3659 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1536,10 +1536,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { start_block: BasicBlock, candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], ) -> BlockAnd<&'b mut [&'c mut Candidate<'pat, 'tcx>]> { - // We can't expand or-patterns freely. The rule is: if the candidate has an - // or-pattern as its only remaining match pair, we can expand it freely. If it has - // other match pairs, we can expand it but we can't process more candidates after - // it. + // We can't expand or-patterns freely. The rule is: + // - If a candidate doesn't start with an or-pattern, we include it in + // the expansion list as-is (i.e. it "expands" to itself). + // - If a candidate has an or-pattern as its only remaining match pair, + // we can expand it. + // - If it starts with an or-pattern but also has other match pairs, + // we can expand it, but we can't process more candidates after it. // // If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the // following, or-pattern simplification (in `merge_trivial_subcandidates`) makes it @@ -1556,17 +1559,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // } // ``` // - // We therefore split the `candidates` slice in two, expand or-patterns in the first half, + // We therefore split the `candidates` slice in two, expand or-patterns in the first part, // and process the rest separately. - let mut expand_until = 0; - for (i, candidate) in candidates.iter().enumerate() { - expand_until = i + 1; - if candidate.match_pairs.len() > 1 && candidate.starts_with_or_pattern() { - // The candidate has an or-pattern as well as more match pairs: we must - // split the candidates list here. - break; - } - } + let expand_until = candidates + .iter() + .position(|candidate| { + // If a candidate starts with an or-pattern and has more match pairs, + // we can expand it, but we must stop expanding _after_ it. + candidate.match_pairs.len() > 1 && candidate.starts_with_or_pattern() + }) + .map(|pos| pos + 1) // Stop _after_ the found candidate + .unwrap_or(candidates.len()); // Otherwise, include all candidates let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until); // Expand one level of or-patterns for each candidate in `candidates_to_expand`. @@ -1581,6 +1584,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expanded_candidates.push(subcandidate); } } else { + // A candidate that doesn't start with an or-pattern has nothing to + // expand, so it is included in the post-expansion list as-is. expanded_candidates.push(candidate); } } From 7f8f1780d47efa836a636de62a2b27cba20f2644 Mon Sep 17 00:00:00 2001 From: Sky Date: Sun, 7 Jul 2024 00:18:35 -0400 Subject: [PATCH 153/734] `impl Send + Sync` and override `count` for the `CStr::bytes` iterator --- library/core/src/ffi/c_str.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index d2a408485d16..1dd4710b3a36 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -780,8 +780,15 @@ const unsafe fn const_strlen(ptr: *const c_char) -> usize { pub struct Bytes<'a> { // since we know the string is nul-terminated, we only need one pointer ptr: NonNull, - phantom: PhantomData<&'a u8>, + phantom: PhantomData<&'a [c_char]>, } + +#[unstable(feature = "cstr_bytes", issue = "112115")] +unsafe impl Send for Bytes<'_> {} + +#[unstable(feature = "cstr_bytes", issue = "112115")] +unsafe impl Sync for Bytes<'_> {} + impl<'a> Bytes<'a> { #[inline] fn new(s: &'a CStr) -> Self { @@ -814,7 +821,7 @@ impl Iterator for Bytes<'_> { if ret == 0 { None } else { - self.ptr = self.ptr.offset(1); + self.ptr = self.ptr.add(1); Some(ret) } } @@ -824,6 +831,12 @@ impl Iterator for Bytes<'_> { fn size_hint(&self) -> (usize, Option) { if self.is_empty() { (0, Some(0)) } else { (1, None) } } + + #[inline] + fn count(self) -> usize { + // SAFETY: We always hold a valid pointer to a C string + unsafe { strlen(self.ptr.as_ptr().cast()) } + } } #[unstable(feature = "cstr_bytes", issue = "112115")] From 00811621fec122f1355d81ab694ecfb32aec49a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=81=E6=B5=A9----=E5=A4=A9=E5=91=BD=E5=89=91=E4=B8=BB?= Date: Tue, 16 Jul 2024 11:05:18 +0800 Subject: [PATCH 154/734] delete #![allow(unsafe_op_in_unsafe_fn)] this is redundant, so we can just delete it. --- library/std/src/sys/pal/teeos/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs index 2a789e72722b..4c0620f270a9 100644 --- a/library/std/src/sys/pal/teeos/mod.rs +++ b/library/std/src/sys/pal/teeos/mod.rs @@ -2,7 +2,6 @@ //! //! This module contains the facade (aka platform-specific) implementations of //! OS level functionality for Teeos. -#![allow(unsafe_op_in_unsafe_fn)] #![allow(unused_variables)] #![allow(dead_code)] From 060a40de63f68c44d38710ebc6dc185ccd156053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=81=E6=B5=A9----=E5=A4=A9=E5=91=BD=E5=89=91=E4=B8=BB?= Date: Tue, 16 Jul 2024 11:18:51 +0800 Subject: [PATCH 155/734] clean unsafe op in unsafe fn --- library/std/src/sys/pal/teeos/alloc.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/library/std/src/sys/pal/teeos/alloc.rs b/library/std/src/sys/pal/teeos/alloc.rs index e236819aa238..b280d1dd76f7 100644 --- a/library/std/src/sys/pal/teeos/alloc.rs +++ b/library/std/src/sys/pal/teeos/alloc.rs @@ -11,9 +11,9 @@ unsafe impl GlobalAlloc for System { // Also see and // . if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::malloc(layout.size()) as *mut u8 + unsafe { libc::malloc(layout.size()) as *mut u8 } } else { - aligned_malloc(&layout) + unsafe { aligned_malloc(&layout) } } } @@ -21,11 +21,11 @@ unsafe impl GlobalAlloc for System { unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { // See the comment above in `alloc` for why this check looks the way it does. if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::calloc(layout.size(), 1) as *mut u8 + unsafe { libc::calloc(layout.size(), 1) as *mut u8 } } else { - let ptr = self.alloc(layout); + let ptr = unsafe { self.alloc(layout) }; if !ptr.is_null() { - ptr::write_bytes(ptr, 0, layout.size()); + unsafe { ptr::write_bytes(ptr, 0, layout.size()) }; } ptr } @@ -33,15 +33,15 @@ unsafe impl GlobalAlloc for System { #[inline] unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { - libc::free(ptr as *mut libc::c_void) + unsafe { libc::free(ptr as *mut libc::c_void) } } #[inline] unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { if layout.align() <= MIN_ALIGN && layout.align() <= new_size { - libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 + unsafe { libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 } } else { - realloc_fallback(self, ptr, layout, new_size) + unsafe { realloc_fallback(self, ptr, layout, new_size) } } } } @@ -52,6 +52,6 @@ unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`. // Since these are all powers of 2, we can just use max. let align = layout.align().max(crate::mem::size_of::()); - let ret = libc::posix_memalign(&mut out, align, layout.size()); + let ret = unsafe { libc::posix_memalign(&mut out, align, layout.size()) }; if ret != 0 { ptr::null_mut() } else { out as *mut u8 } } From 00fff8ac648d486b777c4345ba589be1f5643c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=81=E6=B5=A9----=E5=A4=A9=E5=91=BD=E5=89=91=E4=B8=BB?= Date: Tue, 16 Jul 2024 11:34:23 +0800 Subject: [PATCH 156/734] clean unsafe op in unsafe fn --- library/std/src/sys/sync/condvar/teeos.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/sync/condvar/teeos.rs b/library/std/src/sys/sync/condvar/teeos.rs index 0a931f407d2f..6457da91c2a5 100644 --- a/library/std/src/sys/sync/condvar/teeos.rs +++ b/library/std/src/sys/sync/condvar/teeos.rs @@ -76,16 +76,16 @@ impl Condvar { #[inline] pub unsafe fn wait(&self, mutex: &Mutex) { - let mutex = mutex::raw(mutex); + let mutex = unsafe { mutex::raw(mutex) }; self.verify(mutex); - let r = libc::pthread_cond_wait(raw(self), mutex); + let r = unsafe { libc::pthread_cond_wait(raw(self), mutex) }; debug_assert_eq!(r, 0); } pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { use crate::sys::time::Timespec; - let mutex = mutex::raw(mutex); + let mutex = unsafe { mutex::raw(mutex) }; self.verify(mutex); let timeout = Timespec::now(libc::CLOCK_MONOTONIC) @@ -93,7 +93,7 @@ impl Condvar { .and_then(|t| t.to_timespec()) .unwrap_or(TIMESPEC_MAX); - let r = pthread_cond_timedwait(raw(self), mutex, &timeout); + let r = unsafe { pthread_cond_timedwait(raw(self), mutex, &timeout) }; assert!(r == libc::ETIMEDOUT || r == 0); r == 0 } From af5c90d33fc8063224cb6871619b65f0d8f71f6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=81=E6=B5=A9----=E5=A4=A9=E5=91=BD=E5=89=91=E4=B8=BB?= Date: Tue, 16 Jul 2024 11:46:16 +0800 Subject: [PATCH 157/734] clean unsafe op in unsafe fn --- library/std/src/sys/pal/teeos/thread.rs | 28 +++++++++++++------------ 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs index f4723b2ea46b..7a27d749f1c9 100644 --- a/library/std/src/sys/pal/teeos/thread.rs +++ b/library/std/src/sys/pal/teeos/thread.rs @@ -28,22 +28,24 @@ impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements pub unsafe fn new(stack: usize, p: Box) -> io::Result { let p = Box::into_raw(Box::new(p)); - let mut native: libc::pthread_t = mem::zeroed(); - let mut attr: libc::pthread_attr_t = mem::zeroed(); - assert_eq!(libc::pthread_attr_init(&mut attr), 0); + let mut native: libc::pthread_t = unsafe { mem::zeroed() }; + let mut attr: libc::pthread_attr_t = unsafe { mem::zeroed() }; + assert_eq!(unsafe { libc::pthread_attr_init(&mut attr) }, 0); assert_eq!( - libc::pthread_attr_settee( - &mut attr, - libc::TEESMP_THREAD_ATTR_CA_INHERIT, - libc::TEESMP_THREAD_ATTR_TASK_ID_INHERIT, - libc::TEESMP_THREAD_ATTR_HAS_SHADOW, - ), + unsafe { + libc::pthread_attr_settee( + &mut attr, + libc::TEESMP_THREAD_ATTR_CA_INHERIT, + libc::TEESMP_THREAD_ATTR_TASK_ID_INHERIT, + libc::TEESMP_THREAD_ATTR_HAS_SHADOW, + ) + }, 0, ); let stack_size = cmp::max(stack, min_stack_size(&attr)); - match libc::pthread_attr_setstacksize(&mut attr, stack_size) { + match unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) } { 0 => {} n => { assert_eq!(n, libc::EINVAL); @@ -54,7 +56,7 @@ impl Thread { let page_size = os::page_size(); let stack_size = (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); - assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0); + assert_eq!(unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) }, 0); } }; @@ -62,12 +64,12 @@ impl Thread { // Note: if the thread creation fails and this assert fails, then p will // be leaked. However, an alternative design could cause double-free // which is clearly worse. - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + assert_eq!(unsafe { libc::pthread_attr_destroy(&mut attr) }, 0); return if ret != 0 { // The thread failed to start and as a result p was not consumed. Therefore, it is // safe to reconstruct the box so that it gets deallocated. - drop(Box::from_raw(p)); + drop(unsafe { Box::from_raw(p) }); Err(io::Error::from_raw_os_error(ret)) } else { // The new thread will start running earliest after the next yield. From 9183af25e5ab0c9a39a5a45270e1439ebd22eb24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=81=E6=B5=A9----=E5=A4=A9=E5=91=BD=E5=89=91=E4=B8=BB?= Date: Tue, 16 Jul 2024 11:47:22 +0800 Subject: [PATCH 158/734] deny unsafe_op_in_unsafe_fn for teeos --- library/std/src/sys/pal/teeos/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs index 4c0620f270a9..adefd1bb42c8 100644 --- a/library/std/src/sys/pal/teeos/mod.rs +++ b/library/std/src/sys/pal/teeos/mod.rs @@ -2,6 +2,7 @@ //! //! This module contains the facade (aka platform-specific) implementations of //! OS level functionality for Teeos. +#![deny(unsafe_op_in_unsafe_fn)] #![allow(unused_variables)] #![allow(dead_code)] From 71eb49c318c3e7c25a6306414298d78accd164df Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 14 Jul 2024 13:25:06 -0400 Subject: [PATCH 159/734] fmt --- .../rustc_span/src/analyze_source_file.rs | 91 ++++++++++--------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index 7da7dc610ecf..80c5c3bf1b5a 100644 --- a/compiler/rustc_span/src/analyze_source_file.rs +++ b/compiler/rustc_span/src/analyze_source_file.rs @@ -35,25 +35,25 @@ pub fn analyze_source_file( cfg_match! { cfg(any(target_arch = "x86", target_arch = "x86_64")) => { - fn analyze_source_file_dispatch(src: &str, - lines: &mut Vec, - multi_byte_chars: &mut Vec, - non_narrow_chars: &mut Vec) { + fn analyze_source_file_dispatch( + src: &str, + lines: &mut Vec, + multi_byte_chars: &mut Vec, + non_narrow_chars: &mut Vec, + ) { if is_x86_feature_detected!("sse2") { unsafe { - analyze_source_file_sse2(src, - lines, - multi_byte_chars, - non_narrow_chars); + analyze_source_file_sse2(src, lines, multi_byte_chars, non_narrow_chars); } } else { - analyze_source_file_generic(src, - src.len(), - RelativeBytePos::from_u32(0), - lines, - multi_byte_chars, - non_narrow_chars); - + analyze_source_file_generic( + src, + src.len(), + RelativeBytePos::from_u32(0), + lines, + multi_byte_chars, + non_narrow_chars, + ); } } @@ -62,10 +62,12 @@ cfg_match! { /// function falls back to the generic implementation. Otherwise it uses /// SSE2 intrinsics to quickly find all newlines. #[target_feature(enable = "sse2")] - unsafe fn analyze_source_file_sse2(src: &str, - lines: &mut Vec, - multi_byte_chars: &mut Vec, - non_narrow_chars: &mut Vec) { + unsafe fn analyze_source_file_sse2( + src: &str, + lines: &mut Vec, + multi_byte_chars: &mut Vec, + non_narrow_chars: &mut Vec, + ) { #[cfg(target_arch = "x86")] use std::arch::x86::*; #[cfg(target_arch = "x86_64")] @@ -83,7 +85,7 @@ cfg_match! { // handled it. let mut intra_chunk_offset = 0; - for chunk_index in 0 .. chunk_count { + for chunk_index in 0..chunk_count { let ptr = src_bytes.as_ptr() as *const __m128i; // We don't know if the pointer is aligned to 16 bytes, so we // use `loadu`, which supports unaligned loading. @@ -126,7 +128,7 @@ cfg_match! { if index >= CHUNK_SIZE as u32 { // We have arrived at the end of the chunk. - break + break; } lines.push(RelativeBytePos(index) + output_offset); @@ -137,14 +139,14 @@ cfg_match! { // We are done for this chunk. All control characters were // newlines and we took care of those. - continue + continue; } else { // Some of the control characters are not newlines, // fall through to the slow path below. } } else { // No control characters, nothing to record for this chunk - continue + continue; } } @@ -152,43 +154,48 @@ cfg_match! { // There are control chars in here, fallback to generic decoding. let scan_start = chunk_index * CHUNK_SIZE + intra_chunk_offset; intra_chunk_offset = analyze_source_file_generic( - &src[scan_start .. ], + &src[scan_start..], CHUNK_SIZE - intra_chunk_offset, RelativeBytePos::from_usize(scan_start), lines, multi_byte_chars, - non_narrow_chars + non_narrow_chars, ); } // There might still be a tail left to analyze let tail_start = chunk_count * CHUNK_SIZE + intra_chunk_offset; if tail_start < src.len() { - analyze_source_file_generic(&src[tail_start ..], - src.len() - tail_start, - RelativeBytePos::from_usize(tail_start), - lines, - multi_byte_chars, - non_narrow_chars); + analyze_source_file_generic( + &src[tail_start..], + src.len() - tail_start, + RelativeBytePos::from_usize(tail_start), + lines, + multi_byte_chars, + non_narrow_chars, + ); } } } _ => { // The target (or compiler version) does not support SSE2 ... - fn analyze_source_file_dispatch(src: &str, - lines: &mut Vec, - multi_byte_chars: &mut Vec, - non_narrow_chars: &mut Vec) { - analyze_source_file_generic(src, - src.len(), - RelativeBytePos::from_u32(0), - lines, - multi_byte_chars, - non_narrow_chars); + fn analyze_source_file_dispatch( + src: &str, + lines: &mut Vec, + multi_byte_chars: &mut Vec, + non_narrow_chars: &mut Vec, + ) { + analyze_source_file_generic( + src, + src.len(), + RelativeBytePos::from_u32(0), + lines, + multi_byte_chars, + non_narrow_chars, + ); } } } - // `scan_len` determines the number of bytes in `src` to scan. Note that the // function can read past `scan_len` if a multi-byte character start within the // range but extends past it. The overflow is returned by the function. From 28503d69ac204ff208d115aea30dc09d6fca8728 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 14 Jul 2024 14:27:57 -0400 Subject: [PATCH 160/734] Fix unsafe_op_in_unsafe_fn in compiler --- compiler/rustc_abi/src/lib.rs | 4 +- compiler/rustc_codegen_llvm/src/allocator.rs | 48 ++-- compiler/rustc_codegen_llvm/src/back/lto.rs | 16 +- .../rustc_codegen_llvm/src/back/profiling.rs | 12 +- compiler/rustc_codegen_llvm/src/back/write.rs | 220 ++++++++------- compiler/rustc_codegen_llvm/src/context.rs | 259 ++++++++++-------- compiler/rustc_codegen_llvm/src/lib.rs | 6 +- .../rustc_codegen_llvm/src/llvm/diagnostic.rs | 83 +++--- compiler/rustc_codegen_llvm/src/llvm_util.rs | 16 +- compiler/rustc_codegen_llvm/src/mono_item.rs | 8 +- compiler/rustc_codegen_ssa/src/back/lto.rs | 2 +- compiler/rustc_llvm/src/lib.rs | 2 +- compiler/rustc_middle/src/ty/context/tls.rs | 2 +- .../rustc_span/src/analyze_source_file.rs | 18 +- src/bootstrap/src/core/builder.rs | 1 + 15 files changed, 386 insertions(+), 311 deletions(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 78332d66f036..52ec41f643c0 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -627,7 +627,7 @@ impl Step for Size { #[inline] unsafe fn forward_unchecked(start: Self, count: usize) -> Self { - Self::from_bytes(u64::forward_unchecked(start.bytes(), count)) + Self::from_bytes(unsafe { u64::forward_unchecked(start.bytes(), count) }) } #[inline] @@ -642,7 +642,7 @@ impl Step for Size { #[inline] unsafe fn backward_unchecked(start: Self, count: usize) -> Self { - Self::from_bytes(u64::backward_unchecked(start.bytes(), count)) + Self::from_bytes(unsafe { u64::backward_unchecked(start.bytes(), count) }) } } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index ca3760297354..5969d9b91440 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -21,14 +21,16 @@ pub(crate) unsafe fn codegen( ) { let llcx = &*module_llvm.llcx; let llmod = module_llvm.llmod(); - let usize = match tcx.sess.target.pointer_width { - 16 => llvm::LLVMInt16TypeInContext(llcx), - 32 => llvm::LLVMInt32TypeInContext(llcx), - 64 => llvm::LLVMInt64TypeInContext(llcx), - tws => bug!("Unsupported target word size for int: {}", tws), + let usize = unsafe { + match tcx.sess.target.pointer_width { + 16 => llvm::LLVMInt16TypeInContext(llcx), + 32 => llvm::LLVMInt32TypeInContext(llcx), + 64 => llvm::LLVMInt64TypeInContext(llcx), + tws => bug!("Unsupported target word size for int: {}", tws), + } }; - let i8 = llvm::LLVMInt8TypeInContext(llcx); - let i8p = llvm::LLVMPointerTypeInContext(llcx, 0); + let i8 = unsafe { llvm::LLVMInt8TypeInContext(llcx) }; + let i8p = unsafe { llvm::LLVMPointerTypeInContext(llcx, 0) }; if kind == AllocatorKind::Default { for method in ALLOCATOR_METHODS { @@ -73,23 +75,25 @@ pub(crate) unsafe fn codegen( true, ); - // __rust_alloc_error_handler_should_panic - let name = OomStrategy::SYMBOL; - let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); - if tcx.sess.default_hidden_visibility() { - llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden); - } - let val = tcx.sess.opts.unstable_opts.oom.should_panic(); - let llval = llvm::LLVMConstInt(i8, val as u64, False); - llvm::LLVMSetInitializer(ll_g, llval); + unsafe { + // __rust_alloc_error_handler_should_panic + let name = OomStrategy::SYMBOL; + let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); + if tcx.sess.default_hidden_visibility() { + llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden); + } + let val = tcx.sess.opts.unstable_opts.oom.should_panic(); + let llval = llvm::LLVMConstInt(i8, val as u64, False); + llvm::LLVMSetInitializer(ll_g, llval); - let name = NO_ALLOC_SHIM_IS_UNSTABLE; - let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); - if tcx.sess.default_hidden_visibility() { - llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden); + let name = NO_ALLOC_SHIM_IS_UNSTABLE; + let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); + if tcx.sess.default_hidden_visibility() { + llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden); + } + let llval = llvm::LLVMConstInt(i8, 0, False); + llvm::LLVMSetInitializer(ll_g, llval); } - let llval = llvm::LLVMConstInt(i8, 0, False); - llvm::LLVMSetInitializer(ll_g, llval); if tcx.sess.opts.debuginfo != DebugInfo::None { let dbg_cx = debuginfo::CodegenUnitDebugContext::new(llmod); diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index aff3e3d70760..aef672631c81 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -727,7 +727,7 @@ pub unsafe fn optimize_thin_module( // into that context. One day, however, we may do this for upstream // crates but for locally codegened modules we may be able to reuse // that LLVM Context and Module. - let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); + let llcx = unsafe { llvm::LLVMRustContextCreate(cgcx.fewer_names) }; let llmod_raw = parse_module(llcx, module_name, thin_module.data(), dcx)? as *const _; let mut module = ModuleCodegen { module_llvm: ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) }, @@ -750,7 +750,9 @@ pub unsafe fn optimize_thin_module( { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name()); - if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) { + if unsafe { + !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) + } { return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); } save_temp_bitcode(cgcx, &module, "thin-lto-after-rename"); @@ -760,7 +762,8 @@ pub unsafe fn optimize_thin_module( let _timer = cgcx .prof .generic_activity_with_arg("LLVM_thin_lto_resolve_weak", thin_module.name()); - if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) { + if unsafe { !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) } + { return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); } save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve"); @@ -770,7 +773,8 @@ pub unsafe fn optimize_thin_module( let _timer = cgcx .prof .generic_activity_with_arg("LLVM_thin_lto_internalize", thin_module.name()); - if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) { + if unsafe { !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) } + { return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); } save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize"); @@ -779,7 +783,9 @@ pub unsafe fn optimize_thin_module( { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_import", thin_module.name()); - if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target) { + if unsafe { + !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target) + } { return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); } save_temp_bitcode(cgcx, &module, "thin-lto-after-import"); diff --git a/compiler/rustc_codegen_llvm/src/back/profiling.rs b/compiler/rustc_codegen_llvm/src/back/profiling.rs index 2741f7d848e7..2eee9f8c5a3e 100644 --- a/compiler/rustc_codegen_llvm/src/back/profiling.rs +++ b/compiler/rustc_codegen_llvm/src/back/profiling.rs @@ -46,13 +46,15 @@ pub unsafe extern "C" fn selfprofile_before_pass_callback( pass_name: *const c_char, ir_name: *const c_char, ) { - let llvm_self_profiler = &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>); - let pass_name = CStr::from_ptr(pass_name).to_str().expect("valid UTF-8"); - let ir_name = CStr::from_ptr(ir_name).to_str().expect("valid UTF-8"); - llvm_self_profiler.before_pass_callback(pass_name, ir_name); + unsafe { + let llvm_self_profiler = &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>); + let pass_name = CStr::from_ptr(pass_name).to_str().expect("valid UTF-8"); + let ir_name = CStr::from_ptr(ir_name).to_str().expect("valid UTF-8"); + llvm_self_profiler.before_pass_callback(pass_name, ir_name); + } } pub unsafe extern "C" fn selfprofile_after_pass_callback(llvm_self_profiler: *mut c_void) { - let llvm_self_profiler = &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>); + let llvm_self_profiler = unsafe { &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>) }; llvm_self_profiler.after_pass_callback(); } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 2fda19bf0c91..ddd52e80edff 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -428,9 +428,10 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void if user.is_null() { return; } - let (cgcx, dcx) = *(user as *const (&CodegenContext, DiagCtxtHandle<'_>)); + let (cgcx, dcx) = + unsafe { *(user as *const (&CodegenContext, DiagCtxtHandle<'_>)) }; - match llvm::diagnostic::Diagnostic::unpack(info) { + match unsafe { llvm::diagnostic::Diagnostic::unpack(info) } { llvm::diagnostic::InlineAsm(inline) => { report_inline_asm(cgcx, inline.message, inline.level, inline.cookie, inline.source); } @@ -454,14 +455,14 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void }); } llvm::diagnostic::PGO(diagnostic_ref) | llvm::diagnostic::Linker(diagnostic_ref) => { - let message = llvm::build_string(|s| { + let message = llvm::build_string(|s| unsafe { llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) }) .expect("non-UTF8 diagnostic"); dcx.emit_warn(FromLlvmDiag { message }); } llvm::diagnostic::Unsupported(diagnostic_ref) => { - let message = llvm::build_string(|s| { + let message = llvm::build_string(|s| unsafe { llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) }) .expect("non-UTF8 diagnostic"); @@ -564,37 +565,39 @@ pub(crate) unsafe fn llvm_optimize( let llvm_plugins = config.llvm_plugins.join(","); - let result = llvm::LLVMRustOptimize( - module.module_llvm.llmod(), - &*module.module_llvm.tm, - to_pass_builder_opt_level(opt_level), - opt_stage, - cgcx.opts.cg.linker_plugin_lto.enabled(), - config.no_prepopulate_passes, - config.verify_llvm_ir, - using_thin_buffers, - config.merge_functions, - unroll_loops, - config.vectorize_slp, - config.vectorize_loop, - config.no_builtins, - config.emit_lifetime_markers, - sanitizer_options.as_ref(), - pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), - pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), - config.instrument_coverage, - instr_profile_output_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), - config.instrument_gcov, - pgo_sample_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), - config.debug_info_for_profiling, - llvm_selfprofiler, - selfprofile_before_pass_callback, - selfprofile_after_pass_callback, - extra_passes.as_ptr().cast(), - extra_passes.len(), - llvm_plugins.as_ptr().cast(), - llvm_plugins.len(), - ); + let result = unsafe { + llvm::LLVMRustOptimize( + module.module_llvm.llmod(), + &*module.module_llvm.tm, + to_pass_builder_opt_level(opt_level), + opt_stage, + cgcx.opts.cg.linker_plugin_lto.enabled(), + config.no_prepopulate_passes, + config.verify_llvm_ir, + using_thin_buffers, + config.merge_functions, + unroll_loops, + config.vectorize_slp, + config.vectorize_loop, + config.no_builtins, + config.emit_lifetime_markers, + sanitizer_options.as_ref(), + pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), + pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), + config.instrument_coverage, + instr_profile_output_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), + config.instrument_gcov, + pgo_sample_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), + config.debug_info_for_profiling, + llvm_selfprofiler, + selfprofile_before_pass_callback, + selfprofile_after_pass_callback, + extra_passes.as_ptr().cast(), + extra_passes.len(), + llvm_plugins.as_ptr().cast(), + llvm_plugins.len(), + ) + }; result.into_result().map_err(|()| llvm_err(dcx, LlvmError::RunLlvmPasses)) } @@ -617,7 +620,7 @@ pub(crate) unsafe fn optimize( if config.emit_no_opt_bc { let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name); let out = path_to_c_string(&out); - llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); + unsafe { llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()) }; } if let Some(opt_level) = config.opt_level { @@ -627,7 +630,7 @@ pub(crate) unsafe fn optimize( _ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO, _ => llvm::OptStage::PreLinkNoLTO, }; - return llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage); + return unsafe { llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage) }; } Ok(()) } @@ -692,10 +695,12 @@ pub(crate) unsafe fn codegen( where F: FnOnce(&'ll mut PassManager<'ll>) -> R, { - let cpm = llvm::LLVMCreatePassManager(); - llvm::LLVMAddAnalysisPasses(tm, cpm); - llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); - f(cpm) + unsafe { + let cpm = llvm::LLVMCreatePassManager(); + llvm::LLVMAddAnalysisPasses(tm, cpm); + llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); + f(cpm) + } } // Two things to note: @@ -757,7 +762,9 @@ pub(crate) unsafe fn codegen( let _timer = cgcx .prof .generic_activity_with_arg("LLVM_module_codegen_embed_bitcode", &*module.name); - embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data); + unsafe { + embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data); + } } } @@ -793,7 +800,8 @@ pub(crate) unsafe fn codegen( cursor.position() as size_t } - let result = llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback); + let result = + unsafe { llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback) }; if result == llvm::LLVMRustResult::Success { record_artifact_size(&cgcx.prof, "llvm_ir", &out); @@ -812,22 +820,24 @@ pub(crate) unsafe fn codegen( // binaries. So we must clone the module to produce the asm output // if we are also producing object code. let llmod = if let EmitObj::ObjectCode(_) = config.emit_obj { - llvm::LLVMCloneModule(llmod) + unsafe { llvm::LLVMCloneModule(llmod) } } else { llmod }; - with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file( - dcx, - tm, - cpm, - llmod, - &path, - None, - llvm::FileType::AssemblyFile, - &cgcx.prof, - ) - })?; + unsafe { + with_codegen(tm, llmod, config.no_builtins, |cpm| { + write_output_file( + dcx, + tm, + cpm, + llmod, + &path, + None, + llvm::FileType::AssemblyFile, + &cgcx.prof, + ) + })?; + } } match config.emit_obj { @@ -851,18 +861,20 @@ pub(crate) unsafe fn codegen( (_, SplitDwarfKind::Split) => Some(dwo_out.as_path()), }; - with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file( - dcx, - tm, - cpm, - llmod, - &obj_out, - dwo_out, - llvm::FileType::ObjectFile, - &cgcx.prof, - ) - })?; + unsafe { + with_codegen(tm, llmod, config.no_builtins, |cpm| { + write_output_file( + dcx, + tm, + cpm, + llmod, + &obj_out, + dwo_out, + llvm::FileType::ObjectFile, + &cgcx.prof, + ) + })?; + } } EmitObj::Bitcode => { @@ -1013,44 +1025,46 @@ unsafe fn embed_bitcode( // reason (see issue #90326 for historical background). let is_aix = target_is_aix(cgcx); let is_apple = target_is_apple(cgcx); - if is_apple || is_aix || cgcx.opts.target_triple.triple().starts_with("wasm") { - // We don't need custom section flags, create LLVM globals. - let llconst = common::bytes_in_context(llcx, bitcode); - let llglobal = llvm::LLVMAddGlobal( - llmod, - common::val_ty(llconst), - c"rustc.embedded.module".as_ptr().cast(), - ); - llvm::LLVMSetInitializer(llglobal, llconst); + unsafe { + if is_apple || is_aix || cgcx.opts.target_triple.triple().starts_with("wasm") { + // We don't need custom section flags, create LLVM globals. + let llconst = common::bytes_in_context(llcx, bitcode); + let llglobal = llvm::LLVMAddGlobal( + llmod, + common::val_ty(llconst), + c"rustc.embedded.module".as_ptr().cast(), + ); + llvm::LLVMSetInitializer(llglobal, llconst); - let section = bitcode_section_name(cgcx); - llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); - llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); - llvm::LLVMSetGlobalConstant(llglobal, llvm::True); + let section = bitcode_section_name(cgcx); + llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); + llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::LLVMSetGlobalConstant(llglobal, llvm::True); - let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); - let llglobal = llvm::LLVMAddGlobal( - llmod, - common::val_ty(llconst), - c"rustc.embedded.cmdline".as_ptr().cast(), - ); - llvm::LLVMSetInitializer(llglobal, llconst); - let section = if is_apple { - c"__LLVM,__cmdline" - } else if is_aix { - c".info" + let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); + let llglobal = llvm::LLVMAddGlobal( + llmod, + common::val_ty(llconst), + c"rustc.embedded.cmdline".as_ptr().cast(), + ); + llvm::LLVMSetInitializer(llglobal, llconst); + let section = if is_apple { + c"__LLVM,__cmdline" + } else if is_aix { + c".info" + } else { + c".llvmcmd" + }; + llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); + llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); } else { - c".llvmcmd" - }; - llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); - llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); - } else { - // We need custom section flags, so emit module-level inline assembly. - let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; - let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); - llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); - let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); - llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); + // We need custom section flags, so emit module-level inline assembly. + let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; + let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); + llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); + let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); + llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); + } } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 77beb9a6bb38..49677dcf12f7 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -120,7 +120,7 @@ pub unsafe fn create_module<'ll>( ) -> &'ll llvm::Module { let sess = tcx.sess; let mod_name = SmallCStr::new(mod_name); - let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); + let llmod = unsafe { llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx) }; let mut target_data_layout = sess.target.data_layout.to_string(); let llvm_version = llvm_util::get_version(); @@ -153,11 +153,14 @@ pub unsafe fn create_module<'ll>( // Ensure the data-layout values hardcoded remain the defaults. { let tm = crate::back::write::create_informational_target_machine(tcx.sess); - llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm); + unsafe { + llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm); + } - let llvm_data_layout = llvm::LLVMGetDataLayoutStr(llmod); - let llvm_data_layout = str::from_utf8(CStr::from_ptr(llvm_data_layout).to_bytes()) - .expect("got a non-UTF8 data-layout from LLVM"); + let llvm_data_layout = unsafe { llvm::LLVMGetDataLayoutStr(llmod) }; + let llvm_data_layout = + str::from_utf8(unsafe { CStr::from_ptr(llvm_data_layout) }.to_bytes()) + .expect("got a non-UTF8 data-layout from LLVM"); if target_data_layout != llvm_data_layout { tcx.dcx().emit_err(crate::errors::MismatchedDataLayout { @@ -170,20 +173,28 @@ pub unsafe fn create_module<'ll>( } let data_layout = SmallCStr::new(&target_data_layout); - llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr()); + unsafe { + llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr()); + } let llvm_target = SmallCStr::new(&sess.target.llvm_target); - llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); + unsafe { + llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); + } let reloc_model = sess.relocation_model(); if matches!(reloc_model, RelocModel::Pic | RelocModel::Pie) { - llvm::LLVMRustSetModulePICLevel(llmod); + unsafe { + llvm::LLVMRustSetModulePICLevel(llmod); + } // PIE is potentially more effective than PIC, but can only be used in executables. // If all our outputs are executables, then we can relax PIC to PIE. if reloc_model == RelocModel::Pie || tcx.crate_types().iter().all(|ty| *ty == CrateType::Executable) { - llvm::LLVMRustSetModulePIELevel(llmod); + unsafe { + llvm::LLVMRustSetModulePIELevel(llmod); + } } } @@ -192,95 +203,109 @@ pub unsafe fn create_module<'ll>( // longer jumps) if a larger code model is used with a smaller one. // // See https://reviews.llvm.org/D52322 and https://reviews.llvm.org/D52323. - llvm::LLVMRustSetModuleCodeModel(llmod, to_llvm_code_model(sess.code_model())); + unsafe { + llvm::LLVMRustSetModuleCodeModel(llmod, to_llvm_code_model(sess.code_model())); + } // If skipping the PLT is enabled, we need to add some module metadata // to ensure intrinsic calls don't use it. if !sess.needs_plt() { let avoid_plt = c"RtLibUseGOT".as_ptr().cast(); - llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1); + unsafe { + llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1); + } } // Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.) if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() { let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr().cast(); - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - canonical_jump_tables, - 1, - ); + unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Override, + canonical_jump_tables, + 1, + ); + } } // Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.) if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() { let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr().cast(); - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - enable_split_lto_unit, - 1, - ); + unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Override, + enable_split_lto_unit, + 1, + ); + } } // Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.) if sess.is_sanitizer_kcfi_enabled() { let kcfi = c"kcfi".as_ptr().cast(); - llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1); + unsafe { + llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1); + } } // Control Flow Guard is currently only supported by the MSVC linker on Windows. if sess.target.is_like_msvc { - match sess.opts.cg.control_flow_guard { - CFGuard::Disabled => {} - CFGuard::NoChecks => { - // Set `cfguard=1` module flag to emit metadata only. - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Warning, - c"cfguard".as_ptr() as *const _, - 1, - ) - } - CFGuard::Checks => { - // Set `cfguard=2` module flag to emit metadata and checks. - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Warning, - c"cfguard".as_ptr() as *const _, - 2, - ) + unsafe { + match sess.opts.cg.control_flow_guard { + CFGuard::Disabled => {} + CFGuard::NoChecks => { + // Set `cfguard=1` module flag to emit metadata only. + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Warning, + c"cfguard".as_ptr() as *const _, + 1, + ) + } + CFGuard::Checks => { + // Set `cfguard=2` module flag to emit metadata and checks. + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Warning, + c"cfguard".as_ptr() as *const _, + 2, + ) + } } } } if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection { if sess.target.arch == "aarch64" { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Min, - c"branch-target-enforcement".as_ptr().cast(), - bti.into(), - ); - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Min, - c"sign-return-address".as_ptr().cast(), - pac_ret.is_some().into(), - ); - let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A }); - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Min, - c"sign-return-address-all".as_ptr().cast(), - pac_opts.leaf.into(), - ); - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Min, - c"sign-return-address-with-bkey".as_ptr().cast(), - u32::from(pac_opts.key == PAuthKey::B), - ); + unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Min, + c"branch-target-enforcement".as_ptr().cast(), + bti.into(), + ); + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Min, + c"sign-return-address".as_ptr().cast(), + pac_ret.is_some().into(), + ); + let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A }); + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Min, + c"sign-return-address-all".as_ptr().cast(), + pac_opts.leaf.into(), + ); + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Min, + c"sign-return-address-with-bkey".as_ptr().cast(), + u32::from(pac_opts.key == PAuthKey::B), + ); + } } else { bug!( "branch-protection used on non-AArch64 target; \ @@ -291,39 +316,47 @@ pub unsafe fn create_module<'ll>( // Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang). if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - c"cf-protection-branch".as_ptr().cast(), - 1, - ) + unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Override, + c"cf-protection-branch".as_ptr().cast(), + 1, + ); + } } if let CFProtection::Return | CFProtection::Full = sess.opts.unstable_opts.cf_protection { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - c"cf-protection-return".as_ptr().cast(), - 1, - ) + unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Override, + c"cf-protection-return".as_ptr().cast(), + 1, + ); + } } if sess.opts.unstable_opts.virtual_function_elimination { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Error, - c"Virtual Function Elim".as_ptr().cast(), - 1, - ); + unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Error, + c"Virtual Function Elim".as_ptr().cast(), + 1, + ); + } } // Set module flag to enable Windows EHCont Guard (/guard:ehcont). if sess.opts.unstable_opts.ehcont_guard { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Warning, - c"ehcontguard".as_ptr() as *const _, - 1, - ) + unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Warning, + c"ehcontguard".as_ptr() as *const _, + 1, + ) + } } // Insert `llvm.ident` metadata. @@ -333,16 +366,20 @@ pub unsafe fn create_module<'ll>( #[allow(clippy::option_env_unwrap)] let rustc_producer = format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); - let name_metadata = llvm::LLVMMDStringInContext( - llcx, - rustc_producer.as_ptr().cast(), - rustc_producer.as_bytes().len() as c_uint, - ); - llvm::LLVMAddNamedMetadataOperand( - llmod, - c"llvm.ident".as_ptr(), - llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1), - ); + let name_metadata = unsafe { + llvm::LLVMMDStringInContext( + llcx, + rustc_producer.as_ptr().cast(), + rustc_producer.as_bytes().len() as c_uint, + ) + }; + unsafe { + llvm::LLVMAddNamedMetadataOperand( + llmod, + c"llvm.ident".as_ptr(), + llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1), + ); + } // Emit RISC-V specific target-abi metadata // to workaround lld as the LTO plugin not @@ -351,13 +388,15 @@ pub unsafe fn create_module<'ll>( // If llvm_abiname is empty, emit nothing. let llvm_abiname = &sess.target.options.llvm_abiname; if matches!(sess.target.arch.as_ref(), "riscv32" | "riscv64") && !llvm_abiname.is_empty() { - llvm::LLVMRustAddModuleFlagString( - llmod, - llvm::LLVMModFlagBehavior::Error, - c"target-abi".as_ptr(), - llvm_abiname.as_ptr().cast(), - llvm_abiname.len(), - ); + unsafe { + llvm::LLVMRustAddModuleFlagString( + llmod, + llvm::LLVMModFlagBehavior::Error, + c"target-abi".as_ptr(), + llvm_abiname.as_ptr().cast(), + llvm_abiname.len(), + ); + } } // Add module flags specified via -Z llvm_module_flag @@ -375,7 +414,7 @@ pub unsafe fn create_module<'ll>( // We already checked this during option parsing _ => unreachable!(), }; - llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value) + unsafe { llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value) } } llmod diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index ed0989a0ba41..a96993b9aba7 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -216,7 +216,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { module: &ModuleCodegen, config: &ModuleConfig, ) -> Result<(), FatalError> { - back::write::optimize(cgcx, dcx, module, config) + unsafe { back::write::optimize(cgcx, dcx, module, config) } } fn optimize_fat( cgcx: &CodegenContext, @@ -230,7 +230,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { cgcx: &CodegenContext, thin: ThinModule, ) -> Result, FatalError> { - back::lto::optimize_thin_module(thin, cgcx) + unsafe { back::lto::optimize_thin_module(thin, cgcx) } } unsafe fn codegen( cgcx: &CodegenContext, @@ -238,7 +238,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { module: ModuleCodegen, config: &ModuleConfig, ) -> Result { - back::write::codegen(cgcx, dcx, module, config) + unsafe { back::write::codegen(cgcx, dcx, module, config) } } fn prepare_thin( module: ModuleCodegen, diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs index f9b28178ddb9..73e1b08a3d77 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs @@ -40,7 +40,7 @@ impl<'ll> OptimizationDiagnostic<'ll> { let mut filename = None; let pass_name = super::build_string(|pass_name| { message = super::build_string(|message| { - filename = super::build_string(|filename| { + filename = super::build_string(|filename| unsafe { super::LLVMRustUnpackOptimizationDiagnostic( di, pass_name, @@ -91,7 +91,7 @@ impl SrcMgrDiagnostic { let mut ranges = [0; 8]; let mut num_ranges = ranges.len() / 2; let message = super::build_string(|message| { - buffer = super::build_string(|buffer| { + buffer = super::build_string(|buffer| unsafe { have_source = super::LLVMRustUnpackSMDiagnostic( diag, message, @@ -134,7 +134,9 @@ impl InlineAsmDiagnostic { let mut message = None; let mut level = super::DiagnosticLevel::Error; - super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut level, &mut cookie, &mut message); + unsafe { + super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut level, &mut cookie, &mut message); + } InlineAsmDiagnostic { level, @@ -146,7 +148,8 @@ impl InlineAsmDiagnostic { unsafe fn unpackSrcMgr(di: &DiagnosticInfo) -> Self { let mut cookie = 0; - let smdiag = SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie)); + let smdiag = + unsafe { SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie)) }; InlineAsmDiagnostic { level: smdiag.level, cookie: cookie.into(), @@ -170,44 +173,46 @@ pub enum Diagnostic<'ll> { impl<'ll> Diagnostic<'ll> { pub unsafe fn unpack(di: &'ll DiagnosticInfo) -> Self { use super::DiagnosticKind as Dk; - let kind = super::LLVMRustGetDiagInfoKind(di); - match kind { - Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpackInlineAsm(di)), + unsafe { + let kind = super::LLVMRustGetDiagInfoKind(di); + match kind { + Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpackInlineAsm(di)), - Dk::OptimizationRemark => { - Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di)) + Dk::OptimizationRemark => { + Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di)) + } + Dk::OptimizationRemarkOther => { + Optimization(OptimizationDiagnostic::unpack(OptimizationRemarkOther, di)) + } + Dk::OptimizationRemarkMissed => { + Optimization(OptimizationDiagnostic::unpack(OptimizationMissed, di)) + } + + Dk::OptimizationRemarkAnalysis => { + Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysis, di)) + } + + Dk::OptimizationRemarkAnalysisFPCommute => { + Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisFPCommute, di)) + } + + Dk::OptimizationRemarkAnalysisAliasing => { + Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisAliasing, di)) + } + + Dk::OptimizationFailure => { + Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di)) + } + + Dk::PGOProfile => PGO(di), + Dk::Linker => Linker(di), + Dk::Unsupported => Unsupported(di), + + Dk::SrcMgr => InlineAsm(InlineAsmDiagnostic::unpackSrcMgr(di)), + + _ => UnknownDiagnostic(di), } - Dk::OptimizationRemarkOther => { - Optimization(OptimizationDiagnostic::unpack(OptimizationRemarkOther, di)) - } - Dk::OptimizationRemarkMissed => { - Optimization(OptimizationDiagnostic::unpack(OptimizationMissed, di)) - } - - Dk::OptimizationRemarkAnalysis => { - Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysis, di)) - } - - Dk::OptimizationRemarkAnalysisFPCommute => { - Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisFPCommute, di)) - } - - Dk::OptimizationRemarkAnalysisAliasing => { - Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisAliasing, di)) - } - - Dk::OptimizationFailure => { - Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di)) - } - - Dk::PGOProfile => PGO(di), - Dk::Linker => Linker(di), - Dk::Unsupported => Unsupported(di), - - Dk::SrcMgr => InlineAsm(InlineAsmDiagnostic::unpackSrcMgr(di)), - - _ => UnknownDiagnostic(di), } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 0e89e66be49a..98dc8ac86d2b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -49,12 +49,16 @@ unsafe fn configure_llvm(sess: &Session) { let mut llvm_c_strs = Vec::with_capacity(n_args + 1); let mut llvm_args = Vec::with_capacity(n_args + 1); - llvm::LLVMRustInstallErrorHandlers(); + unsafe { + llvm::LLVMRustInstallErrorHandlers(); + } // On Windows, an LLVM assertion will open an Abort/Retry/Ignore dialog // box for the purpose of launching a debugger. However, on CI this will // cause it to hang until it times out, which can take several hours. if std::env::var_os("CI").is_some() { - llvm::LLVMRustDisableSystemDialogsOnCrash(); + unsafe { + llvm::LLVMRustDisableSystemDialogsOnCrash(); + } } fn llvm_arg_to_arg_name(full_arg: &str) -> &str { @@ -124,12 +128,12 @@ unsafe fn configure_llvm(sess: &Session) { } if sess.opts.unstable_opts.llvm_time_trace { - llvm::LLVMRustTimeTraceProfilerInitialize(); + unsafe { llvm::LLVMRustTimeTraceProfilerInitialize() }; } rustc_llvm::initialize_available_targets(); - llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr()); + unsafe { llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr()) }; } pub fn time_trace_profiler_finish(file_name: &Path) { @@ -442,8 +446,8 @@ pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) { let cpu_cstring = CString::new(handle_native(sess.target.cpu.as_ref())) .unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e)); unsafe extern "C" fn callback(out: *mut c_void, string: *const c_char, len: usize) { - let out = &mut *(out as *mut &mut String); - let bytes = slice::from_raw_parts(string as *const u8, len); + let out = unsafe { &mut *(out as *mut &mut String) }; + let bytes = unsafe { slice::from_raw_parts(string as *const u8, len) }; write!(out, "{}", String::from_utf8_lossy(bytes)).unwrap(); } unsafe { diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index a7df08421a31..282a186be99a 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -108,8 +108,8 @@ impl CodegenCx<'_, '_> { llval: &llvm::Value, is_declaration: bool, ) -> bool { - let linkage = llvm::LLVMRustGetLinkage(llval); - let visibility = llvm::LLVMRustGetVisibility(llval); + let linkage = unsafe { llvm::LLVMRustGetLinkage(llval) }; + let visibility = unsafe { llvm::LLVMRustGetVisibility(llval) }; if matches!(linkage, llvm::Linkage::InternalLinkage | llvm::Linkage::PrivateLinkage) { return true; @@ -145,8 +145,8 @@ impl CodegenCx<'_, '_> { } // Thread-local variables generally don't support copy relocations. - let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval) - .is_some_and(|v| llvm::LLVMIsThreadLocal(v) == llvm::True); + let is_thread_local_var = unsafe { llvm::LLVMIsAGlobalVariable(llval) } + .is_some_and(|v| unsafe { llvm::LLVMIsThreadLocal(v) } == llvm::True); if is_thread_local_var { return false; } diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs index cb6244050df2..5291cad148e2 100644 --- a/compiler/rustc_codegen_ssa/src/back/lto.rs +++ b/compiler/rustc_codegen_ssa/src/back/lto.rs @@ -72,7 +72,7 @@ impl LtoModuleCodegen { B::optimize_fat(cgcx, &mut module)?; Ok(module) } - LtoModuleCodegen::Thin(thin) => B::optimize_thin(cgcx, thin), + LtoModuleCodegen::Thin(thin) => unsafe { B::optimize_thin(cgcx, thin) }, } } diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index e5366c9b5183..1365afbce1c3 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -33,7 +33,7 @@ pub unsafe extern "C" fn LLVMRustStringWriteImpl( ptr: *const c_char, size: size_t, ) { - let slice = slice::from_raw_parts(ptr as *const u8, size); + let slice = unsafe { slice::from_raw_parts(ptr as *const u8, size) }; sr.bytes.borrow_mut().extend_from_slice(slice); } diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs index 5e256dc8d26e..7b5ccae35682 100644 --- a/compiler/rustc_middle/src/ty/context/tls.rs +++ b/compiler/rustc_middle/src/ty/context/tls.rs @@ -67,7 +67,7 @@ fn erase(context: &ImplicitCtxt<'_, '_>) -> *const () { #[inline] unsafe fn downcast<'a, 'tcx>(context: *const ()) -> &'a ImplicitCtxt<'a, 'tcx> { - &*(context as *const ImplicitCtxt<'a, 'tcx>) + unsafe { &*(context as *const ImplicitCtxt<'a, 'tcx>) } } /// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`. diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index 80c5c3bf1b5a..d9e1ebaf0bce 100644 --- a/compiler/rustc_span/src/analyze_source_file.rs +++ b/compiler/rustc_span/src/analyze_source_file.rs @@ -89,13 +89,13 @@ cfg_match! { let ptr = src_bytes.as_ptr() as *const __m128i; // We don't know if the pointer is aligned to 16 bytes, so we // use `loadu`, which supports unaligned loading. - let chunk = _mm_loadu_si128(ptr.add(chunk_index)); + let chunk = unsafe { _mm_loadu_si128(ptr.add(chunk_index)) }; // For character in the chunk, see if its byte value is < 0, which // indicates that it's part of a UTF-8 char. - let multibyte_test = _mm_cmplt_epi8(chunk, _mm_set1_epi8(0)); + let multibyte_test = unsafe { _mm_cmplt_epi8(chunk, _mm_set1_epi8(0)) }; // Create a bit mask from the comparison results. - let multibyte_mask = _mm_movemask_epi8(multibyte_test); + let multibyte_mask = unsafe { _mm_movemask_epi8(multibyte_test) }; // If the bit mask is all zero, we only have ASCII chars here: if multibyte_mask == 0 { @@ -104,19 +104,19 @@ cfg_match! { // Check if there are any control characters in the chunk. All // control characters that we can encounter at this point have a // byte value less than 32 or ... - let control_char_test0 = _mm_cmplt_epi8(chunk, _mm_set1_epi8(32)); - let control_char_mask0 = _mm_movemask_epi8(control_char_test0); + let control_char_test0 = unsafe { _mm_cmplt_epi8(chunk, _mm_set1_epi8(32)) }; + let control_char_mask0 = unsafe { _mm_movemask_epi8(control_char_test0) }; // ... it's the ASCII 'DEL' character with a value of 127. - let control_char_test1 = _mm_cmpeq_epi8(chunk, _mm_set1_epi8(127)); - let control_char_mask1 = _mm_movemask_epi8(control_char_test1); + let control_char_test1 = unsafe { _mm_cmpeq_epi8(chunk, _mm_set1_epi8(127)) }; + let control_char_mask1 = unsafe { _mm_movemask_epi8(control_char_test1) }; let control_char_mask = control_char_mask0 | control_char_mask1; if control_char_mask != 0 { // Check for newlines in the chunk - let newlines_test = _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\n' as i8)); - let newlines_mask = _mm_movemask_epi8(newlines_test); + let newlines_test = unsafe { _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\n' as i8)) }; + let newlines_mask = unsafe { _mm_movemask_epi8(newlines_test) }; if control_char_mask == newlines_mask { // All control characters are newlines, record them diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index f033905e9f62..604fd8e19908 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -2001,6 +2001,7 @@ impl<'a> Builder<'a> { // FIXME(edition_2024): Change this to `-Wrust_2024_idioms` when all // of the individual lints are satisfied. rustflags.arg("-Wkeyword_idents_2024"); + rustflags.arg("-Wunsafe_op_in_unsafe_fn"); } if self.config.rust_frame_pointers { From 2f305ff460862e18b67db2faa11b85ab223d4e60 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Jul 2024 15:02:19 +1000 Subject: [PATCH 161/734] Remove an unnecessary `?`. --- compiler/rustc_parse/src/parser/item.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index d2fea5583b81..994e7c5d2db5 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -128,14 +128,10 @@ impl<'a> Parser<'a> { Some(item.into_inner()) }); - let item = - self.collect_tokens_trailing_token(attrs, force_collect, |this: &mut Self, attrs| { - let item = - this.parse_item_common_(attrs, mac_allowed, attrs_allowed, fn_parse_mode); - Ok((item?, TrailingToken::None)) - })?; - - Ok(item) + self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| { + let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, fn_parse_mode)?; + Ok((item, TrailingToken::None)) + }) } fn parse_item_common_( From 48cdfc388d67a6bde420d8d44eddf8ef1e5b7eb2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Jul 2024 15:07:42 +1000 Subject: [PATCH 162/734] Inline `Parser::parse_item_common_`. It has a single call site, it isn't that big, and its name is confusingly similar to `Parser::parse_item_common`. --- compiler/rustc_parse/src/parser/item.rs | 79 +++++++++++-------------- 1 file changed, 34 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 994e7c5d2db5..2d5781c3bbfb 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -128,54 +128,43 @@ impl<'a> Parser<'a> { Some(item.into_inner()) }); - self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| { - let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, fn_parse_mode)?; - Ok((item, TrailingToken::None)) + self.collect_tokens_trailing_token(attrs, force_collect, |this, mut attrs| { + let lo = this.token.span; + let vis = this.parse_visibility(FollowedByType::No)?; + let mut def = this.parse_defaultness(); + let kind = this.parse_item_kind( + &mut attrs, + mac_allowed, + lo, + &vis, + &mut def, + fn_parse_mode, + Case::Sensitive, + )?; + if let Some((ident, kind)) = kind { + this.error_on_unconsumed_default(def, &kind); + let span = lo.to(this.prev_token.span); + let id = DUMMY_NODE_ID; + let item = Item { ident, attrs, id, kind, vis, span, tokens: None }; + return Ok((Some(item), TrailingToken::None)); + } + + // At this point, we have failed to parse an item. + if !matches!(vis.kind, VisibilityKind::Inherited) { + this.dcx().emit_err(errors::VisibilityNotFollowedByItem { span: vis.span, vis }); + } + + if let Defaultness::Default(span) = def { + this.dcx().emit_err(errors::DefaultNotFollowedByItem { span }); + } + + if !attrs_allowed { + this.recover_attrs_no_item(&attrs)?; + } + Ok((None, TrailingToken::None)) }) } - fn parse_item_common_( - &mut self, - mut attrs: AttrVec, - mac_allowed: bool, - attrs_allowed: bool, - fn_parse_mode: FnParseMode, - ) -> PResult<'a, Option> { - let lo = self.token.span; - let vis = self.parse_visibility(FollowedByType::No)?; - let mut def = self.parse_defaultness(); - let kind = self.parse_item_kind( - &mut attrs, - mac_allowed, - lo, - &vis, - &mut def, - fn_parse_mode, - Case::Sensitive, - )?; - if let Some((ident, kind)) = kind { - self.error_on_unconsumed_default(def, &kind); - let span = lo.to(self.prev_token.span); - let id = DUMMY_NODE_ID; - let item = Item { ident, attrs, id, kind, vis, span, tokens: None }; - return Ok(Some(item)); - } - - // At this point, we have failed to parse an item. - if !matches!(vis.kind, VisibilityKind::Inherited) { - self.dcx().emit_err(errors::VisibilityNotFollowedByItem { span: vis.span, vis }); - } - - if let Defaultness::Default(span) = def { - self.dcx().emit_err(errors::DefaultNotFollowedByItem { span }); - } - - if !attrs_allowed { - self.recover_attrs_no_item(&attrs)?; - } - Ok(None) - } - /// Error in-case `default` was parsed in an in-appropriate context. fn error_on_unconsumed_default(&self, def: Defaultness, kind: &ItemKind) { if let Defaultness::Default(span) = def { From d247489ac280147b48c72ed739ea9056e0ca6ff2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Jul 2024 15:54:34 +1000 Subject: [PATCH 163/734] Reorder `Parser::parse_expr_dot_or_call_with` arguments. Put `attrs` before `e0` because that matches the order in the source code, where outer attributes appear before expressions. --- compiler/rustc_parse/src/parser/expr.rs | 4 ++-- compiler/rustc_parse/src/parser/pat.rs | 2 +- compiler/rustc_parse/src/parser/stmt.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index b2df9a14eb01..a1bb047e464f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -885,15 +885,15 @@ impl<'a> Parser<'a> { self.collect_tokens_for_expr(attrs, |this, attrs| { let base = this.parse_expr_bottom()?; let span = this.interpolated_or_expr_span(&base); - this.parse_expr_dot_or_call_with(base, span, attrs) + this.parse_expr_dot_or_call_with(attrs, base, span) }) } pub(super) fn parse_expr_dot_or_call_with( &mut self, + mut attrs: ast::AttrVec, e0: P, lo: Span, - mut attrs: ast::AttrVec, ) -> PResult<'a, P> { // Stitch the list of outer attributes onto the return value. // A little bit ugly, but the best way given the current code diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 6f2b71771594..7ef6474c29e4 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -388,9 +388,9 @@ impl<'a> Parser<'a> { // Parse `?`, `.f`, `(arg0, arg1, ...)` or `[expr]` until they've all been eaten. if let Ok(expr) = snapshot .parse_expr_dot_or_call_with( + AttrVec::new(), self.mk_expr(pat_span, ExprKind::Dummy), // equivalent to transforming the parsed pattern into an `Expr` pat_span, - AttrVec::new(), ) .map_err(|err| err.cancel()) { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index d65f6ff68eee..1259d223af6b 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -164,7 +164,7 @@ impl<'a> Parser<'a> { }; let expr = this.with_res(Restrictions::STMT_EXPR, |this| { - this.parse_expr_dot_or_call_with(expr, lo, attrs) + this.parse_expr_dot_or_call_with(attrs, expr, lo) })?; // `DUMMY_SP` will get overwritten later in this function Ok((this.mk_stmt(rustc_span::DUMMY_SP, StmtKind::Expr(expr)), TrailingToken::None)) @@ -206,7 +206,7 @@ impl<'a> Parser<'a> { // Since none of the above applied, this is an expression statement macro. let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac)); let e = self.maybe_recover_from_bad_qpath(e)?; - let e = self.parse_expr_dot_or_call_with(e, lo, attrs)?; + let e = self.parse_expr_dot_or_call_with(attrs, e, lo)?; let e = self .parse_expr_assoc_with(0, LhsExpr::Parsed { expr: e, starts_statement: false })?; StmtKind::Expr(e) From 96cc9c99b29c373db41093dee3170f36dc15543b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Jul 2024 16:02:45 +1000 Subject: [PATCH 164/734] Inline and remove `Parser::parse_and_disallow_postfix_after_cast`. It has a single call site. Removing it removes the need for an `ExprKind` check. The commit also clarifies the relevant comment. --- compiler/rustc_parse/src/parser/expr.rs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index a1bb047e464f..49a71b97be24 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -785,19 +785,10 @@ impl<'a> Parser<'a> { } }; - self.parse_and_disallow_postfix_after_cast(cast_expr) - } - - /// Parses a postfix operators such as `.`, `?`, or index (`[]`) after a cast, - /// then emits an error and returns the newly parsed tree. - /// The resulting parse tree for `&x as T[0]` has a precedence of `((&x) as T)[0]`. - fn parse_and_disallow_postfix_after_cast( - &mut self, - cast_expr: P, - ) -> PResult<'a, P> { - if let ExprKind::Type(_, _) = cast_expr.kind { - panic!("ExprKind::Type must not be parsed"); - } + // Try to parse a postfix operator such as `.`, `?`, or index (`[]`) + // after a cast. If one is present, emit an error then return a valid + // parse tree; For something like `&x as T[0]` will be as if it was + // written `((&x) as T)[0]`. let span = cast_expr.span; From 96b39f1204992368f059b44b56362a91e1e27ef9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Jul 2024 16:12:58 +1000 Subject: [PATCH 165/734] Inline and remove `Parser::parse_expr_dot_or_call_with_`. It only has two call sites, and it extremely similar to `Parser::parse_expr_dot_or_call_with`, in both name and behaviour. The only difference is the latter has an `attrs` argument and an `ensure_sufficient_stack` call. We can pass in an empty `attrs` as necessary, as is already done at some `parse_expr_dot_or_call_with` call sites. --- compiler/rustc_parse/src/parser/expr.rs | 102 ++++++++++++------------ 1 file changed, 49 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 49a71b97be24..896f84d3a36c 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -792,7 +792,7 @@ impl<'a> Parser<'a> { let span = cast_expr.span; - let with_postfix = self.parse_expr_dot_or_call_with_(cast_expr, span)?; + let with_postfix = self.parse_expr_dot_or_call_with(AttrVec::new(), cast_expr, span)?; // Check if an illegal postfix operator has been added after the cast. // If the resulting expression is not a cast, it is an illegal postfix operator. @@ -883,16 +883,56 @@ impl<'a> Parser<'a> { pub(super) fn parse_expr_dot_or_call_with( &mut self, mut attrs: ast::AttrVec, - e0: P, + mut e: P, lo: Span, ) -> PResult<'a, P> { - // Stitch the list of outer attributes onto the return value. - // A little bit ugly, but the best way given the current code - // structure - let res = ensure_sufficient_stack( - // this expr demonstrates the recursion it guards against - || self.parse_expr_dot_or_call_with_(e0, lo), - ); + let res = ensure_sufficient_stack(|| { + loop { + let has_question = + if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) { + // We are using noexpect here because we don't expect a `?` directly after + // a `return` which could be suggested otherwise. + self.eat_noexpect(&token::Question) + } else { + self.eat(&token::Question) + }; + if has_question { + // `expr?` + e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e)); + continue; + } + let has_dot = + if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) { + // We are using noexpect here because we don't expect a `.` directly after + // a `return` which could be suggested otherwise. + self.eat_noexpect(&token::Dot) + } else if self.token.kind == TokenKind::RArrow && self.may_recover() { + // Recovery for `expr->suffix`. + self.bump(); + let span = self.prev_token.span; + self.dcx().emit_err(errors::ExprRArrowCall { span }); + true + } else { + self.eat(&token::Dot) + }; + if has_dot { + // expr.f + e = self.parse_dot_suffix_expr(lo, e)?; + continue; + } + if self.expr_is_complete(&e) { + return Ok(e); + } + e = match self.token.kind { + token::OpenDelim(Delimiter::Parenthesis) => self.parse_expr_fn_call(lo, e), + token::OpenDelim(Delimiter::Bracket) => self.parse_expr_index(lo, e)?, + _ => return Ok(e), + } + } + }); + + // Stitch the list of outer attributes onto the return value. A little + // bit ugly, but the best way given the current code structure. if attrs.is_empty() { res } else { @@ -906,50 +946,6 @@ impl<'a> Parser<'a> { } } - fn parse_expr_dot_or_call_with_(&mut self, mut e: P, lo: Span) -> PResult<'a, P> { - loop { - let has_question = - if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) { - // we are using noexpect here because we don't expect a `?` directly after a `return` - // which could be suggested otherwise - self.eat_noexpect(&token::Question) - } else { - self.eat(&token::Question) - }; - if has_question { - // `expr?` - e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e)); - continue; - } - let has_dot = if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) { - // we are using noexpect here because we don't expect a `.` directly after a `return` - // which could be suggested otherwise - self.eat_noexpect(&token::Dot) - } else if self.token.kind == TokenKind::RArrow && self.may_recover() { - // Recovery for `expr->suffix`. - self.bump(); - let span = self.prev_token.span; - self.dcx().emit_err(errors::ExprRArrowCall { span }); - true - } else { - self.eat(&token::Dot) - }; - if has_dot { - // expr.f - e = self.parse_dot_suffix_expr(lo, e)?; - continue; - } - if self.expr_is_complete(&e) { - return Ok(e); - } - e = match self.token.kind { - token::OpenDelim(Delimiter::Parenthesis) => self.parse_expr_fn_call(lo, e), - token::OpenDelim(Delimiter::Bracket) => self.parse_expr_index(lo, e)?, - _ => return Ok(e), - } - } - } - pub(super) fn parse_dot_suffix_expr( &mut self, lo: Span, From 8cb6bc3b5a33cbd7d9b131fad2f63cc243b26ea0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Jul 2024 16:39:04 +1000 Subject: [PATCH 166/734] Fix a comment. --- compiler/rustc_parse/src/parser/expr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 896f84d3a36c..796a279188db 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1375,7 +1375,7 @@ impl<'a> Parser<'a> { /// Parses things like parenthesized exprs, macros, `return`, etc. /// /// N.B., this does not parse outer attributes, and is private because it only works - /// correctly if called from `parse_dot_or_call_expr()`. + /// correctly if called from `parse_expr_dot_or_call`. fn parse_expr_bottom(&mut self) -> PResult<'a, P> { maybe_recover_from_interpolated_ty_qpath!(self, true); From 9c4f3dbd066fd8e35f188388f66493522f7d4476 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Jul 2024 16:40:35 +1000 Subject: [PATCH 167/734] Remove references to `maybe_whole_expr`. It was removed in #126571. --- compiler/rustc_ast/src/token.rs | 3 +-- compiler/rustc_parse/src/parser/mod.rs | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index efe195661521..9478da236c31 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -699,8 +699,7 @@ impl Token { false } - /// Would `maybe_whole_expr` in `parser.rs` return `Ok(..)`? - /// That is, is this a pre-parsed expression dropped into the token stream + /// Is this a pre-parsed expression dropped into the token stream /// (which happens while parsing the result of macro expansion)? pub fn is_whole_expr(&self) -> bool { if let Interpolated(nt) = &self.kind diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 958458eda9a7..0117f993bcb3 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -101,7 +101,6 @@ pub enum TrailingToken { MaybeComma, } -/// Like `maybe_whole_expr`, but for things other than expressions. #[macro_export] macro_rules! maybe_whole { ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { From 8dafc5c8198c65311daa9f89a61f3b5c7eb833ad Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Mon, 15 Jul 2024 20:18:56 -0700 Subject: [PATCH 168/734] std: Use read_unaligned for reading DWARF --- library/std/src/sys/personality/dwarf/mod.rs | 26 +++++++++----------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/library/std/src/sys/personality/dwarf/mod.rs b/library/std/src/sys/personality/dwarf/mod.rs index 652fbe95a14d..281587a97329 100644 --- a/library/std/src/sys/personality/dwarf/mod.rs +++ b/library/std/src/sys/personality/dwarf/mod.rs @@ -17,32 +17,30 @@ pub struct DwarfReader { pub ptr: *const u8, } -#[repr(C, packed)] -struct Unaligned(T); - +#[deny(unsafe_op_in_unsafe_fn)] impl DwarfReader { pub fn new(ptr: *const u8) -> DwarfReader { DwarfReader { ptr } } - // DWARF streams are packed, so e.g., a u32 would not necessarily be aligned - // on a 4-byte boundary. This may cause problems on platforms with strict - // alignment requirements. By wrapping data in a "packed" struct, we are - // telling the backend to generate "misalignment-safe" code. + /// Read a type T and then bump the pointer by that amount. + /// + /// DWARF streams are "packed", so all types must be read at align 1. pub unsafe fn read(&mut self) -> T { - let Unaligned(result) = *(self.ptr as *const Unaligned); - self.ptr = self.ptr.add(mem::size_of::()); - result + unsafe { + let result = self.ptr.cast::().read_unaligned(); + self.ptr = self.ptr.byte_add(mem::size_of::()); + result + } } - // ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable - // Length Data". + /// ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable Length Data". pub unsafe fn read_uleb128(&mut self) -> u64 { let mut shift: usize = 0; let mut result: u64 = 0; let mut byte: u8; loop { - byte = self.read::(); + byte = unsafe { self.read::() }; result |= ((byte & 0x7F) as u64) << shift; shift += 7; if byte & 0x80 == 0 { @@ -57,7 +55,7 @@ impl DwarfReader { let mut result: u64 = 0; let mut byte: u8; loop { - byte = self.read::(); + byte = unsafe { self.read::() }; result |= ((byte & 0x7F) as u64) << shift; shift += 7; if byte & 0x80 == 0 { From 664907cab68408a2a67c70d5f6864f558840b119 Mon Sep 17 00:00:00 2001 From: Mrmaxmeier Date: Tue, 16 Jul 2024 11:01:35 +0200 Subject: [PATCH 169/734] run-make-support: update gimli to 0.31.0 --- Cargo.lock | 13 ++++++++++++- src/tools/run-make-support/Cargo.toml | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cafc623c185a..68478d55e231 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1618,6 +1618,17 @@ dependencies = [ "rustc-std-workspace-core", ] +[[package]] +name = "gimli" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + [[package]] name = "glob" version = "0.3.1" @@ -3421,7 +3432,7 @@ dependencies = [ "ar", "bstr", "build_helper", - "gimli 0.28.1", + "gimli 0.31.0", "object 0.34.0", "regex", "similar", diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 969552dec84a..681284b1a489 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -9,7 +9,7 @@ object = "0.34.0" similar = "2.5.0" wasmparser = "0.118.2" regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace -gimli = "0.28.1" +gimli = "0.31.0" ar = "0.9.0" build_helper = { path = "../build_helper" } From 51bdcf66d3b884134a7a3b905e3b72a365f16c40 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 16 Jul 2024 10:08:26 +0000 Subject: [PATCH 170/734] Use futex.rs for Windows thread parking --- library/std/src/sys/pal/hermit/futex.rs | 5 +++++ library/std/src/sys/pal/unix/futex.rs | 5 +++++ library/std/src/sys/pal/wasm/atomics/futex.rs | 5 +++++ library/std/src/sys/pal/windows/futex.rs | 5 +++++ library/std/src/sys/sync/mutex/futex.rs | 19 ++++--------------- .../std/src/sys/sync/thread_parking/futex.rs | 17 ++++++++++------- .../std/src/sys/sync/thread_parking/mod.rs | 7 ++++--- .../{windows.rs => windows7.rs} | 0 8 files changed, 38 insertions(+), 25 deletions(-) rename library/std/src/sys/sync/thread_parking/{windows.rs => windows7.rs} (100%) diff --git a/library/std/src/sys/pal/hermit/futex.rs b/library/std/src/sys/pal/hermit/futex.rs index b2d74d1311bc..21c5facd52fb 100644 --- a/library/std/src/sys/pal/hermit/futex.rs +++ b/library/std/src/sys/pal/hermit/futex.rs @@ -3,6 +3,11 @@ use crate::ptr::null; use crate::sync::atomic::AtomicU32; use crate::time::Duration; +/// An atomic for use as a futex that is at least 8-bits but may be larger. +pub type SmallAtomic = AtomicU32; +/// Must be the underlying type of SmallAtomic +pub type SmallPrimitive = u32; + pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option) -> bool { // Calculate the timeout as a relative timespec. // diff --git a/library/std/src/sys/pal/unix/futex.rs b/library/std/src/sys/pal/unix/futex.rs index 26161a9af79d..b8900da4cddb 100644 --- a/library/std/src/sys/pal/unix/futex.rs +++ b/library/std/src/sys/pal/unix/futex.rs @@ -11,6 +11,11 @@ use crate::sync::atomic::AtomicU32; use crate::time::Duration; +/// An atomic for use as a futex that is at least 8-bits but may be larger. +pub type SmallAtomic = AtomicU32; +/// Must be the underlying type of SmallAtomic +pub type SmallPrimitive = u32; + /// Wait for a futex_wake operation to wake us. /// /// Returns directly if the futex doesn't hold the expected value. diff --git a/library/std/src/sys/pal/wasm/atomics/futex.rs b/library/std/src/sys/pal/wasm/atomics/futex.rs index a21b71efbbc6..3584138ca044 100644 --- a/library/std/src/sys/pal/wasm/atomics/futex.rs +++ b/library/std/src/sys/pal/wasm/atomics/futex.rs @@ -6,6 +6,11 @@ use core::arch::wasm64 as wasm; use crate::sync::atomic::AtomicU32; use crate::time::Duration; +/// An atomic for use as a futex that is at least 8-bits but may be larger. +pub type SmallAtomic = AtomicU32; +/// Must be the underlying type of SmallAtomic +pub type SmallPrimitive = u32; + /// Wait for a futex_wake operation to wake us. /// /// Returns directly if the futex doesn't hold the expected value. diff --git a/library/std/src/sys/pal/windows/futex.rs b/library/std/src/sys/pal/windows/futex.rs index 08b7fe300dc3..cb802fdd9c96 100644 --- a/library/std/src/sys/pal/windows/futex.rs +++ b/library/std/src/sys/pal/windows/futex.rs @@ -10,6 +10,11 @@ use core::sync::atomic::{ }; use core::time::Duration; +/// An atomic for use as a futex that is at least 8-bits but may be larger. +pub type SmallAtomic = AtomicU8; +/// Must be the underlying type of SmallAtomic +pub type SmallPrimitive = u8; + pub unsafe trait Waitable { type Atomic; } diff --git a/library/std/src/sys/sync/mutex/futex.rs b/library/std/src/sys/sync/mutex/futex.rs index 7427cae94d68..81afa94b1478 100644 --- a/library/std/src/sys/sync/mutex/futex.rs +++ b/library/std/src/sys/sync/mutex/futex.rs @@ -1,19 +1,8 @@ -use crate::sync::atomic::{ - self, - Ordering::{Acquire, Relaxed, Release}, -}; -use crate::sys::futex::{futex_wait, futex_wake}; +use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; +use crate::sys::futex::{self, futex_wait, futex_wake}; -cfg_if::cfg_if! { -if #[cfg(windows)] { - // On Windows we can have a smol futex - type Atomic = atomic::AtomicU8; - type State = u8; -} else { - type Atomic = atomic::AtomicU32; - type State = u32; -} -} +type Atomic = futex::SmallAtomic; +type State = futex::SmallPrimitive; pub struct Mutex { futex: Atomic, diff --git a/library/std/src/sys/sync/thread_parking/futex.rs b/library/std/src/sys/sync/thread_parking/futex.rs index 588e7b27826f..034eececb2a2 100644 --- a/library/std/src/sys/sync/thread_parking/futex.rs +++ b/library/std/src/sys/sync/thread_parking/futex.rs @@ -1,15 +1,18 @@ +#![forbid(unsafe_op_in_unsafe_fn)] use crate::pin::Pin; -use crate::sync::atomic::AtomicU32; use crate::sync::atomic::Ordering::{Acquire, Release}; -use crate::sys::futex::{futex_wait, futex_wake}; +use crate::sys::futex::{self, futex_wait, futex_wake}; use crate::time::Duration; -const PARKED: u32 = u32::MAX; -const EMPTY: u32 = 0; -const NOTIFIED: u32 = 1; +type Atomic = futex::SmallAtomic; +type State = futex::SmallPrimitive; + +const PARKED: State = State::MAX; +const EMPTY: State = 0; +const NOTIFIED: State = 1; pub struct Parker { - state: AtomicU32, + state: Atomic, } // Notes about memory ordering: @@ -36,7 +39,7 @@ impl Parker { /// Construct the futex parker. The UNIX parker implementation /// requires this to happen in-place. pub unsafe fn new_in_place(parker: *mut Parker) { - parker.write(Self { state: AtomicU32::new(EMPTY) }); + unsafe { parker.write(Self { state: Atomic::new(EMPTY) }) }; } // Assumes this is only called by the thread that owns the Parker, diff --git a/library/std/src/sys/sync/thread_parking/mod.rs b/library/std/src/sys/sync/thread_parking/mod.rs index ed1a6437faaa..0ebc5e093ee2 100644 --- a/library/std/src/sys/sync/thread_parking/mod.rs +++ b/library/std/src/sys/sync/thread_parking/mod.rs @@ -1,5 +1,6 @@ cfg_if::cfg_if! { if #[cfg(any( + all(target_os = "windows", not(target_vendor = "win7")), target_os = "linux", target_os = "android", all(target_arch = "wasm32", target_feature = "atomics"), @@ -18,9 +19,9 @@ cfg_if::cfg_if! { ))] { mod id; pub use id::Parker; - } else if #[cfg(target_os = "windows")] { - mod windows; - pub use windows::Parker; + } else if #[cfg(target_vendor = "win7")] { + mod windows7; + pub use windows7::Parker; } else if #[cfg(all(target_vendor = "apple", not(miri)))] { mod darwin; pub use darwin::Parker; diff --git a/library/std/src/sys/sync/thread_parking/windows.rs b/library/std/src/sys/sync/thread_parking/windows7.rs similarity index 100% rename from library/std/src/sys/sync/thread_parking/windows.rs rename to library/std/src/sys/sync/thread_parking/windows7.rs From fb98fbb759cf7b2e3cb262bf3621407cae9e3c6d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 16 Jul 2024 11:31:04 +0000 Subject: [PATCH 171/734] Make `ErrorGuaranteed` discoverable outside types, consts, and lifetimes --- .../rustc_middle/src/ty/structural_impls.rs | 19 ++++++++-- compiler/rustc_type_ir/src/visit.rs | 36 +++++++------------ 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index a9dca47ab437..33c04b411173 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -257,7 +257,6 @@ TrivialTypeTraversalImpls! { crate::ty::adjustment::PointerCoercion, ::rustc_span::Span, ::rustc_span::symbol::Ident, - ::rustc_errors::ErrorGuaranteed, ty::BoundVar, ty::ValTree<'tcx>, } @@ -443,13 +442,14 @@ impl<'tcx> TypeSuperVisitable> for Ty<'tcx> { pat.visit_with(visitor) } + ty::Error(guar) => guar.visit_with(visitor), + ty::Bool | ty::Char | ty::Str | ty::Int(_) | ty::Uint(_) | ty::Float(_) - | ty::Error(_) | ty::Infer(_) | ty::Bound(..) | ty::Placeholder(..) @@ -602,6 +602,21 @@ impl<'tcx> TypeSuperVisitable> for ty::Const<'tcx> { } } +impl<'tcx> TypeVisitable> for rustc_span::ErrorGuaranteed { + fn visit_with>>(&self, visitor: &mut V) -> V::Result { + visitor.visit_error(*self) + } +} + +impl<'tcx> TypeFoldable> for rustc_span::ErrorGuaranteed { + fn try_fold_with>>( + self, + _folder: &mut F, + ) -> Result { + Ok(self) + } +} + impl<'tcx> TypeFoldable> for InferConst { fn try_fold_with>>( self, diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 25eb56fe3fb5..d604199b8e06 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -101,8 +101,12 @@ pub trait TypeVisitor: Sized { // The default region visitor is a no-op because `Region` is non-recursive // and has no `super_visit_with` method to call. - fn visit_region(&mut self, _r: I::Region) -> Self::Result { - Self::Result::output() + fn visit_region(&mut self, r: I::Region) -> Self::Result { + if let ty::ReError(guar) = r.kind() { + self.visit_error(guar) + } else { + Self::Result::output() + } } fn visit_const(&mut self, c: I::Const) -> Self::Result { @@ -116,6 +120,10 @@ pub trait TypeVisitor: Sized { fn visit_clauses(&mut self, p: I::Clauses) -> Self::Result { p.super_visit_with(self) } + + fn visit_error(&mut self, _guar: I::ErrorGuaranteed) -> Self::Result { + Self::Result::output() + } } /////////////////////////////////////////////////////////////////////////// @@ -547,27 +555,7 @@ struct HasErrorVisitor; impl TypeVisitor for HasErrorVisitor { type Result = ControlFlow; - fn visit_ty(&mut self, t: ::Ty) -> Self::Result { - if let ty::Error(guar) = t.kind() { - ControlFlow::Break(guar) - } else { - t.super_visit_with(self) - } - } - - fn visit_const(&mut self, c: ::Const) -> Self::Result { - if let ty::ConstKind::Error(guar) = c.kind() { - ControlFlow::Break(guar) - } else { - c.super_visit_with(self) - } - } - - fn visit_region(&mut self, r: ::Region) -> Self::Result { - if let ty::ReError(guar) = r.kind() { - ControlFlow::Break(guar) - } else { - ControlFlow::Continue(()) - } + fn visit_error(&mut self, guar: ::ErrorGuaranteed) -> Self::Result { + ControlFlow::Break(guar) } } From 50ba821e12f51903aba6902b2b404edbc94011d2 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 16 Jul 2024 15:57:00 +0200 Subject: [PATCH 172/734] add rust error message for CMSE stack spill when the `C-cmse-nonsecure-call` ABI is used, arguments and return values must be passed via registers. Failing to do so (i.e. spilling to the stack) causes an LLVM error down the line, but now rustc will properly emit an error a bit earlier in the chain --- compiler/rustc_codegen_ssa/messages.ftl | 12 ++++ compiler/rustc_codegen_ssa/src/errors.rs | 22 ++++++++ compiler/rustc_codegen_ssa/src/mir/block.rs | 56 ++++++++++++++++++- .../src/error_codes/E0798.md | 36 ++++++++++++ compiler/rustc_error_codes/src/lib.rs | 1 + .../cmse-nonsecure-call/params-on-stack.rs | 15 ++--- .../params-on-stack.stderr | 12 +++- 7 files changed, 143 insertions(+), 11 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0798.md diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 000fe2e3ce0f..0aee5e16a537 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -16,6 +16,18 @@ codegen_ssa_cgu_not_recorded = codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option. +codegen_ssa_cmse_call_inputs_stack_spill = + arguments for `C-cmse-nonsecure-call` function too large to pass via registers + .label = this function uses the `C-cmse-nonsecure-call` ABI + .call = but its arguments don't fit in the available registers + .note = functions with the `C-cmse-nonsecure-call` ABI must pass all their arguments via the 4 32-bit available argument registers + +codegen_ssa_cmse_call_output_stack_spill = + return value of `C-cmse-nonsecure-call` function too large to pass via registers + .label = this function uses the `C-cmse-nonsecure-call` ABI + .call = but its return value doesn't fit in the available registers + .note = functions with the `C-cmse-nonsecure-call` ABI must pass their result via the available return registers + codegen_ssa_compiler_builtins_cannot_call = `compiler_builtins` cannot call functions through upstream monomorphizations; encountered invalid call from `{$caller}` to `{$callee}` diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index e9d31db92541..13a2dce3e69c 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1033,3 +1033,25 @@ pub struct CompilerBuiltinsCannotCall { pub caller: String, pub callee: String, } + +#[derive(Diagnostic)] +#[diag(codegen_ssa_cmse_call_inputs_stack_spill, code = E0798)] +#[note] +pub struct CmseCallInputsStackSpill { + #[primary_span] + #[label(codegen_ssa_call)] + pub span: Span, + #[label] + pub func_span: Span, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_cmse_call_output_stack_spill, code = E0798)] +#[note] +pub struct CmseCallOutputStackSpill { + #[primary_span] + #[label(codegen_ssa_call)] + pub span: Span, + #[label] + pub func_span: Span, +} diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 6a5525dc2b34..8011604d5766 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -5,7 +5,9 @@ use super::{CachedLlbb, FunctionCx, LocalRef}; use crate::base; use crate::common::{self, IntPredicate}; -use crate::errors::CompilerBuiltinsCannotCall; +use crate::errors::{ + CmseCallInputsStackSpill, CmseCallOutputStackSpill, CompilerBuiltinsCannotCall, +}; use crate::meth; use crate::traits::*; use crate::MemFlags; @@ -834,6 +836,58 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. let callee = self.codegen_operand(bx, func); + let fn_sig = callee.layout.ty.fn_sig(bx.tcx()).skip_binder(); + + if let rustc_target::spec::abi::Abi::CCmseNonSecureCall = fn_sig.abi { + let mut accum = 0u64; + + for arg_def in fn_sig.inputs().iter() { + let layout = bx.layout_of(*arg_def); + + let align = layout.layout.align().abi.bytes(); + let size = layout.layout.size().bytes(); + + accum += size; + accum = accum.next_multiple_of(Ord::max(4, align)); + } + + // the available argument space is 16 bytes (4 32-bit registers) in total + let available_space = 16; + + if accum > available_space { + let err = CmseCallInputsStackSpill { span, func_span: func.span(self.mir) }; + bx.tcx().dcx().emit_err(err); + } + + let mut ret_layout = bx.layout_of(fn_sig.output()); + + // unwrap any `repr(transparent)` wrappers + loop { + if ret_layout.is_transparent::() { + match ret_layout.non_1zst_field(bx) { + None => break, + Some((_, layout)) => ret_layout = layout, + } + } else { + break; + } + } + + let valid_2register_return_types = + [bx.tcx().types.i64, bx.tcx().types.u64, bx.tcx().types.f64]; + + // A Composite Type larger than 4 bytes is stored in memory at an address + // passed as an extra argument when the function was called. That is not allowed + // for cmse_nonsecure_entry functions. + let is_valid_output = ret_layout.layout.size().bytes() <= 4 + || valid_2register_return_types.contains(&ret_layout.ty); + + if !is_valid_output { + let err = CmseCallOutputStackSpill { span, func_span: func.span(self.mir) }; + bx.tcx().dcx().emit_err(err); + } + } + let (instance, mut llfn) = match *callee.layout.ty.kind() { ty::FnDef(def_id, args) => ( Some( diff --git a/compiler/rustc_error_codes/src/error_codes/E0798.md b/compiler/rustc_error_codes/src/error_codes/E0798.md new file mode 100644 index 000000000000..79ed041004e9 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0798.md @@ -0,0 +1,36 @@ +Functions marked as `C-cmse-nonsecure-call` place restrictions on their +inputs and outputs. + +- inputs must fit in the 4 available 32-bit argument registers. Alignment +is relevant. +- outputs must either fit in 4 bytes, or be a foundational type of +size 8 (`i64`, `u64`, `f64`). + +For more information, +see [arm's aapcs32](https://github.com/ARM-software/abi-aa/releases). + +Erroneous code example: + +```compile_fail,E0798 +#![feature(abi_c_cmse_nonsecure_call)] + +fn test( + f: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32, +) -> u32 { + f(1, 2, 3, 4, 5) +} +``` + +Arguments' alignment is respected. In the example below, padding is inserted +so that the `u64` argument is passed in registers r2 and r3. There is then no +room left for the final `f32` argument + +```compile_fail,E0798 +#![feature(abi_c_cmse_nonsecure_call)] + +fn test( + f: extern "C-cmse-nonsecure-call" fn(u32, u64, f32) -> u32, +) -> u32 { + f(1, 2, 3.0) +} +``` diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index d13d5e1bca21..2a7bc2501c08 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -536,6 +536,7 @@ E0794: 0794, E0795: 0795, E0796: 0796, E0797: 0797, +E0798: 0798, ); ) } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs index c225a26c065d..f13e81d00608 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs @@ -3,10 +3,10 @@ //@ needs-llvm-components: arm #![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)] #![no_core] -#[lang="sized"] -pub trait Sized { } -#[lang="copy"] -pub trait Copy { } +#[lang = "sized"] +pub trait Sized {} +#[lang = "copy"] +pub trait Copy {} impl Copy for u32 {} extern "rust-intrinsic" { @@ -16,12 +16,9 @@ extern "rust-intrinsic" { #[no_mangle] pub fn test(a: u32, b: u32, c: u32, d: u32, e: u32) -> u32 { let non_secure_function = unsafe { - transmute::< - usize, - extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32> - ( + transmute:: u32>( 0x10000004, ) }; - non_secure_function(a, b, c, d, e) + non_secure_function(a, b, c, d, e) //~ ERROR [E0798] } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.stderr index a8aced2483e8..ee4effa56d4a 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.stderr @@ -1,4 +1,14 @@ -error: :0:0: in function test i32 (i32, i32, i32, i32, i32): call to non-secure function would require passing arguments on stack +error[E0798]: arguments for `C-cmse-nonsecure-call` function too large to pass via registers + --> $DIR/params-on-stack.rs:23:5 + | +LL | let non_secure_function = unsafe { + | ------------------- this function uses the `C-cmse-nonsecure-call` ABI +... +LL | non_secure_function(a, b, c, d, e) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ but its arguments don't fit in the available registers + | + = note: functions with the `C-cmse-nonsecure-call` ABI must pass all their arguments via the 4 32-bit available argument registers error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0798`. From 077d0da30a888ea049a471bca6301d706ca66c25 Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 16 Jul 2024 21:57:12 +0800 Subject: [PATCH 173/734] add test for issue 127590 --- .../invalid-suggest-deref-issue-127590.rs | 18 +++++ .../invalid-suggest-deref-issue-127590.stderr | 69 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.rs create mode 100644 tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr diff --git a/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.rs b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.rs new file mode 100644 index 000000000000..a71657316ae6 --- /dev/null +++ b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.rs @@ -0,0 +1,18 @@ +fn main() { + let fields = vec![1]; + let variant = vec![2]; + + // should not suggest `*&variant.iter()` + for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) { + //~^ ERROR `&std::slice::Iter<'_, {integer}>` is not an iterator + //~| ERROR `&std::slice::Iter<'_, {integer}>` is not an iterator + eprintln!("{} {}", src, dest); + } + + // don't suggest add `variant.iter().clone().clone()` + for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone()) { + //~^ ERROR `&std::slice::Iter<'_, {integer}>` is not an iterator + //~| ERROR `&std::slice::Iter<'_, {integer}>` is not an iterator + eprintln!("{} {}", src, dest); + } +} diff --git a/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr new file mode 100644 index 000000000000..14befe796cf0 --- /dev/null +++ b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr @@ -0,0 +1,69 @@ +error[E0277]: `&std::slice::Iter<'_, {integer}>` is not an iterator + --> $DIR/invalid-suggest-deref-issue-127590.rs:6:54 + | +LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) { + | -------------- ^^^^^^^^^^^^^^^ `&std::slice::Iter<'_, {integer}>` is not an iterator + | | + | required by a bound introduced by this call + | + = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`, which is required by `&std::slice::Iter<'_, {integer}>: IntoIterator` + = note: required for `&std::slice::Iter<'_, {integer}>` to implement `IntoIterator` +note: required by a bound in `std::iter::zip` + --> $SRC_DIR/core/src/iter/adapters/zip.rs:LL:COL +help: consider dereferencing here + | +LL | for (src, dest) in std::iter::zip(fields.iter(), *&variant.iter()) { + | + +help: consider removing the leading `&`-reference + | +LL - for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) { +LL + for (src, dest) in std::iter::zip(fields.iter(), variant.iter()) { + | + +error[E0277]: `&std::slice::Iter<'_, {integer}>` is not an iterator + --> $DIR/invalid-suggest-deref-issue-127590.rs:6:24 + | +LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&std::slice::Iter<'_, {integer}>` is not an iterator + | + = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`, which is required by `Zip, &std::slice::Iter<'_, {integer}>>: IntoIterator` + = help: the trait `Iterator` is implemented for `std::slice::Iter<'a, T>` + = note: required for `Zip, &std::slice::Iter<'_, {integer}>>` to implement `Iterator` + = note: required for `Zip, &std::slice::Iter<'_, {integer}>>` to implement `IntoIterator` + +error[E0277]: `&std::slice::Iter<'_, {integer}>` is not an iterator + --> $DIR/invalid-suggest-deref-issue-127590.rs:13:54 + | +LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone()) { + | -------------- ^^^^^^^^^^^^^^^^^^^^^^^ `&std::slice::Iter<'_, {integer}>` is not an iterator + | | + | required by a bound introduced by this call + | + = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`, which is required by `&std::slice::Iter<'_, {integer}>: IntoIterator` + = note: required for `&std::slice::Iter<'_, {integer}>` to implement `IntoIterator` +note: required by a bound in `std::iter::zip` + --> $SRC_DIR/core/src/iter/adapters/zip.rs:LL:COL +help: consider dereferencing here + | +LL | for (src, dest) in std::iter::zip(fields.iter(), *&variant.iter().clone()) { + | + +help: consider removing the leading `&`-reference + | +LL - for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone()) { +LL + for (src, dest) in std::iter::zip(fields.iter(), variant.iter().clone()) { + | + +error[E0277]: `&std::slice::Iter<'_, {integer}>` is not an iterator + --> $DIR/invalid-suggest-deref-issue-127590.rs:13:24 + | +LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&std::slice::Iter<'_, {integer}>` is not an iterator + | + = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`, which is required by `Zip, &std::slice::Iter<'_, {integer}>>: IntoIterator` + = help: the trait `Iterator` is implemented for `std::slice::Iter<'a, T>` + = note: required for `Zip, &std::slice::Iter<'_, {integer}>>` to implement `Iterator` + = note: required for `Zip, &std::slice::Iter<'_, {integer}>>` to implement `IntoIterator` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. From 48ddf5e32398287efed553e88043bafc04177917 Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 16 Jul 2024 22:00:04 +0800 Subject: [PATCH 174/734] Fix the issue of invalid suggestion for a reference of iterator --- .../src/error_reporting/traits/suggestions.rs | 4 +++- .../invalid-suggest-deref-issue-127590.stderr | 8 -------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index f8843b892db3..2bf582dcfb11 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -466,7 +466,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr) { // Suggest dereferencing the argument to a function/method call if possible - let mut real_trait_pred = trait_pred; while let Some((parent_code, parent_trait_pred)) = code.parent() { code = parent_code; @@ -553,6 +552,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); if self.predicate_may_hold(&obligation) && self.predicate_must_hold_modulo_regions(&sized_obligation) + // Do not suggest * if it is already a reference, + // will suggest removing the borrow instead in that case. + && !matches!(expr.kind, hir::ExprKind::AddrOf(..)) { let call_node = self.tcx.hir_node(*call_hir_id); let msg = "consider dereferencing here"; diff --git a/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr index 14befe796cf0..a3ed51ace088 100644 --- a/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr +++ b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr @@ -10,10 +10,6 @@ LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) { = note: required for `&std::slice::Iter<'_, {integer}>` to implement `IntoIterator` note: required by a bound in `std::iter::zip` --> $SRC_DIR/core/src/iter/adapters/zip.rs:LL:COL -help: consider dereferencing here - | -LL | for (src, dest) in std::iter::zip(fields.iter(), *&variant.iter()) { - | + help: consider removing the leading `&`-reference | LL - for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) { @@ -43,10 +39,6 @@ LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone( = note: required for `&std::slice::Iter<'_, {integer}>` to implement `IntoIterator` note: required by a bound in `std::iter::zip` --> $SRC_DIR/core/src/iter/adapters/zip.rs:LL:COL -help: consider dereferencing here - | -LL | for (src, dest) in std::iter::zip(fields.iter(), *&variant.iter().clone()) { - | + help: consider removing the leading `&`-reference | LL - for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone()) { From 53f7f8ce5cb01a4bdef70b0bdb4aa812fe548ce7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 16 Jul 2024 11:31:18 +0000 Subject: [PATCH 175/734] Remove an unnecessary impl --- compiler/rustc_middle/src/ty/structural_impls.rs | 6 ------ compiler/rustc_type_ir/src/visit.rs | 9 +++++++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 33c04b411173..00ea87690c1a 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -632,12 +632,6 @@ impl<'tcx> TypeVisitable> for InferConst { } } -impl<'tcx> TypeSuperVisitable> for ty::UnevaluatedConst<'tcx> { - fn super_visit_with>>(&self, visitor: &mut V) -> V::Result { - self.args.visit_with(visitor) - } -} - impl<'tcx> TypeVisitable> for TyAndLayout<'tcx, Ty<'tcx>> { fn visit_with>>(&self, visitor: &mut V) -> V::Result { visitor.visit_ty(self.ty) diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index d604199b8e06..6ec38b78fc22 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -447,6 +447,15 @@ impl TypeVisitor for HasTypeFlagsVisitor { ControlFlow::Continue(()) } } + + #[inline] + fn visit_error(&mut self, _guar: ::ErrorGuaranteed) -> Self::Result { + if self.flags.intersects(TypeFlags::HAS_ERROR) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::Continue(()) + } + } } #[derive(Debug, PartialEq, Eq, Copy, Clone)] From 7ee97f93dabd0be0cfbee437c42dd6555f7bdfd4 Mon Sep 17 00:00:00 2001 From: Bryanskiy Date: Tue, 18 Jun 2024 14:04:28 +0300 Subject: [PATCH 176/734] Delegation: support coercion for target expression --- compiler/rustc_ast_lowering/src/delegation.rs | 84 +++++++++++++++---- compiler/rustc_hir_typeck/src/method/mod.rs | 9 +- compiler/rustc_hir_typeck/src/method/probe.rs | 33 +++++++- tests/ui/delegation/bad-resolve.rs | 3 + tests/ui/delegation/bad-resolve.stderr | 24 +++++- tests/ui/delegation/explicit-paths-pass.rs | 4 +- tests/ui/delegation/explicit-paths.rs | 4 +- tests/ui/delegation/explicit-paths.stderr | 9 +- tests/ui/delegation/ice-issue-122550.stderr | 25 ++++-- tests/ui/delegation/method-call-choice.rs | 25 ++++++ tests/ui/delegation/method-call-choice.stderr | 21 +++++ tests/ui/delegation/method-call-priority.rs | 34 ++++++++ tests/ui/delegation/self-coercion.rs | 26 ++++++ 13 files changed, 264 insertions(+), 37 deletions(-) create mode 100644 tests/ui/delegation/method-call-choice.rs create mode 100644 tests/ui/delegation/method-call-choice.stderr create mode 100644 tests/ui/delegation/method-call-priority.rs create mode 100644 tests/ui/delegation/self-coercion.rs diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 678cac210f41..6df2c15ce60c 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -38,7 +38,7 @@ use crate::{ImplTraitPosition, ResolverAstLoweringExt}; -use super::{ImplTraitContext, LoweringContext, ParamMode}; +use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; use ast::visit::Visitor; use hir::def::{DefKind, PartialRes, Res}; @@ -259,8 +259,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self_param_id: pat_node_id, }; self_resolver.visit_block(block); - let block = this.lower_block(block, false); - this.mk_expr(hir::ExprKind::Block(block, None), block.span) + this.lower_target_expr(&block) } else { let pat_hir_id = this.lower_node_id(pat_node_id); this.generate_arg(pat_hir_id, span) @@ -273,26 +272,81 @@ impl<'hir> LoweringContext<'_, 'hir> { }) } - // Generates fully qualified call for the resulting body. + // FIXME(fn_delegation): Alternatives for target expression lowering: + // https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2197170600. + fn lower_target_expr(&mut self, block: &Block) -> hir::Expr<'hir> { + if block.stmts.len() == 1 + && let StmtKind::Expr(expr) = &block.stmts[0].kind + { + return self.lower_expr_mut(expr); + } + + let block = self.lower_block(block, false); + self.mk_expr(hir::ExprKind::Block(block, None), block.span) + } + + // Generates expression for the resulting body. If possible, `MethodCall` is used + // to allow autoref/autoderef for target expression. For example in: + // + // trait Trait : Sized { + // fn by_value(self) -> i32 { 1 } + // fn by_mut_ref(&mut self) -> i32 { 2 } + // fn by_ref(&self) -> i32 { 3 } + // } + // + // struct NewType(SomeType); + // impl Trait for NewType { + // reuse Trait::* { self.0 } + // } + // + // `self.0` will automatically coerce. fn finalize_body_lowering( &mut self, delegation: &Delegation, args: Vec>, span: Span, ) -> hir::Expr<'hir> { - let path = self.lower_qpath( - delegation.id, - &delegation.qself, - &delegation.path, - ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, - ); - let args = self.arena.alloc_from_iter(args); - let path_expr = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(path), span)); - let call = self.arena.alloc(self.mk_expr(hir::ExprKind::Call(path_expr, args), span)); + let has_generic_args = + delegation.path.segments.iter().rev().skip(1).any(|segment| segment.args.is_some()); + + let call = if self + .get_resolution_id(delegation.id, span) + .and_then(|def_id| Ok(self.has_self(def_id, span))) + .unwrap_or_default() + && delegation.qself.is_none() + && !has_generic_args + { + let ast_segment = delegation.path.segments.last().unwrap(); + let segment = self.lower_path_segment( + delegation.path.span, + ast_segment, + ParamMode::Optional, + ParenthesizedGenericArgs::Err, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + let segment = self.arena.alloc(segment); + + self.arena.alloc(hir::Expr { + hir_id: self.next_id(), + kind: hir::ExprKind::MethodCall(segment, &args[0], &args[1..], span), + span, + }) + } else { + let path = self.lower_qpath( + delegation.id, + &delegation.qself, + &delegation.path, + ParamMode::Optional, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + + let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(path), span)); + self.arena.alloc(self.mk_expr(hir::ExprKind::Call(callee_path, args), span)) + }; let block = self.arena.alloc(hir::Block { stmts: &[], expr: Some(call), diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index dc1b888374cf..daf4ef5cdb32 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -182,8 +182,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_expr: &'tcx hir::Expr<'tcx>, args: &'tcx [hir::Expr<'tcx>], ) -> Result, MethodError<'tcx>> { - let pick = - self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?; + let scope = if let Some(only_method) = segment.res.opt_def_id() { + ProbeScope::Single(only_method) + } else { + ProbeScope::TraitsInScope + }; + + let pick = self.lookup_probe(segment.ident, self_ty, call_expr, scope)?; self.lint_edition_dependent_dot_call( self_ty, segment, span, call_expr, self_expr, &pick, args, diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 6a7af5510e07..1c308d4af3ef 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -20,6 +20,7 @@ use rustc_middle::middle::stability; use rustc_middle::query::Providers; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; use rustc_middle::ty::AssocItem; +use rustc_middle::ty::AssocItemContainer; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::Upcast; use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; @@ -216,6 +217,9 @@ pub enum Mode { #[derive(PartialEq, Eq, Copy, Clone, Debug)] pub enum ProbeScope { + // Single candidate coming from pre-resolved delegation method. + Single(DefId), + // Assemble candidates coming only from traits in scope. TraitsInScope, @@ -480,12 +484,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { is_suggestion, ); - probe_cx.assemble_inherent_candidates(); match scope { ProbeScope::TraitsInScope => { - probe_cx.assemble_extension_candidates_for_traits_in_scope() + probe_cx.assemble_inherent_candidates(); + probe_cx.assemble_extension_candidates_for_traits_in_scope(); + } + ProbeScope::AllTraits => { + probe_cx.assemble_inherent_candidates(); + probe_cx.assemble_extension_candidates_for_all_traits(); + } + ProbeScope::Single(def_id) => { + let item = self.tcx.associated_item(def_id); + // FIXME(fn_delegation): Delegation to inherent methods is not yet supported. + assert_eq!(item.container, AssocItemContainer::TraitContainer); + + let trait_def_id = self.tcx.parent(def_id); + let trait_span = self.tcx.def_span(trait_def_id); + + let trait_args = self.fresh_args_for_item(trait_span, trait_def_id); + let trait_ref = ty::TraitRef::new_from_args(self.tcx, trait_def_id, trait_args); + + probe_cx.push_candidate( + Candidate { + item, + kind: CandidateKind::TraitCandidate(ty::Binder::dummy(trait_ref)), + import_ids: smallvec![], + }, + false, + ); } - ProbeScope::AllTraits => probe_cx.assemble_extension_candidates_for_all_traits(), }; op(probe_cx) }) diff --git a/tests/ui/delegation/bad-resolve.rs b/tests/ui/delegation/bad-resolve.rs index f378e05304b2..f15e6aa81afb 100644 --- a/tests/ui/delegation/bad-resolve.rs +++ b/tests/ui/delegation/bad-resolve.rs @@ -34,6 +34,9 @@ impl Trait for S { reuse foo { &self.0 } //~^ ERROR cannot find function `foo` in this scope + reuse Trait::foo2 { self.0 } + //~^ ERROR cannot find function `foo2` in trait `Trait` + //~| ERROR method `foo2` is not a member of trait `Trait` } mod prefix {} diff --git a/tests/ui/delegation/bad-resolve.stderr b/tests/ui/delegation/bad-resolve.stderr index 883ff523bcfe..32d2f3b26cb0 100644 --- a/tests/ui/delegation/bad-resolve.stderr +++ b/tests/ui/delegation/bad-resolve.stderr @@ -25,6 +25,15 @@ LL | reuse ::baz; | | help: there is an associated function with a similar name: `bar` | not a member of trait `Trait` +error[E0407]: method `foo2` is not a member of trait `Trait` + --> $DIR/bad-resolve.rs:37:5 + | +LL | reuse Trait::foo2 { self.0 } + | ^^^^^^^^^^^^^----^^^^^^^^^^^ + | | | + | | help: there is an associated function with a similar name: `foo` + | not a member of trait `Trait` + error[E0423]: expected function, found associated constant `Trait::C` --> $DIR/bad-resolve.rs:24:11 | @@ -54,6 +63,15 @@ error[E0425]: cannot find function `foo` in this scope LL | reuse foo { &self.0 } | ^^^ not found in this scope +error[E0425]: cannot find function `foo2` in trait `Trait` + --> $DIR/bad-resolve.rs:37:18 + | +LL | fn foo(&self, x: i32) -> i32 { x } + | ---------------------------- similarly named associated function `foo` defined here +... +LL | reuse Trait::foo2 { self.0 } + | ^^^^ help: an associated function with a similar name exists: `foo` + error[E0046]: not all trait items implemented, missing: `Type` --> $DIR/bad-resolve.rs:22:1 | @@ -64,18 +82,18 @@ LL | impl Trait for S { | ^^^^^^^^^^^^^^^^ missing `Type` in implementation error[E0433]: failed to resolve: use of undeclared crate or module `unresolved_prefix` - --> $DIR/bad-resolve.rs:40:7 + --> $DIR/bad-resolve.rs:43:7 | LL | reuse unresolved_prefix::{a, b, c}; | ^^^^^^^^^^^^^^^^^ use of undeclared crate or module `unresolved_prefix` error[E0433]: failed to resolve: `crate` in paths can only be used in start position - --> $DIR/bad-resolve.rs:41:29 + --> $DIR/bad-resolve.rs:44:29 | LL | reuse prefix::{self, super, crate}; | ^^^^^ `crate` in paths can only be used in start position -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors Some errors have detailed explanations: E0046, E0324, E0407, E0423, E0425, E0433, E0575, E0576. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/delegation/explicit-paths-pass.rs b/tests/ui/delegation/explicit-paths-pass.rs index fada793bd118..dd0ee2c732f5 100644 --- a/tests/ui/delegation/explicit-paths-pass.rs +++ b/tests/ui/delegation/explicit-paths-pass.rs @@ -24,8 +24,8 @@ reuse to_reuse::zero_args { self } struct S(F); impl Trait for S { - reuse Trait::bar { &self.0 } - reuse Trait::description { &self.0 } + reuse Trait::bar { self.0 } + reuse Trait::description { self.0 } reuse ::static_method; reuse ::static_method2 { S::static_method(self) } } diff --git a/tests/ui/delegation/explicit-paths.rs b/tests/ui/delegation/explicit-paths.rs index a91ca4cb931e..d42e305b252f 100644 --- a/tests/ui/delegation/explicit-paths.rs +++ b/tests/ui/delegation/explicit-paths.rs @@ -34,7 +34,7 @@ mod inherent_impl_assoc_fn_to_other { use crate::*; impl S { - reuse Trait::foo1 { &self.0 } + reuse Trait::foo1 { self.0 } reuse ::foo2; reuse to_reuse::foo3; reuse F::foo4 { &self.0 } @@ -46,7 +46,7 @@ mod trait_impl_assoc_fn_to_other { use crate::*; impl Trait for S { - reuse Trait::foo1 { &self.0 } + reuse Trait::foo1 { self.0 } reuse ::foo2; reuse to_reuse::foo3; //~^ ERROR method `foo3` is not a member of trait `Trait` diff --git a/tests/ui/delegation/explicit-paths.stderr b/tests/ui/delegation/explicit-paths.stderr index d33c5da4377b..b5afe19f8789 100644 --- a/tests/ui/delegation/explicit-paths.stderr +++ b/tests/ui/delegation/explicit-paths.stderr @@ -91,10 +91,17 @@ error[E0308]: mismatched types LL | trait Trait2 : Trait { | -------------------- found this type parameter LL | reuse ::foo1 { self } - | ^^^^ expected `&F`, found `&Self` + | ---- ^^^^ expected `&F`, found `&Self` + | | + | arguments to this function are incorrect | = note: expected reference `&F` found reference `&Self` +note: method defined here + --> $DIR/explicit-paths.rs:5:8 + | +LL | fn foo1(&self, x: i32) -> i32 { x } + | ^^^^ ----- error[E0277]: the trait bound `S2: Trait` is not satisfied --> $DIR/explicit-paths.rs:78:16 diff --git a/tests/ui/delegation/ice-issue-122550.stderr b/tests/ui/delegation/ice-issue-122550.stderr index c92170644e78..1a01bee3e1e2 100644 --- a/tests/ui/delegation/ice-issue-122550.stderr +++ b/tests/ui/delegation/ice-issue-122550.stderr @@ -4,15 +4,6 @@ error[E0308]: mismatched types LL | fn description(&self) -> &str {} | ^^ expected `&str`, found `()` -error[E0308]: mismatched types - --> $DIR/ice-issue-122550.rs:13:39 - | -LL | reuse ::description { &self.0 } - | ^^^^^^^ expected `&S`, found `&F` - | - = note: expected reference `&S` - found reference `&F` - error[E0277]: the trait bound `S: Trait` is not satisfied --> $DIR/ice-issue-122550.rs:13:12 | @@ -25,6 +16,22 @@ help: this trait has no implementations, consider adding one LL | trait Trait { | ^^^^^^^^^^^ +error[E0308]: mismatched types + --> $DIR/ice-issue-122550.rs:13:39 + | +LL | reuse ::description { &self.0 } + | ----------- ^^^^^^^ expected `&S`, found `&F` + | | + | arguments to this function are incorrect + | + = note: expected reference `&S` + found reference `&F` +note: method defined here + --> $DIR/ice-issue-122550.rs:5:8 + | +LL | fn description(&self) -> &str {} + | ^^^^^^^^^^^ ----- + error: aborting due to 3 previous errors Some errors have detailed explanations: E0277, E0308. diff --git a/tests/ui/delegation/method-call-choice.rs b/tests/ui/delegation/method-call-choice.rs new file mode 100644 index 000000000000..8d53d8bfdb72 --- /dev/null +++ b/tests/ui/delegation/method-call-choice.rs @@ -0,0 +1,25 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn foo(&self) {} +} + +struct F; +impl Trait for F {} +struct S(F); + +pub mod to_reuse { + use crate::F; + + pub fn foo(_: &F) {} +} + +impl Trait for S { + // Make sure that the method call is not generated if the path resolution + // does not have a `self` parameter. + reuse to_reuse::foo { self.0 } + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/delegation/method-call-choice.stderr b/tests/ui/delegation/method-call-choice.stderr new file mode 100644 index 000000000000..6757af20a6b3 --- /dev/null +++ b/tests/ui/delegation/method-call-choice.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/method-call-choice.rs:21:27 + | +LL | reuse to_reuse::foo { self.0 } + | --- ^^^^^^ expected `&F`, found `F` + | | + | arguments to this function are incorrect + | +note: function defined here + --> $DIR/method-call-choice.rs:15:12 + | +LL | pub fn foo(_: &F) {} + | ^^^ ----- +help: consider borrowing here + | +LL | reuse to_reuse::foo { &self.0 } + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/delegation/method-call-priority.rs b/tests/ui/delegation/method-call-priority.rs new file mode 100644 index 000000000000..8d68740d181a --- /dev/null +++ b/tests/ui/delegation/method-call-priority.rs @@ -0,0 +1,34 @@ +//@ run-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] +#![allow(dead_code)] + +trait Trait1 { + fn foo(&self) -> i32 { 1 } +} + +trait Trait2 { + fn foo(&self) -> i32 { 2 } +} + +struct F; +impl Trait1 for F {} +impl Trait2 for F {} + +impl F { + fn foo(&self) -> i32 { 3 } +} + +struct S(F); + +impl Trait1 for S { + // Make sure that the generated `self.0.foo()` does not turn into the inherent method `F::foo` + // that has a higher priority than methods from traits. + reuse Trait1::foo { self.0 } +} + +fn main() { + let s = S(F); + assert_eq!(s.foo(), 1); +} diff --git a/tests/ui/delegation/self-coercion.rs b/tests/ui/delegation/self-coercion.rs new file mode 100644 index 000000000000..96c1f1b140b1 --- /dev/null +++ b/tests/ui/delegation/self-coercion.rs @@ -0,0 +1,26 @@ +//@ run-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait : Sized { + fn by_value(self) -> i32 { 1 } + fn by_mut_ref(&mut self) -> i32 { 2 } + fn by_ref(&self) -> i32 { 3 } +} + +struct F; +impl Trait for F {} + +struct S(F); + +impl Trait for S { + reuse Trait::{by_value, by_mut_ref, by_ref} { self.0 } +} + +fn main() { + let mut s = S(F); + assert_eq!(s.by_ref(), 3); + assert_eq!(s.by_mut_ref(), 2); + assert_eq!(s.by_value(), 1); +} From 1e8606408d14e2509f59c0a87c02788cb112b55a Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 16 Jul 2024 16:35:23 +0200 Subject: [PATCH 177/734] add more tests for `cmse-nonsecure-call` stack spills --- .../params-on-registers.rs | 24 ----- .../cmse-nonsecure-call/params-on-stack.rs | 24 ----- .../params-on-stack.stderr | 14 --- .../cmse-nonsecure-call/params-via-stack.rs | 29 ++++++ .../params-via-stack.stderr | 58 +++++++++++ .../cmse-nonsecure-call/return-via-stack.rs | 41 ++++++++ .../return-via-stack.stderr | 97 +++++++++++++++++++ .../cmse-nonsecure-call/via-registers.rs | 55 +++++++++++ 8 files changed, 280 insertions(+), 62 deletions(-) delete mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs delete mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs delete mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.stderr create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs deleted file mode 100644 index 364d0858afb9..000000000000 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ build-pass -//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib -//@ needs-llvm-components: arm -#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)] -#![no_core] -#[lang="sized"] -pub trait Sized { } -#[lang="copy"] -pub trait Copy { } -impl Copy for u32 {} - -extern "rust-intrinsic" { - pub fn transmute(e: T) -> U; -} - -#[no_mangle] -pub fn test(a: u32, b: u32, c: u32, d: u32) -> u32 { - let non_secure_function = unsafe { - transmute:: u32>( - 0x10000004, - ) - }; - non_secure_function(a, b, c, d) -} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs deleted file mode 100644 index f13e81d00608..000000000000 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ build-fail -//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib -//@ needs-llvm-components: arm -#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)] -#![no_core] -#[lang = "sized"] -pub trait Sized {} -#[lang = "copy"] -pub trait Copy {} -impl Copy for u32 {} - -extern "rust-intrinsic" { - pub fn transmute(e: T) -> U; -} - -#[no_mangle] -pub fn test(a: u32, b: u32, c: u32, d: u32, e: u32) -> u32 { - let non_secure_function = unsafe { - transmute:: u32>( - 0x10000004, - ) - }; - non_secure_function(a, b, c, d, e) //~ ERROR [E0798] -} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.stderr deleted file mode 100644 index ee4effa56d4a..000000000000 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0798]: arguments for `C-cmse-nonsecure-call` function too large to pass via registers - --> $DIR/params-on-stack.rs:23:5 - | -LL | let non_secure_function = unsafe { - | ------------------- this function uses the `C-cmse-nonsecure-call` ABI -... -LL | non_secure_function(a, b, c, d, e) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ but its arguments don't fit in the available registers - | - = note: functions with the `C-cmse-nonsecure-call` ABI must pass all their arguments via the 4 32-bit available argument registers - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0798`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs new file mode 100644 index 000000000000..a4cc74f716f1 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs @@ -0,0 +1,29 @@ +//@ build-fail +//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +//@ needs-llvm-components: arm +#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)] +#![no_core] +#[lang = "sized"] +pub trait Sized {} +#[lang = "copy"] +pub trait Copy {} +impl Copy for u32 {} + +#[repr(C, align(16))] +#[allow(unused)] +pub struct AlignRelevant(u32); + +#[no_mangle] +pub fn test( + f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32, + f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u16, u16) -> u32, + f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32) -> u32, + f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32) -> u32, + f5: extern "C-cmse-nonsecure-call" fn([u32; 5]) -> u32, +) { + f1(1, 2, 3, 4, 5); //~ ERROR [E0798] + f2(1, 2, 3, 4, 5); //~ ERROR [E0798] + f3(1, 2, 3); //~ ERROR [E0798] + f4(AlignRelevant(1), 2); //~ ERROR [E0798] + f5([0xAA; 5]); //~ ERROR [E0798] +} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr new file mode 100644 index 000000000000..b161c90d01ac --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr @@ -0,0 +1,58 @@ +error[E0798]: arguments for `C-cmse-nonsecure-call` function too large to pass via registers + --> $DIR/params-via-stack.rs:24:5 + | +LL | f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32, + | -- this function uses the `C-cmse-nonsecure-call` ABI +... +LL | f1(1, 2, 3, 4, 5); + | ^^^^^^^^^^^^^^^^^ but its arguments don't fit in the available registers + | + = note: functions with the `C-cmse-nonsecure-call` ABI must pass all their arguments via the 4 32-bit available argument registers + +error[E0798]: arguments for `C-cmse-nonsecure-call` function too large to pass via registers + --> $DIR/params-via-stack.rs:25:5 + | +LL | f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u16, u16) -> u32, + | -- this function uses the `C-cmse-nonsecure-call` ABI +... +LL | f2(1, 2, 3, 4, 5); + | ^^^^^^^^^^^^^^^^^ but its arguments don't fit in the available registers + | + = note: functions with the `C-cmse-nonsecure-call` ABI must pass all their arguments via the 4 32-bit available argument registers + +error[E0798]: arguments for `C-cmse-nonsecure-call` function too large to pass via registers + --> $DIR/params-via-stack.rs:26:5 + | +LL | f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32) -> u32, + | -- this function uses the `C-cmse-nonsecure-call` ABI +... +LL | f3(1, 2, 3); + | ^^^^^^^^^^^ but its arguments don't fit in the available registers + | + = note: functions with the `C-cmse-nonsecure-call` ABI must pass all their arguments via the 4 32-bit available argument registers + +error[E0798]: arguments for `C-cmse-nonsecure-call` function too large to pass via registers + --> $DIR/params-via-stack.rs:27:5 + | +LL | f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32) -> u32, + | -- this function uses the `C-cmse-nonsecure-call` ABI +... +LL | f4(AlignRelevant(1), 2); + | ^^^^^^^^^^^^^^^^^^^^^^^ but its arguments don't fit in the available registers + | + = note: functions with the `C-cmse-nonsecure-call` ABI must pass all their arguments via the 4 32-bit available argument registers + +error[E0798]: arguments for `C-cmse-nonsecure-call` function too large to pass via registers + --> $DIR/params-via-stack.rs:28:5 + | +LL | f5: extern "C-cmse-nonsecure-call" fn([u32; 5]) -> u32, + | -- this function uses the `C-cmse-nonsecure-call` ABI +... +LL | f5([0xAA; 5]); + | ^^^^^^^^^^^^^ but its arguments don't fit in the available registers + | + = note: functions with the `C-cmse-nonsecure-call` ABI must pass all their arguments via the 4 32-bit available argument registers + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0798`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs new file mode 100644 index 000000000000..c417dddac4ff --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs @@ -0,0 +1,41 @@ +//@ build-fail +//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +//@ needs-llvm-components: arm +#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)] +#![no_core] +#[lang = "sized"] +pub trait Sized {} +#[lang = "copy"] +pub trait Copy {} +impl Copy for u32 {} + +#[repr(C)] +pub struct ReprCU64(u64); + +#[repr(C)] +pub struct ReprCBytes(u8, u8, u8, u8, u8); + +#[repr(C)] +pub struct U64Compound(u32, u32); + +#[repr(C, align(16))] +pub struct ReprCAlign16(u16); + +#[no_mangle] +pub fn test( + f1: extern "C-cmse-nonsecure-call" fn() -> ReprCU64, + f2: extern "C-cmse-nonsecure-call" fn() -> ReprCBytes, + f3: extern "C-cmse-nonsecure-call" fn() -> U64Compound, + f4: extern "C-cmse-nonsecure-call" fn() -> ReprCAlign16, + f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 5], + f6: extern "C-cmse-nonsecure-call" fn() -> u128, //~ WARNING [improper_ctypes_definitions] + f7: extern "C-cmse-nonsecure-call" fn() -> i128, //~ WARNING [improper_ctypes_definitions] +) { + f1(); //~ ERROR [E0798] + f2(); //~ ERROR [E0798] + f3(); //~ ERROR [E0798] + f4(); //~ ERROR [E0798] + f5(); //~ ERROR [E0798] + f6(); //~ ERROR [E0798] + f7(); //~ ERROR [E0798] +} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr new file mode 100644 index 000000000000..6dea0cf68a0d --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr @@ -0,0 +1,97 @@ +warning: `extern` fn uses type `u128`, which is not FFI-safe + --> $DIR/return-via-stack.rs:31:9 + | +LL | f6: extern "C-cmse-nonsecure-call" fn() -> u128, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = note: 128-bit integers don't currently have a known stable ABI + = note: `#[warn(improper_ctypes_definitions)]` on by default + +warning: `extern` fn uses type `i128`, which is not FFI-safe + --> $DIR/return-via-stack.rs:32:9 + | +LL | f7: extern "C-cmse-nonsecure-call" fn() -> i128, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = note: 128-bit integers don't currently have a known stable ABI + +error[E0798]: return value of `C-cmse-nonsecure-call` function too large to pass via registers + --> $DIR/return-via-stack.rs:34:5 + | +LL | f1: extern "C-cmse-nonsecure-call" fn() -> ReprCU64, + | -- this function uses the `C-cmse-nonsecure-call` ABI +... +LL | f1(); + | ^^^^ but its return value doesn't fit in the available registers + | + = note: functions with the `C-cmse-nonsecure-call` ABI must pass their result via the available return registers + +error[E0798]: return value of `C-cmse-nonsecure-call` function too large to pass via registers + --> $DIR/return-via-stack.rs:35:5 + | +LL | f2: extern "C-cmse-nonsecure-call" fn() -> ReprCBytes, + | -- this function uses the `C-cmse-nonsecure-call` ABI +... +LL | f2(); + | ^^^^ but its return value doesn't fit in the available registers + | + = note: functions with the `C-cmse-nonsecure-call` ABI must pass their result via the available return registers + +error[E0798]: return value of `C-cmse-nonsecure-call` function too large to pass via registers + --> $DIR/return-via-stack.rs:36:5 + | +LL | f3: extern "C-cmse-nonsecure-call" fn() -> U64Compound, + | -- this function uses the `C-cmse-nonsecure-call` ABI +... +LL | f3(); + | ^^^^ but its return value doesn't fit in the available registers + | + = note: functions with the `C-cmse-nonsecure-call` ABI must pass their result via the available return registers + +error[E0798]: return value of `C-cmse-nonsecure-call` function too large to pass via registers + --> $DIR/return-via-stack.rs:37:5 + | +LL | f4: extern "C-cmse-nonsecure-call" fn() -> ReprCAlign16, + | -- this function uses the `C-cmse-nonsecure-call` ABI +... +LL | f4(); + | ^^^^ but its return value doesn't fit in the available registers + | + = note: functions with the `C-cmse-nonsecure-call` ABI must pass their result via the available return registers + +error[E0798]: return value of `C-cmse-nonsecure-call` function too large to pass via registers + --> $DIR/return-via-stack.rs:38:5 + | +LL | f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 5], + | -- this function uses the `C-cmse-nonsecure-call` ABI +... +LL | f5(); + | ^^^^ but its return value doesn't fit in the available registers + | + = note: functions with the `C-cmse-nonsecure-call` ABI must pass their result via the available return registers + +error[E0798]: return value of `C-cmse-nonsecure-call` function too large to pass via registers + --> $DIR/return-via-stack.rs:39:5 + | +LL | f6: extern "C-cmse-nonsecure-call" fn() -> u128, + | -- this function uses the `C-cmse-nonsecure-call` ABI +... +LL | f6(); + | ^^^^ but its return value doesn't fit in the available registers + | + = note: functions with the `C-cmse-nonsecure-call` ABI must pass their result via the available return registers + +error[E0798]: return value of `C-cmse-nonsecure-call` function too large to pass via registers + --> $DIR/return-via-stack.rs:40:5 + | +LL | f7: extern "C-cmse-nonsecure-call" fn() -> i128, + | -- this function uses the `C-cmse-nonsecure-call` ABI +... +LL | f7(); + | ^^^^ but its return value doesn't fit in the available registers + | + = note: functions with the `C-cmse-nonsecure-call` ABI must pass their result via the available return registers + +error: aborting due to 7 previous errors; 2 warnings emitted + +For more information about this error, try `rustc --explain E0798`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs new file mode 100644 index 000000000000..72b405ef2820 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs @@ -0,0 +1,55 @@ +//@ build-pass +//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +//@ needs-llvm-components: arm +#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)] +#![no_core] +#[lang = "sized"] +pub trait Sized {} +#[lang = "copy"] +pub trait Copy {} +impl Copy for u32 {} + +#[repr(transparent)] +pub struct ReprTransparentU64(u64); + +#[repr(C)] +pub struct U32Compound(u16, u16); + +#[no_mangle] +#[allow(improper_ctypes_definitions)] +pub fn params( + f1: extern "C-cmse-nonsecure-call" fn(), + f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32), + f3: extern "C-cmse-nonsecure-call" fn(u64, u64), + f4: extern "C-cmse-nonsecure-call" fn(u128), + f5: extern "C-cmse-nonsecure-call" fn(f64, f32, f32), + f6: extern "C-cmse-nonsecure-call" fn(ReprTransparentU64, U32Compound), + f7: extern "C-cmse-nonsecure-call" fn([u32; 4]), +) { + f1(); + f2(1, 2, 3, 4); + f3(1, 2); + f4(1); + f5(1.0, 2.0, 3.0); + f6(ReprTransparentU64(1), U32Compound(2, 3)); + f7([0xDEADBEEF; 4]); +} + +#[no_mangle] +pub fn returns( + f1: extern "C-cmse-nonsecure-call" fn() -> u32, + f2: extern "C-cmse-nonsecure-call" fn() -> u64, + f3: extern "C-cmse-nonsecure-call" fn() -> i64, + f4: extern "C-cmse-nonsecure-call" fn() -> f64, + f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 4], + f6: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentU64, + f7: extern "C-cmse-nonsecure-call" fn() -> U32Compound, +) { + f1(); + f2(); + f3(); + f4(); + f5(); + f6(); + f7(); +} From 6ce78bea030855d3a0e391adad810afa22568636 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sat, 6 Jul 2024 19:21:22 +0000 Subject: [PATCH 178/734] Update method name to reflect changes to its internals --- compiler/rustc_resolve/src/build_reduced_graph.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 92cf73870ff1..ced5ac17dacb 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -316,7 +316,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } } - fn insert_field_def_ids(&mut self, def_id: LocalDefId, fields: &[ast::FieldDef]) { + fn insert_field_idents(&mut self, def_id: LocalDefId, fields: &[ast::FieldDef]) { if fields.iter().any(|field| field.is_placeholder) { // The fields are not expanded yet. return; @@ -652,7 +652,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let def_id = feed.key(); // Record field names for error reporting. - self.insert_field_def_ids(def_id, fields); + self.insert_field_idents(def_id, fields); self.insert_field_visibilities_local(def_id.to_def_id(), fields); for field in fields { @@ -1520,7 +1520,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { } // Record field names for error reporting. - self.insert_field_def_ids(def_id, variant.data.fields()); + self.insert_field_idents(def_id, variant.data.fields()); self.insert_field_visibilities_local(def_id.to_def_id(), variant.data.fields()); visit::walk_variant(self, variant); From 9a4c1058fac8cbbf771740928ec9a954b451c653 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 8 Jul 2024 09:48:12 +0000 Subject: [PATCH 179/734] Just store a span instead of the whole item --- compiler/rustc_ast_passes/src/ast_validation.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index dd0d904c52cc..507329cc899f 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -81,7 +81,7 @@ struct AstValidator<'a> { features: &'a Features, /// The span of the `extern` in an `extern { ... }` block, if any. - extern_mod: Option<&'a Item>, + extern_mod: Option, outer_trait_or_trait_impl: Option>, @@ -579,7 +579,7 @@ impl<'a> AstValidator<'a> { } fn current_extern_span(&self) -> Span { - self.session.source_map().guess_head_span(self.extern_mod.unwrap().span) + self.session.source_map().guess_head_span(self.extern_mod.unwrap()) } /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`. @@ -1080,7 +1080,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ItemKind::ForeignMod(ForeignMod { abi, safety, .. }) => { self.with_in_extern_mod(*safety, |this| { - let old_item = mem::replace(&mut this.extern_mod, Some(item)); + let old_item = mem::replace(&mut this.extern_mod, Some(item.span)); this.visibility_not_permitted( &item.vis, errors::VisibilityNotPermittedNote::IndividualForeignItems, From b879e29864c30d2bb2be2fffb910d66f0f4e9773 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 9 Jul 2024 08:54:11 +0000 Subject: [PATCH 180/734] Remove a needless borrow --- compiler/rustc_ast_passes/src/ast_validation.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 507329cc899f..45c6211598be 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -61,12 +61,12 @@ enum DisallowTildeConstContext<'a> { Item, } -enum TraitOrTraitImpl<'a> { +enum TraitOrTraitImpl { Trait { span: Span, constness: Option }, - TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref: &'a TraitRef }, + TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref: Span }, } -impl<'a> TraitOrTraitImpl<'a> { +impl TraitOrTraitImpl { fn constness(&self) -> Option { match self { Self::Trait { constness: Some(span), .. } @@ -83,7 +83,7 @@ struct AstValidator<'a> { /// The span of the `extern` in an `extern { ... }` block, if any. extern_mod: Option, - outer_trait_or_trait_impl: Option>, + outer_trait_or_trait_impl: Option, has_proc_macro_decls: bool, @@ -115,7 +115,7 @@ impl<'a> AstValidator<'a> { trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl { constness, polarity, - trait_ref, + trait_ref: trait_ref.path.span, }), ); f(self); @@ -354,7 +354,7 @@ impl<'a> AstValidator<'a> { } } - fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl<'a>) { + fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl) { let Const::Yes(span) = constness else { return; }; @@ -367,7 +367,7 @@ impl<'a> AstValidator<'a> { .. } = parent { - Some(trait_ref.path.span.shrink_to_lo()) + Some(trait_ref.shrink_to_lo()) } else { None }; From d9f959292464c7bd68672801a42113e5b6d262b8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 9 Jul 2024 09:54:19 +0000 Subject: [PATCH 181/734] Remove a boilerplaty abstraction --- .../rustc_ast_passes/src/ast_validation.rs | 76 ++++--------------- compiler/rustc_ast_passes/src/errors.rs | 2 +- 2 files changed, 17 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 45c6211598be..e6cc2e4069b7 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -38,7 +38,7 @@ use std::mem; use std::ops::{Deref, DerefMut}; use thin_vec::thin_vec; -use crate::errors; +use crate::errors::{self, TildeConstReason}; /// Is `self` allowed semantically as the first parameter in an `FnDecl`? enum SelfSemantic { @@ -46,21 +46,6 @@ enum SelfSemantic { No, } -/// What is the context that prevents using `~const`? -// FIXME(effects): Consider getting rid of this in favor of `errors::TildeConstReason`, they're -// almost identical. This gets rid of an abstraction layer which might be considered bad. -enum DisallowTildeConstContext<'a> { - TraitObject, - Fn(FnKind<'a>), - Trait(Span), - TraitImpl(Span), - Impl(Span), - TraitAssocTy(Span), - TraitImplAssocTy(Span), - InherentAssocTy(Span), - Item, -} - enum TraitOrTraitImpl { Trait { span: Span, constness: Option }, TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref: Span }, @@ -92,7 +77,7 @@ struct AstValidator<'a> { /// e.g., `impl Iterator`. outer_impl_trait: Option, - disallow_tilde_const: Option>, + disallow_tilde_const: Option, /// Used to ban `impl Trait` in path projections like `::Item` /// or `Foo::Bar` @@ -145,7 +130,7 @@ impl<'a> AstValidator<'a> { fn with_tilde_const( &mut self, - disallowed: Option>, + disallowed: Option, f: impl FnOnce(&mut Self), ) { let old = mem::replace(&mut self.disallow_tilde_const, disallowed); @@ -224,7 +209,7 @@ impl<'a> AstValidator<'a> { } } TyKind::TraitObject(..) => self - .with_tilde_const(Some(DisallowTildeConstContext::TraitObject), |this| { + .with_tilde_const(Some(TildeConstReason::TraitObject), |this| { visit::walk_ty(this, t) }), TyKind::Path(qself, path) => { @@ -980,7 +965,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { this.visit_vis(&item.vis); this.visit_ident(item.ident); let disallowed = matches!(constness, Const::No) - .then(|| DisallowTildeConstContext::TraitImpl(item.span)); + .then(|| TildeConstReason::TraitImpl { span: item.span }); this.with_tilde_const(disallowed, |this| this.visit_generics(generics)); this.visit_trait_ref(t); this.visit_ty(self_ty); @@ -1035,7 +1020,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { this.visit_vis(&item.vis); this.visit_ident(item.ident); this.with_tilde_const( - Some(DisallowTildeConstContext::Impl(item.span)), + Some(TildeConstReason::Impl { span: item.span }), |this| this.visit_generics(generics), ); this.visit_ty(self_ty); @@ -1154,7 +1139,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { this.visit_ident(item.ident); let disallowed = is_const_trait .is_none() - .then(|| DisallowTildeConstContext::Trait(item.span)); + .then(|| TildeConstReason::Trait { span: item.span }); this.with_tilde_const(disallowed, |this| { this.visit_generics(generics); walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) @@ -1399,40 +1384,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.dcx().emit_err(errors::ConstBoundTraitObject { span: trait_ref.span }); } (_, BoundConstness::Maybe(span), BoundPolarity::Positive) - if let Some(reason) = &self.disallow_tilde_const => + if let Some(reason) = self.disallow_tilde_const => { - let reason = match reason { - DisallowTildeConstContext::Fn(FnKind::Closure(..)) => { - errors::TildeConstReason::Closure - } - DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => { - errors::TildeConstReason::Function { ident: ident.span } - } - &DisallowTildeConstContext::Trait(span) => { - errors::TildeConstReason::Trait { span } - } - &DisallowTildeConstContext::TraitImpl(span) => { - errors::TildeConstReason::TraitImpl { span } - } - &DisallowTildeConstContext::Impl(span) => { - // FIXME(effects): Consider providing a help message or even a structured - // suggestion for moving such bounds to the assoc const fns if available. - errors::TildeConstReason::Impl { span } - } - &DisallowTildeConstContext::TraitAssocTy(span) => { - errors::TildeConstReason::TraitAssocTy { span } - } - &DisallowTildeConstContext::TraitImplAssocTy(span) => { - errors::TildeConstReason::TraitImplAssocTy { span } - } - &DisallowTildeConstContext::InherentAssocTy(span) => { - errors::TildeConstReason::InherentAssocTy { span } - } - DisallowTildeConstContext::TraitObject => { - errors::TildeConstReason::TraitObject - } - DisallowTildeConstContext::Item => errors::TildeConstReason::Item, - }; self.dcx().emit_err(errors::TildeConstDisallowed { span, reason }); } ( @@ -1569,7 +1522,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .and_then(TraitOrTraitImpl::constness) .is_some(); - let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk)); + let disallowed = (!tilde_const_allowed).then(|| match fk { + FnKind::Fn(_, ident, _, _, _, _) => TildeConstReason::Function { ident: ident.span }, + FnKind::Closure(_, _, _) => TildeConstReason::Closure, + }); self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk)); } @@ -1664,12 +1620,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { AssocItemKind::Type(_) => { let disallowed = (!parent_is_const).then(|| match self.outer_trait_or_trait_impl { Some(TraitOrTraitImpl::Trait { .. }) => { - DisallowTildeConstContext::TraitAssocTy(item.span) + TildeConstReason::TraitAssocTy { span: item.span } } Some(TraitOrTraitImpl::TraitImpl { .. }) => { - DisallowTildeConstContext::TraitImplAssocTy(item.span) + TildeConstReason::TraitImplAssocTy { span: item.span } } - None => DisallowTildeConstContext::InherentAssocTy(item.span), + None => TildeConstReason::InherentAssocTy { span: item.span }, }); self.with_tilde_const(disallowed, |this| { this.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)) @@ -1852,7 +1808,7 @@ pub fn check_crate( outer_trait_or_trait_impl: None, has_proc_macro_decls: false, outer_impl_trait: None, - disallow_tilde_const: Some(DisallowTildeConstContext::Item), + disallow_tilde_const: Some(TildeConstReason::Item), is_impl_trait_banned: false, extern_mod_safety: None, lint_buffer: lints, diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index bfb904764501..2c18b47f0f7f 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -612,7 +612,7 @@ pub struct TildeConstDisallowed { pub reason: TildeConstReason, } -#[derive(Subdiagnostic)] +#[derive(Subdiagnostic, Copy, Clone)] pub enum TildeConstReason { #[note(ast_passes_closure)] Closure, From 117ff0a4fd11c5a71766ce76bf4b4467abd7ddf1 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 9 Jul 2024 11:22:09 +0000 Subject: [PATCH 182/734] Fix a bunch of sites that were walking instead of visiting, making it impossible for visitor impls to look at these values --- compiler/rustc_ast/src/mut_visit.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 1c1163551db5..39d0f2c7305f 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -482,7 +482,7 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { TyKind::Slice(ty) => vis.visit_ty(ty), TyKind::Ptr(mt) => vis.visit_mt(mt), TyKind::Ref(lt, mt) => { - visit_opt(lt, |lt| noop_visit_lifetime(lt, vis)); + visit_opt(lt, |lt| vis.visit_lifetime(lt)); vis.visit_mt(mt); } TyKind::BareFn(bft) => { @@ -925,7 +925,7 @@ pub fn noop_flat_map_generic_param( vis.visit_id(id); visit_attrs(attrs, vis); vis.visit_ident(ident); - visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis)); + visit_vec(bounds, |bound| vis.visit_param_bound(bound)); match kind { GenericParamKind::Lifetime => {} GenericParamKind::Type { default } => { @@ -983,7 +983,7 @@ fn noop_visit_where_predicate(pred: &mut WherePredicate, vis: &mu } WherePredicate::RegionPredicate(rp) => { let WhereRegionPredicate { span, lifetime, bounds } = rp; - noop_visit_lifetime(lifetime, vis); + vis.visit_lifetime(lifetime); visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis)); vis.visit_span(span); } From d0a1851ec2cf84bdb41bc4d788b3995a8463c543 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 20 Jun 2024 16:36:35 -0400 Subject: [PATCH 183/734] Deny keyword lifetimes pre-expansion --- compiler/rustc_ast_passes/messages.ftl | 6 ---- .../rustc_ast_passes/src/ast_validation.rs | 30 ------------------- compiler/rustc_ast_passes/src/errors.rs | 15 ---------- compiler/rustc_parse/messages.ftl | 6 ++++ compiler/rustc_parse/src/errors.rs | 15 ++++++++++ compiler/rustc_parse/src/parser/expr.rs | 13 ++++++-- .../rustc_parse/src/parser/nonterminal.rs | 7 +++-- compiler/rustc_parse/src/parser/pat.rs | 8 ++--- compiler/rustc_parse/src/parser/ty.rs | 6 ++++ tests/ui/parser/cfg-keyword-lifetime.rs | 15 ++++++++++ tests/ui/parser/cfg-keyword-lifetime.stderr | 14 +++++++++ .../require-parens-for-chained-comparison.rs | 2 ++ ...quire-parens-for-chained-comparison.stderr | 20 ++++++++++--- tests/ui/self/self_type_keyword.stderr | 12 ++++---- 14 files changed, 99 insertions(+), 70 deletions(-) create mode 100644 tests/ui/parser/cfg-keyword-lifetime.rs create mode 100644 tests/ui/parser/cfg-keyword-lifetime.stderr diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 7da726ef4086..02bdff96aa6d 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -159,9 +159,6 @@ ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation} .type = inherent impl for this type .only_trait = only trait implementations may be annotated with {$annotation} -ast_passes_invalid_label = - invalid label name `{$name}` - ast_passes_invalid_unnamed_field = unnamed fields are not allowed outside of structs or unions .label = unnamed field declared here @@ -176,9 +173,6 @@ ast_passes_item_invalid_safety = items outside of `unsafe extern {"{ }"}` cannot ast_passes_item_underscore = `{$kind}` items in this context need a name .label = `_` is not a valid name for this `{$kind}` item -ast_passes_keyword_lifetime = - lifetimes cannot use keyword names - ast_passes_match_arm_with_no_body = `match` arm with no body .suggestion = add a body after the pattern diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index dd0d904c52cc..f33176c0b323 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -284,19 +284,6 @@ impl<'a> AstValidator<'a> { self.session.dcx() } - fn check_lifetime(&self, ident: Ident) { - let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty]; - if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() { - self.dcx().emit_err(errors::KeywordLifetime { span: ident.span }); - } - } - - fn check_label(&self, ident: Ident) { - if ident.without_first_quote().is_reserved() { - self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name }); - } - } - fn visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote) { if let VisibilityKind::Inherited = vis.kind { return; @@ -923,16 +910,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.walk_ty(ty) } - fn visit_label(&mut self, label: &'a Label) { - self.check_label(label.ident); - visit::walk_label(self, label); - } - - fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) { - self.check_lifetime(lifetime.ident); - visit::walk_lifetime(self, lifetime); - } - fn visit_field_def(&mut self, field: &'a FieldDef) { self.deny_unnamed_field(field); visit::walk_field_def(self, field) @@ -1371,13 +1348,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } - fn visit_generic_param(&mut self, param: &'a GenericParam) { - if let GenericParamKind::Lifetime { .. } = param.kind { - self.check_lifetime(param.ident); - } - visit::walk_generic_param(self, param); - } - fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) { match bound { GenericBound::Trait(trait_ref, modifiers) => { diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index bfb904764501..4dff4ecfae03 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -9,21 +9,6 @@ use rustc_span::{symbol::Ident, Span, Symbol}; use crate::fluent_generated as fluent; -#[derive(Diagnostic)] -#[diag(ast_passes_keyword_lifetime)] -pub struct KeywordLifetime { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_invalid_label)] -pub struct InvalidLabel { - #[primary_span] - pub span: Span, - pub name: Symbol, -} - #[derive(Diagnostic)] #[diag(ast_passes_visibility_not_permitted, code = E0449)] pub struct VisibilityNotPermitted { diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index c2201b1c41ec..4ce9e0f025c9 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -388,6 +388,9 @@ parse_invalid_dyn_keyword = invalid `dyn` keyword parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else` parse_invalid_identifier_with_leading_number = identifiers cannot start with a number +parse_invalid_label = + invalid label name `{$name}` + parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid .label = invalid suffix `{$suffix}` .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases @@ -414,6 +417,9 @@ parse_invalid_unicode_escape = invalid unicode character escape parse_invalid_variable_declaration = invalid variable declaration +parse_keyword_lifetime = + lifetimes cannot use keyword names + parse_kw_bad_case = keyword `{$kw}` is written in the wrong case .suggestion = write it in the correct case diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 092a2a10ab7b..4222486034ba 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2009,6 +2009,21 @@ pub struct CannotBeRawIdent { pub ident: Symbol, } +#[derive(Diagnostic)] +#[diag(parse_keyword_lifetime)] +pub struct KeywordLifetime { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_invalid_label)] +pub struct InvalidLabel { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + #[derive(Diagnostic)] #[diag(parse_cr_doc_comment)] pub struct CrDocComment { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 4bd20be41712..0ba8c66f48f0 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2932,10 +2932,17 @@ impl<'a> Parser<'a> { } pub(crate) fn eat_label(&mut self) -> Option(); -} diff --git a/tests/mir-opt/const_prop/invalid_constant.rs b/tests/mir-opt/const_prop/invalid_constant.rs index 91ee36ae2c54..b59103792bfc 100644 --- a/tests/mir-opt/const_prop/invalid_constant.rs +++ b/tests/mir-opt/const_prop/invalid_constant.rs @@ -3,7 +3,7 @@ //@ compile-flags: -Zmir-enable-passes=+RemoveZsts // Verify that we can pretty print invalid constants. -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] #[derive(Copy, Clone)] diff --git a/tests/mir-opt/issue_99325.rs b/tests/mir-opt/issue_99325.rs index 2638b69e2ee5..4cee4f20b31b 100644 --- a/tests/mir-opt/issue_99325.rs +++ b/tests/mir-opt/issue_99325.rs @@ -1,7 +1,7 @@ // skip-filecheck // EMIT_MIR_FOR_EACH_BIT_WIDTH -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] pub fn function_with_bytes() -> &'static [u8] { diff --git a/tests/rustdoc/const-generics/const-impl.rs b/tests/rustdoc/const-generics/const-impl.rs index ce536291290d..279a78422541 100644 --- a/tests/rustdoc/const-generics/const-impl.rs +++ b/tests/rustdoc/const-generics/const-impl.rs @@ -1,5 +1,5 @@ #![allow(incomplete_features)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![crate_name = "foo"] use std::marker::ConstParamTy; diff --git a/tests/ui/coherence/negative-coherence/regions-in-canonical.rs b/tests/ui/coherence/negative-coherence/regions-in-canonical.rs index 6c2a11e01358..f0424e724344 100644 --- a/tests/ui/coherence/negative-coherence/regions-in-canonical.rs +++ b/tests/ui/coherence/negative-coherence/regions-in-canonical.rs @@ -1,13 +1,12 @@ //@ check-pass -#![feature(adt_const_params)] -//~^ WARN the feature `adt_const_params` is incomplete +#![feature(adt_const_params, unsized_const_params)] +//~^ WARN the feature `unsized_const_params` is incomplete #![feature(with_negative_coherence, negative_impls)] pub trait A {} pub trait C {} - struct W(T); // Negative coherence: diff --git a/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr b/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr index dc8c926f182b..720449152945 100644 --- a/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr +++ b/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr @@ -1,8 +1,8 @@ -warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/regions-in-canonical.rs:3:12 +warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/regions-in-canonical.rs:3:30 | -LL | #![feature(adt_const_params)] - | ^^^^^^^^^^^^^^^^ +LL | #![feature(adt_const_params, unsized_const_params)] + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #95174 for more information = note: `#[warn(incomplete_features)]` on by default diff --git a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.rs b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.rs index 8035fce09147..e90426ec0c76 100644 --- a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.rs +++ b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(adt_const_params, lazy_type_alias)] -//~^ WARN: the feature `adt_const_params` is incomplete -//~| WARN: the feature `lazy_type_alias` is incomplete +//~^ WARN: the feature `lazy_type_alias` is incomplete pub type Matrix = [usize; 1]; const EMPTY_MATRIX: Matrix = [0; 1]; diff --git a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.stderr b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.stderr index 5c6981077b2d..4f5133474c60 100644 --- a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.stderr +++ b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.stderr @@ -1,12 +1,3 @@ -warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/alias_const_param_ty-1.rs:2:12 - | -LL | #![feature(adt_const_params, lazy_type_alias)] - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #95174 for more information - = note: `#[warn(incomplete_features)]` on by default - warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/alias_const_param_ty-1.rs:2:30 | @@ -14,6 +5,7 @@ LL | #![feature(adt_const_params, lazy_type_alias)] | ^^^^^^^^^^^^^^^ | = note: see issue #112792 for more information + = note: `#[warn(incomplete_features)]` on by default -warning: 2 warnings emitted +warning: 1 warning emitted diff --git a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.rs b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.rs index a576b75341cf..961e1a9cfbf4 100644 --- a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.rs +++ b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.rs @@ -1,6 +1,5 @@ //@ check-pass #![feature(adt_const_params)] -//~^ WARN: the feature `adt_const_params` is incomplete const EMPTY_MATRIX: ::Matrix = [0; 1]; diff --git a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.stderr b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.stderr deleted file mode 100644 index dbc8ab716365..000000000000 --- a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/alias_const_param_ty-2.rs:2:12 - | -LL | #![feature(adt_const_params)] - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #95174 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/const-generics/adt_const_params/auxiliary/unsized_const_param.rs b/tests/ui/const-generics/adt_const_params/auxiliary/unsized_const_param.rs new file mode 100644 index 000000000000..e2ba459f8dd3 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/auxiliary/unsized_const_param.rs @@ -0,0 +1,7 @@ +#![feature(adt_const_params, unsized_const_params)] + +#[derive(std::marker::UnsizedConstParamTy, Eq, PartialEq)] +pub struct Foo([u8]); + +#[derive(std::marker::ConstParamTy, Eq, PartialEq)] +pub struct GenericNotUnsizedParam(T); diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs index c4d2d02ba703..35539193a278 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs @@ -1,13 +1,13 @@ #![allow(incomplete_features)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] -fn check(_: impl std::marker::ConstParamTy) {} +fn check(_: impl std::marker::UnsizedConstParamTy) {} fn main() { - check(main); //~ error: `fn() {main}` can't be used as a const parameter type - check(|| {}); //~ error: `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}` can't be used as a const parameter type - check(main as fn()); //~ error: `fn()` can't be used as a const parameter type - check(&mut ()); //~ error: `&mut ()` can't be used as a const parameter type + check(main); //~ error: `fn() {main}` can't be used as a const parameter type + check(|| {}); //~ error: `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}` can't be used as a const parameter type + check(main as fn()); //~ error: `fn()` can't be used as a const parameter type + check(&mut ()); //~ error: `&mut ()` can't be used as a const parameter type check(&mut () as *mut ()); //~ error: `*mut ()` can't be used as a const parameter type - check(&() as *const ()); //~ error: `*const ()` can't be used as a const parameter type + check(&() as *const ()); //~ error: `*const ()` can't be used as a const parameter type } diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr index d96491f4f20e..694f5a5c1a9d 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr @@ -2,15 +2,15 @@ error[E0277]: `fn() {main}` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:7:11 | LL | check(main); - | ----- ^^^^ the trait `ConstParamTy` is not implemented for fn item `fn() {main}` + | ----- ^^^^ the trait `UnsizedConstParamTy` is not implemented for fn item `fn() {main}` | | | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | -LL | fn check(_: impl std::marker::ConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` help: use parentheses to call this function | LL | check(main()); @@ -20,15 +20,15 @@ error[E0277]: `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}` can't be used as --> $DIR/const_param_ty_bad.rs:8:11 | LL | check(|| {}); - | ----- ^^^^^ the trait `ConstParamTy` is not implemented for closure `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}` + | ----- ^^^^^ the trait `UnsizedConstParamTy` is not implemented for closure `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}` | | | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | -LL | fn check(_: impl std::marker::ConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` help: use parentheses to call this closure | LL | check(|| {}()); @@ -38,15 +38,15 @@ error[E0277]: `fn()` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:9:11 | LL | check(main as fn()); - | ----- ^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `fn()` + | ----- ^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `fn()` | | | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | -LL | fn check(_: impl std::marker::ConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` help: use parentheses to call this function pointer | LL | check(main as fn()()); @@ -56,16 +56,16 @@ error[E0277]: `&mut ()` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:10:11 | LL | check(&mut ()); - | ----- ^^^^^^^ the trait `ConstParamTy` is not implemented for `&mut ()` + | ----- ^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `&mut ()` | | | required by a bound introduced by this call | - = note: `ConstParamTy` is implemented for `&()`, but not for `&mut ()` + = note: `UnsizedConstParamTy` is implemented for `&()`, but not for `&mut ()` note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | -LL | fn check(_: impl std::marker::ConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` help: consider removing the leading `&`-reference | LL - check(&mut ()); @@ -76,31 +76,31 @@ error[E0277]: `*mut ()` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:11:11 | LL | check(&mut () as *mut ()); - | ----- ^^^^^^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `*mut ()` + | ----- ^^^^^^^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `*mut ()` | | | required by a bound introduced by this call | - = help: the trait `ConstParamTy` is implemented for `()` + = help: the trait `UnsizedConstParamTy` is implemented for `()` note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | -LL | fn check(_: impl std::marker::ConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` error[E0277]: `*const ()` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:12:11 | LL | check(&() as *const ()); - | ----- ^^^^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `*const ()` + | ----- ^^^^^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `*const ()` | | | required by a bound introduced by this call | - = help: the trait `ConstParamTy` is implemented for `()` + = help: the trait `UnsizedConstParamTy` is implemented for `()` note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | -LL | fn check(_: impl std::marker::ConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` error: aborting due to 6 previous errors diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs index b0e3b13cc1ef..2008a96310a8 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs @@ -1,10 +1,10 @@ #![allow(incomplete_features)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #[derive(PartialEq, Eq)] struct NotParam; -fn check() {} +fn check() {} fn main() { check::<[NotParam; 0]>(); diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr index 771d661f615e..9852e181b9ac 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr @@ -2,14 +2,14 @@ error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_bad_empty_array.rs:10:13 | LL | check::<[NotParam; 0]>(); - | ^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam; 0]: ConstParamTy` + | ^^^^^^^^^^^^^ the trait `ConstParamTy_` is not implemented for `NotParam`, which is required by `[NotParam; 0]: ConstParamTy_` | - = note: required for `[NotParam; 0]` to implement `ConstParamTy` + = note: required for `[NotParam; 0]` to implement `ConstParamTy_` note: required by a bound in `check` --> $DIR/const_param_ty_bad_empty_array.rs:7:13 | -LL | fn check() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs index e4dc76703a2d..7ffdafa33e93 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs @@ -1,13 +1,13 @@ #![allow(incomplete_features)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #[derive(PartialEq, Eq)] struct NotParam; -fn check() {} +fn check() {} fn main() { - check::<&NotParam>(); //~ error: `NotParam` can't be used as a const parameter type - check::<[NotParam]>(); //~ error: `NotParam` can't be used as a const parameter type + check::<&NotParam>(); //~ error: `NotParam` can't be used as a const parameter type + check::<[NotParam]>(); //~ error: `NotParam` can't be used as a const parameter type check::<[NotParam; 17]>(); //~ error: `NotParam` can't be used as a const parameter type } diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr index 83c34c41f105..e63ae582fd57 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr @@ -2,40 +2,40 @@ error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:10:13 | LL | check::<&NotParam>(); - | ^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`, which is required by `&NotParam: ConstParamTy` + | ^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam`, which is required by `&NotParam: UnsizedConstParamTy` | - = note: required for `&NotParam` to implement `ConstParamTy` + = note: required for `&NotParam` to implement `UnsizedConstParamTy` note: required by a bound in `check` --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13 | -LL | fn check() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:11:13 | LL | check::<[NotParam]>(); - | ^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam]: ConstParamTy` + | ^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam]: UnsizedConstParamTy` | - = note: required for `[NotParam]` to implement `ConstParamTy` + = note: required for `[NotParam]` to implement `UnsizedConstParamTy` note: required by a bound in `check` --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13 | -LL | fn check() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:12:13 | LL | check::<[NotParam; 17]>(); - | ^^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam; 17]: ConstParamTy` + | ^^^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam; 17]: UnsizedConstParamTy` | - = note: required for `[NotParam; 17]` to implement `ConstParamTy` + = note: required for `[NotParam; 17]` to implement `UnsizedConstParamTy` note: required by a bound in `check` --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13 | -LL | fn check() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs index bce24059de8e..98a8eb6ee950 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs @@ -1,7 +1,9 @@ //@ check-pass + +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] -#![feature(adt_const_params)] -use std::marker::ConstParamTy; + +use std::marker::UnsizedConstParamTy; #[derive(PartialEq, Eq)] struct S { @@ -9,16 +11,15 @@ struct S { gen: T, } -impl ConstParamTy for S {} +impl UnsizedConstParamTy for S {} -#[derive(PartialEq, Eq, ConstParamTy)] +#[derive(PartialEq, Eq, UnsizedConstParamTy)] struct D { field: u8, gen: T, } - -fn check() {} +fn check() {} fn main() { check::(); diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs index 74283a37afca..8b3d0546010d 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs @@ -1,5 +1,5 @@ #![allow(incomplete_features)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #[derive(PartialEq, Eq)] struct NotParam; @@ -7,11 +7,11 @@ struct NotParam; #[derive(PartialEq, Eq)] struct CantParam(NotParam); -impl std::marker::ConstParamTy for CantParam {} -//~^ error: the trait `ConstParamTy` cannot be implemented for this type +impl std::marker::UnsizedConstParamTy for CantParam {} +//~^ error: the trait `ConstParamTy_` cannot be implemented for this type -#[derive(std::marker::ConstParamTy, Eq, PartialEq)] -//~^ error: the trait `ConstParamTy` cannot be implemented for this type +#[derive(std::marker::UnsizedConstParamTy, Eq, PartialEq)] +//~^ error: the trait `ConstParamTy_` cannot be implemented for this type struct CantParamDerive(NotParam); fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr index 52b65d6061ab..808a569fcadf 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr @@ -1,22 +1,22 @@ -error[E0204]: the trait `ConstParamTy` cannot be implemented for this type - --> $DIR/const_param_ty_impl_bad_field.rs:10:36 +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/const_param_ty_impl_bad_field.rs:10:43 | LL | struct CantParam(NotParam); - | -------- this field does not implement `ConstParamTy` + | -------- this field does not implement `ConstParamTy_` LL | -LL | impl std::marker::ConstParamTy for CantParam {} - | ^^^^^^^^^ +LL | impl std::marker::UnsizedConstParamTy for CantParam {} + | ^^^^^^^^^ -error[E0204]: the trait `ConstParamTy` cannot be implemented for this type +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type --> $DIR/const_param_ty_impl_bad_field.rs:13:10 | -LL | #[derive(std::marker::ConstParamTy, Eq, PartialEq)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[derive(std::marker::UnsizedConstParamTy, Eq, PartialEq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | struct CantParamDerive(NotParam); - | -------- this field does not implement `ConstParamTy` + | -------- this field does not implement `ConstParamTy_` | - = note: this error originates in the derive macro `std::marker::ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `std::marker::UnsizedConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs index dfb8a36ec535..761a6387a24e 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs @@ -1,22 +1,22 @@ #![allow(incomplete_features)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #[derive(PartialEq, Eq)] struct ImplementsConstParamTy; -impl std::marker::ConstParamTy for ImplementsConstParamTy {} +impl std::marker::UnsizedConstParamTy for ImplementsConstParamTy {} struct CantParam(ImplementsConstParamTy); -impl std::marker::ConstParamTy for CantParam {} +impl std::marker::UnsizedConstParamTy for CantParam {} //~^ error: the type `CantParam` does not `#[derive(PartialEq)]` //~| the trait bound `CantParam: Eq` is not satisfied -#[derive(std::marker::ConstParamTy)] +#[derive(std::marker::UnsizedConstParamTy)] //~^ error: the type `CantParamDerive` does not `#[derive(PartialEq)]` //~| the trait bound `CantParamDerive: Eq` is not satisfied struct CantParamDerive(ImplementsConstParamTy); -fn check() {} +fn check() {} fn main() { check::(); diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr index e213808cf7bd..80d9942c5914 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr @@ -1,10 +1,10 @@ error[E0277]: the trait bound `CantParam: Eq` is not satisfied - --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:36 + --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:43 | -LL | impl std::marker::ConstParamTy for CantParam {} - | ^^^^^^^^^ the trait `Eq` is not implemented for `CantParam` +LL | impl std::marker::UnsizedConstParamTy for CantParam {} + | ^^^^^^^^^ the trait `Eq` is not implemented for `CantParam` | -note: required by a bound in `ConstParamTy` +note: required by a bound in `UnsizedConstParamTy` --> $SRC_DIR/core/src/marker.rs:LL:COL help: consider annotating `CantParam` with `#[derive(Eq)]` | @@ -13,23 +13,23 @@ LL | struct CantParam(ImplementsConstParamTy); | error[E0277]: the type `CantParam` does not `#[derive(PartialEq)]` - --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:36 + --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:43 | -LL | impl std::marker::ConstParamTy for CantParam {} - | ^^^^^^^^^ the trait `StructuralPartialEq` is not implemented for `CantParam` +LL | impl std::marker::UnsizedConstParamTy for CantParam {} + | ^^^^^^^^^ the trait `StructuralPartialEq` is not implemented for `CantParam` | -note: required by a bound in `ConstParamTy` +note: required by a bound in `UnsizedConstParamTy` --> $SRC_DIR/core/src/marker.rs:LL:COL error[E0277]: the trait bound `CantParamDerive: Eq` is not satisfied --> $DIR/const_param_ty_impl_no_structural_eq.rs:14:10 | -LL | #[derive(std::marker::ConstParamTy)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `CantParamDerive` +LL | #[derive(std::marker::UnsizedConstParamTy)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `CantParamDerive` | -note: required by a bound in `ConstParamTy` +note: required by a bound in `UnsizedConstParamTy` --> $SRC_DIR/core/src/marker.rs:LL:COL - = note: this error originates in the derive macro `std::marker::ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `std::marker::UnsizedConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `CantParamDerive` with `#[derive(Eq)]` | LL + #[derive(Eq)] @@ -39,12 +39,12 @@ LL | struct CantParamDerive(ImplementsConstParamTy); error[E0277]: the type `CantParamDerive` does not `#[derive(PartialEq)]` --> $DIR/const_param_ty_impl_no_structural_eq.rs:14:10 | -LL | #[derive(std::marker::ConstParamTy)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `StructuralPartialEq` is not implemented for `CantParamDerive` +LL | #[derive(std::marker::UnsizedConstParamTy)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `StructuralPartialEq` is not implemented for `CantParamDerive` | -note: required by a bound in `ConstParamTy` +note: required by a bound in `UnsizedConstParamTy` --> $SRC_DIR/core/src/marker.rs:LL:COL - = note: this error originates in the derive macro `std::marker::ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `std::marker::UnsizedConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs index f2986f9cc60d..236b3bc162aa 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs @@ -1,5 +1,5 @@ #![allow(incomplete_features)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] union Union { a: u8, @@ -12,10 +12,10 @@ impl PartialEq for Union { } impl Eq for Union {} -impl std::marker::ConstParamTy for Union {} -//~^ ERROR the type `Union` does not `#[derive(PartialEq)]` +impl std::marker::UnsizedConstParamTy for Union {} +//~^ ERROR the trait `ConstParamTy` may not be implemented for this type -#[derive(std::marker::ConstParamTy)] +#[derive(std::marker::UnsizedConstParamTy)] //~^ ERROR this trait cannot be derived for unions union UnionDerive { a: u8, @@ -28,5 +28,4 @@ impl PartialEq for UnionDerive { } impl Eq for UnionDerive {} - fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr index 4c937db6c3ab..837c289c9248 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr @@ -1,18 +1,14 @@ error: this trait cannot be derived for unions --> $DIR/const_param_ty_impl_union.rs:18:10 | -LL | #[derive(std::marker::ConstParamTy)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[derive(std::marker::UnsizedConstParamTy)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the type `Union` does not `#[derive(PartialEq)]` - --> $DIR/const_param_ty_impl_union.rs:15:36 +error: the trait `ConstParamTy` may not be implemented for this type + --> $DIR/const_param_ty_impl_union.rs:15:43 | -LL | impl std::marker::ConstParamTy for Union {} - | ^^^^^ the trait `StructuralPartialEq` is not implemented for `Union` - | -note: required by a bound in `ConstParamTy` - --> $SRC_DIR/core/src/marker.rs:LL:COL +LL | impl std::marker::UnsizedConstParamTy for Union {} + | ^^^^^ type is not a structure or enumeration error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.rs new file mode 100644 index 000000000000..6a553c2e0854 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.rs @@ -0,0 +1,12 @@ +#![feature(adt_const_params, unsized_const_params)] +#![allow(incomplete_features)] + +use std::marker::{ConstParamTy_, UnsizedConstParamTy}; + +fn foo(a: &dyn ConstParamTy_) {} +//~^ ERROR: the trait `ConstParamTy_` + +fn bar(a: &dyn UnsizedConstParamTy) {} +//~^ ERROR: the trait `UnsizedConstParamTy` + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.stderr new file mode 100644 index 000000000000..ba38f63d5df7 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.stderr @@ -0,0 +1,33 @@ +error[E0038]: the trait `ConstParamTy_` cannot be made into an object + --> $DIR/const_param_ty_object_safety.rs:6:12 + | +LL | fn foo(a: &dyn ConstParamTy_) {} + | ^^^^^^^^^^^^^^^^^ `ConstParamTy_` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: the trait cannot be made into an object because it uses `Self` as a type parameter +help: consider using an opaque type instead + | +LL | fn foo(a: &impl ConstParamTy_) {} + | ~~~~ + +error[E0038]: the trait `UnsizedConstParamTy` cannot be made into an object + --> $DIR/const_param_ty_object_safety.rs:9:12 + | +LL | fn bar(a: &dyn UnsizedConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^ `UnsizedConstParamTy` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: the trait cannot be made into an object because it uses `Self` as a type parameter +help: consider using an opaque type instead + | +LL | fn bar(a: &impl UnsizedConstParamTy) {} + | ~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.rs b/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.rs index 0d1f023d565f..7a4970c2e3c9 100644 --- a/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.rs +++ b/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.rs @@ -1,18 +1,30 @@ // issue: rust-lang/rust/#83993 #![feature(adt_const_params)] -//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + fn bug<'a>() where for<'b> [(); { let x: &'b (); //~^ ERROR generic parameters may not be used in const operations 0 - }]: -{} + }]:, +{ +} -fn bad() where for<'b> [();{let _:&'b (); 0}]: Sized { } -//~^ ERROR generic parameters may not be used in const operations -fn good() where for<'b> [();{0}]: Sized { } +fn bad() +where + for<'b> [(); { + let _: &'b (); + //~^ ERROR generic parameters may not be used in const operations + 0 + }]: Sized, +{ +} +fn good() +where + for<'b> [(); { 0 }]: Sized, +{ +} pub fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.stderr b/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.stderr index a49dfc319167..b7e459511f15 100644 --- a/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.stderr +++ b/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.stderr @@ -8,22 +8,13 @@ LL | let x: &'b (); = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/index-oob-ice-83993.rs:14:36 + --> $DIR/index-oob-ice-83993.rs:18:17 | -LL | fn bad() where for<'b> [();{let _:&'b (); 0}]: Sized { } - | ^^ cannot perform const operation using `'b` +LL | let _: &'b (); + | ^^ cannot perform const operation using `'b` | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions -warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/index-oob-ice-83993.rs:3:12 - | -LL | #![feature(adt_const_params)] - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #95174 for more information - = note: `#[warn(incomplete_features)]` on by default - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs index 9f05c53eef0f..3a283442a0b0 100644 --- a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs +++ b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs @@ -4,15 +4,18 @@ use std::marker::ConstParamTy; #[derive(ConstParamTy)] -//~^ the trait `ConstParamTy` cannot be implemented for this ty +//~^ the trait `ConstParamTy_` cannot be implemented for this ty +//~| the trait `ConstParamTy_` cannot be implemented for this ty struct Foo([*const u8; 1]); #[derive(ConstParamTy)] -//~^ the trait `ConstParamTy` cannot be implemented for this ty +//~^ the trait `ConstParamTy_` cannot be implemented for this ty +//~| the trait `ConstParamTy_` cannot be implemented for this ty struct Foo2([*mut u8; 1]); #[derive(ConstParamTy)] -//~^ the trait `ConstParamTy` cannot be implemented for this ty +//~^ the trait `ConstParamTy_` cannot be implemented for this ty +//~| the trait `ConstParamTy_` cannot be implemented for this ty struct Foo3([fn(); 1]); fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr index 9e772e8d55df..c2520f1d1038 100644 --- a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr +++ b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr @@ -1,51 +1,99 @@ -error[E0204]: the trait `ConstParamTy` cannot be implemented for this type +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type --> $DIR/nested_bad_const_param_ty.rs:6:10 | LL | #[derive(ConstParamTy)] | ^^^^^^^^^^^^ -LL | +... LL | struct Foo([*const u8; 1]); - | -------------- this field does not implement `ConstParamTy` + | -------------- this field does not implement `ConstParamTy_` | -note: the `ConstParamTy` impl for `[*const u8; 1]` requires that `*const u8: ConstParamTy` - --> $DIR/nested_bad_const_param_ty.rs:8:12 +note: the `ConstParamTy_` impl for `[*const u8; 1]` requires that `*const u8: ConstParamTy_` + --> $DIR/nested_bad_const_param_ty.rs:9:12 | LL | struct Foo([*const u8; 1]); | ^^^^^^^^^^^^^^ = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0204]: the trait `ConstParamTy` cannot be implemented for this type - --> $DIR/nested_bad_const_param_ty.rs:10:10 +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/nested_bad_const_param_ty.rs:11:10 | LL | #[derive(ConstParamTy)] | ^^^^^^^^^^^^ -LL | +... LL | struct Foo2([*mut u8; 1]); - | ------------ this field does not implement `ConstParamTy` + | ------------ this field does not implement `ConstParamTy_` | -note: the `ConstParamTy` impl for `[*mut u8; 1]` requires that `*mut u8: ConstParamTy` - --> $DIR/nested_bad_const_param_ty.rs:12:13 +note: the `ConstParamTy_` impl for `[*mut u8; 1]` requires that `*mut u8: ConstParamTy_` + --> $DIR/nested_bad_const_param_ty.rs:14:13 | LL | struct Foo2([*mut u8; 1]); | ^^^^^^^^^^^^ = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0204]: the trait `ConstParamTy` cannot be implemented for this type - --> $DIR/nested_bad_const_param_ty.rs:14:10 +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/nested_bad_const_param_ty.rs:16:10 | LL | #[derive(ConstParamTy)] | ^^^^^^^^^^^^ -LL | +... LL | struct Foo3([fn(); 1]); - | --------- this field does not implement `ConstParamTy` + | --------- this field does not implement `ConstParamTy_` | -note: the `ConstParamTy` impl for `[fn(); 1]` requires that `fn(): ConstParamTy` - --> $DIR/nested_bad_const_param_ty.rs:16:13 +note: the `ConstParamTy_` impl for `[fn(); 1]` requires that `fn(): ConstParamTy_` + --> $DIR/nested_bad_const_param_ty.rs:19:13 | LL | struct Foo3([fn(); 1]); | ^^^^^^^^^ = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 3 previous errors +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/nested_bad_const_param_ty.rs:6:10 + | +LL | #[derive(ConstParamTy)] + | ^^^^^^^^^^^^ +... +LL | struct Foo([*const u8; 1]); + | -------------- this field does not implement `ConstParamTy_` + | +note: the `ConstParamTy_` impl for `[*const u8; 1]` requires that `*const u8: UnsizedConstParamTy` + --> $DIR/nested_bad_const_param_ty.rs:9:12 + | +LL | struct Foo([*const u8; 1]); + | ^^^^^^^^^^^^^^ + = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/nested_bad_const_param_ty.rs:11:10 + | +LL | #[derive(ConstParamTy)] + | ^^^^^^^^^^^^ +... +LL | struct Foo2([*mut u8; 1]); + | ------------ this field does not implement `ConstParamTy_` + | +note: the `ConstParamTy_` impl for `[*mut u8; 1]` requires that `*mut u8: UnsizedConstParamTy` + --> $DIR/nested_bad_const_param_ty.rs:14:13 + | +LL | struct Foo2([*mut u8; 1]); + | ^^^^^^^^^^^^ + = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/nested_bad_const_param_ty.rs:16:10 + | +LL | #[derive(ConstParamTy)] + | ^^^^^^^^^^^^ +... +LL | struct Foo3([fn(); 1]); + | --------- this field does not implement `ConstParamTy_` + | +note: the `ConstParamTy_` impl for `[fn(); 1]` requires that `fn(): UnsizedConstParamTy` + --> $DIR/nested_bad_const_param_ty.rs:19:13 + | +LL | struct Foo3([fn(); 1]); + | ^^^^^^^^^ + = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0204`. diff --git a/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs b/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs index c55f3dcec68c..f28bebf85db5 100644 --- a/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs +++ b/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs @@ -3,7 +3,7 @@ // issues rust-lang/rust#111911 // test for ICE opaque type with non-universal region substs -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] pub async fn foo() {} diff --git a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.rs b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.rs new file mode 100644 index 000000000000..a1ee1c4cdd58 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.rs @@ -0,0 +1,11 @@ +#![feature(adt_const_params, unsized_const_params)] +#![allow(incomplete_features)] + +use std::marker::UnsizedConstParamTy; + +struct Foo; + +impl UnsizedConstParamTy for &'static Foo {} +//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.stderr b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.stderr new file mode 100644 index 000000000000..5ca8e6c75167 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.stderr @@ -0,0 +1,9 @@ +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/reference_pointee_is_const_param-1.rs:8:30 + | +LL | impl UnsizedConstParamTy for &'static Foo {} + | ^^^^^^^^^^^^ this field does not implement `ConstParamTy_` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0204`. diff --git a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.rs b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.rs new file mode 100644 index 000000000000..ac1b522f469e --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.rs @@ -0,0 +1,27 @@ +#![feature(adt_const_params, unsized_const_params)] +#![allow(incomplete_features)] + +// Regression test for #119299 + +use std::marker::UnsizedConstParamTy; + +#[derive(Eq, PartialEq)] +struct ConstStrU(*const u8, usize); + +impl UnsizedConstParamTy for &'static ConstStrU {} +//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type + +impl ConstStrU { + const fn from_bytes(bytes: &'static [u8]) -> Self { + Self(bytes.as_ptr(), bytes.len()) + } +} + +const fn chars_s() -> [char; 3] { + ['a', 'b', 'c'] +} + +fn main() { + const A: &'static ConstStrU = &ConstStrU::from_bytes(b"abc"); + chars_s::(); +} diff --git a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.stderr b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.stderr new file mode 100644 index 000000000000..5e5f6cc642d3 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.stderr @@ -0,0 +1,9 @@ +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/reference_pointee_is_const_param-2.rs:11:30 + | +LL | impl UnsizedConstParamTy for &'static ConstStrU {} + | ^^^^^^^^^^^^^^^^^^ this field does not implement `ConstParamTy_` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0204`. diff --git a/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.rs b/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.rs index 0d2e65c45eaf..33988bc06785 100644 --- a/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.rs +++ b/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.rs @@ -8,9 +8,8 @@ fn uwu_0() {} //~| HELP: add `#![feature(adt_const_params)]` //~| HELP: add `#![feature(adt_const_params)]` //~| HELP: add `#![feature(adt_const_params)]` -//~| HELP: add `#![feature(adt_const_params)]` -//~| HELP: add `#![feature(adt_const_params)]` -//~| HELP: add `#![feature(adt_const_params)]` +//~| HELP: add `#![feature(unsized_const_params)]` +//~| HELP: add `#![feature(unsized_const_params)]` // Needs the feature but can be used, so suggest adding the feature. fn owo_0() {} diff --git a/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr b/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr index cd4349623d72..aafc0640dd2d 100644 --- a/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr +++ b/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr @@ -7,7 +7,7 @@ LL | fn uwu_0() {} = note: the only supported types are integers, `bool` and `char` error: `&'static u32` is forbidden as the type of a const generic parameter - --> $DIR/suggest_feature_only_when_possible.rs:16:19 + --> $DIR/suggest_feature_only_when_possible.rs:15:19 | LL | fn owo_0() {} | ^^^^^^^^^^^^ @@ -17,9 +17,13 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `Meow` is forbidden as the type of a const generic parameter - --> $DIR/suggest_feature_only_when_possible.rs:24:20 + --> $DIR/suggest_feature_only_when_possible.rs:23:20 | LL | fn meow_0() {} | ^^^^ @@ -31,7 +35,7 @@ LL + #![feature(adt_const_params)] | error: `&'static Meow` is forbidden as the type of a const generic parameter - --> $DIR/suggest_feature_only_when_possible.rs:26:20 + --> $DIR/suggest_feature_only_when_possible.rs:25:20 | LL | fn meow_1() {} | ^^^^^^^^^^^^^ @@ -41,45 +45,37 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `[Meow; 100]` is forbidden as the type of a const generic parameter - --> $DIR/suggest_feature_only_when_possible.rs:28:20 + --> $DIR/suggest_feature_only_when_possible.rs:27:20 | LL | fn meow_2() {} | ^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` -help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types - | -LL + #![feature(adt_const_params)] - | error: `(Meow, u8)` is forbidden as the type of a const generic parameter - --> $DIR/suggest_feature_only_when_possible.rs:30:20 + --> $DIR/suggest_feature_only_when_possible.rs:29:20 | LL | fn meow_3() {} | ^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` -help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types - | -LL + #![feature(adt_const_params)] - | error: `(Meow, String)` is forbidden as the type of a const generic parameter - --> $DIR/suggest_feature_only_when_possible.rs:35:20 + --> $DIR/suggest_feature_only_when_possible.rs:34:20 | LL | fn meow_4() {} | ^^^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` -help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types - | -LL + #![feature(adt_const_params)] - | error: `String` is forbidden as the type of a const generic parameter - --> $DIR/suggest_feature_only_when_possible.rs:39:19 + --> $DIR/suggest_feature_only_when_possible.rs:38:19 | LL | fn nya_0() {} | ^^^^^^ @@ -87,7 +83,7 @@ LL | fn nya_0() {} = note: the only supported types are integers, `bool` and `char` error: `Vec` is forbidden as the type of a const generic parameter - --> $DIR/suggest_feature_only_when_possible.rs:41:19 + --> $DIR/suggest_feature_only_when_possible.rs:40:19 | LL | fn nya_1>() {} | ^^^^^^^^ diff --git a/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.rs b/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.rs new file mode 100644 index 000000000000..b0934508399d --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.rs @@ -0,0 +1,13 @@ +#![feature(adt_const_params, unsized_const_params)] +#![allow(incomplete_features)] + +use std::marker::UnsizedConstParamTy; + +trait Trait {} + +impl UnsizedConstParamTy for dyn Trait {} +//~^ ERROR: the trait `ConstParamTy` may not be implemented for this type + +fn foo() {} + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.stderr b/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.stderr new file mode 100644 index 000000000000..9933ba6e335b --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.stderr @@ -0,0 +1,8 @@ +error: the trait `ConstParamTy` may not be implemented for this type + --> $DIR/trait_objects_as_a_const_generic.rs:8:30 + | +LL | impl UnsizedConstParamTy for dyn Trait {} + | ^^^^^^^^^ type is not a structure or enumeration + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/adt_const_params/unsized_field-1.rs b/tests/ui/const-generics/adt_const_params/unsized_field-1.rs new file mode 100644 index 000000000000..f6e5bd6e355d --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/unsized_field-1.rs @@ -0,0 +1,20 @@ +//@ aux-build:unsized_const_param.rs +#![feature(adt_const_params)] + +extern crate unsized_const_param; + +use std::marker::ConstParamTy; + +#[derive(ConstParamTy, Eq, PartialEq)] +//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type +struct A([u8]); + +#[derive(ConstParamTy, Eq, PartialEq)] +//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type +struct B(&'static [u8]); + +#[derive(ConstParamTy, Eq, PartialEq)] +//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type +struct C(unsized_const_param::Foo); + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr b/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr new file mode 100644 index 000000000000..7a4f9b99c637 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr @@ -0,0 +1,36 @@ +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/unsized_field-1.rs:8:10 + | +LL | #[derive(ConstParamTy, Eq, PartialEq)] + | ^^^^^^^^^^^^ +LL | +LL | struct A([u8]); + | ---- this field does not implement `ConstParamTy_` + | + = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/unsized_field-1.rs:12:10 + | +LL | #[derive(ConstParamTy, Eq, PartialEq)] + | ^^^^^^^^^^^^ +LL | +LL | struct B(&'static [u8]); + | ------------- this field does not implement `ConstParamTy_` + | + = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/unsized_field-1.rs:16:10 + | +LL | #[derive(ConstParamTy, Eq, PartialEq)] + | ^^^^^^^^^^^^ +LL | +LL | struct C(unsized_const_param::Foo); + | ------------------------ this field does not implement `ConstParamTy_` + | + = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0204`. diff --git a/tests/ui/const-generics/adt_const_params/unsized_field-2.rs b/tests/ui/const-generics/adt_const_params/unsized_field-2.rs new file mode 100644 index 000000000000..e4a3a481b4e3 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/unsized_field-2.rs @@ -0,0 +1,14 @@ +//@ aux-build:unsized_const_param.rs +#![feature(adt_const_params, unsized_const_params)] +//~^ WARN: the feature `unsized_const_params` is incomplete + +extern crate unsized_const_param; + +#[derive(std::marker::ConstParamTy, Eq, PartialEq)] +//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type +struct A(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>); + +#[derive(std::marker::UnsizedConstParamTy, Eq, PartialEq)] +struct B(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>); + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/unsized_field-2.stderr b/tests/ui/const-generics/adt_const_params/unsized_field-2.stderr new file mode 100644 index 000000000000..15acece538fd --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/unsized_field-2.stderr @@ -0,0 +1,28 @@ +warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/unsized_field-2.rs:2:30 + | +LL | #![feature(adt_const_params, unsized_const_params)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #95174 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/unsized_field-2.rs:7:10 + | +LL | #[derive(std::marker::ConstParamTy, Eq, PartialEq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | struct A(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>); + | ---------------------------------------------------------- this field does not implement `ConstParamTy_` + | +note: the `ConstParamTy_` impl for `GenericNotUnsizedParam<&'static [u8]>` requires that `&'static [u8]: ConstParamTy_` + --> $DIR/unsized_field-2.rs:9:10 + | +LL | struct A(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the derive macro `std::marker::ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0204`. diff --git a/tests/ui/const-generics/const-param-elided-lifetime.min.stderr b/tests/ui/const-generics/const-param-elided-lifetime.min.stderr index 1c81b14f8f5c..62267224738d 100644 --- a/tests/ui/const-generics/const-param-elided-lifetime.min.stderr +++ b/tests/ui/const-generics/const-param-elided-lifetime.min.stderr @@ -39,6 +39,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `&u8` is forbidden as the type of a const generic parameter --> $DIR/const-param-elided-lifetime.rs:14:15 @@ -51,6 +55,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `&u8` is forbidden as the type of a const generic parameter --> $DIR/const-param-elided-lifetime.rs:22:15 @@ -63,6 +71,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `&u8` is forbidden as the type of a const generic parameter --> $DIR/const-param-elided-lifetime.rs:26:17 @@ -75,6 +87,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `&u8` is forbidden as the type of a const generic parameter --> $DIR/const-param-elided-lifetime.rs:17:21 @@ -87,6 +103,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 10 previous errors diff --git a/tests/ui/const-generics/const-param-elided-lifetime.rs b/tests/ui/const-generics/const-param-elided-lifetime.rs index ef1eecb59be9..e75073de98d3 100644 --- a/tests/ui/const-generics/const-param-elided-lifetime.rs +++ b/tests/ui/const-generics/const-param-elided-lifetime.rs @@ -3,7 +3,7 @@ // elided lifetimes within the type of a const generic parameters to be 'static, like elided // lifetimes within const/static items. //@ revisions: full min -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] struct A; @@ -12,8 +12,8 @@ struct A; trait B {} impl A { -//~^ ERROR `&` without an explicit lifetime name cannot be used here -//[min]~^^ ERROR `&u8` is forbidden + //~^ ERROR `&` without an explicit lifetime name cannot be used here + //[min]~^^ ERROR `&u8` is forbidden fn foo(&self) {} //~^ ERROR `&` without an explicit lifetime name cannot be used here //[min]~^^ ERROR `&u8` is forbidden diff --git a/tests/ui/const-generics/const-param-with-additional-obligations.rs b/tests/ui/const-generics/const-param-with-additional-obligations.rs index f53cf85cdd39..98097e86c7df 100644 --- a/tests/ui/const-generics/const-param-with-additional-obligations.rs +++ b/tests/ui/const-generics/const-param-with-additional-obligations.rs @@ -1,14 +1,14 @@ -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] -use std::marker::ConstParamTy; +use std::marker::UnsizedConstParamTy; #[derive(Eq, PartialEq)] struct Foo(T); trait Other {} -impl ConstParamTy for Foo where T: Other + ConstParamTy {} +impl UnsizedConstParamTy for Foo where T: Other + UnsizedConstParamTy {} fn foo>() {} //~^ ERROR `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter diff --git a/tests/ui/const-generics/float-generic.adt_const_params.stderr b/tests/ui/const-generics/float-generic.adt_const_params.stderr index cae4806368a9..1a7c19ba4be6 100644 --- a/tests/ui/const-generics/float-generic.adt_const_params.stderr +++ b/tests/ui/const-generics/float-generic.adt_const_params.stderr @@ -1,5 +1,5 @@ error[E0741]: `f32` is forbidden as the type of a const generic parameter - --> $DIR/float-generic.rs:5:17 + --> $DIR/float-generic.rs:7:17 | LL | fn foo() {} | ^^^ diff --git a/tests/ui/const-generics/float-generic.full.stderr b/tests/ui/const-generics/float-generic.full.stderr new file mode 100644 index 000000000000..1a7c19ba4be6 --- /dev/null +++ b/tests/ui/const-generics/float-generic.full.stderr @@ -0,0 +1,9 @@ +error[E0741]: `f32` is forbidden as the type of a const generic parameter + --> $DIR/float-generic.rs:7:17 + | +LL | fn foo() {} + | ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0741`. diff --git a/tests/ui/const-generics/float-generic.rs b/tests/ui/const-generics/float-generic.rs index aaf63a93d708..f92e1667701b 100644 --- a/tests/ui/const-generics/float-generic.rs +++ b/tests/ui/const-generics/float-generic.rs @@ -1,4 +1,6 @@ -//@ revisions: simple adt_const_params +//@ revisions: simple adt_const_params full +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] +#![cfg_attr(full, allow(incomplete_features))] #![cfg_attr(adt_const_params, feature(adt_const_params))] #![cfg_attr(adt_const_params, allow(incomplete_features))] diff --git a/tests/ui/const-generics/float-generic.simple.stderr b/tests/ui/const-generics/float-generic.simple.stderr index eccf9059ee33..2999bce32d6a 100644 --- a/tests/ui/const-generics/float-generic.simple.stderr +++ b/tests/ui/const-generics/float-generic.simple.stderr @@ -1,5 +1,5 @@ error: `f32` is forbidden as the type of a const generic parameter - --> $DIR/float-generic.rs:5:17 + --> $DIR/float-generic.rs:7:17 | LL | fn foo() {} | ^^^ diff --git a/tests/ui/const-generics/fn-const-param-call.adt_const_params.stderr b/tests/ui/const-generics/fn-const-param-call.adt_const_params.stderr new file mode 100644 index 000000000000..fd9346a533ec --- /dev/null +++ b/tests/ui/const-generics/fn-const-param-call.adt_const_params.stderr @@ -0,0 +1,15 @@ +error[E0741]: using function pointers as const generic parameters is forbidden + --> $DIR/fn-const-param-call.rs:13:25 + | +LL | struct Wrapper u32>; + | ^^^^^^^^^^^ + +error[E0741]: using function pointers as const generic parameters is forbidden + --> $DIR/fn-const-param-call.rs:15:15 + | +LL | impl u32> Wrapper { + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0741`. diff --git a/tests/ui/const-generics/fn-const-param-call.full.stderr b/tests/ui/const-generics/fn-const-param-call.full.stderr index b55c2449858c..fd9346a533ec 100644 --- a/tests/ui/const-generics/fn-const-param-call.full.stderr +++ b/tests/ui/const-generics/fn-const-param-call.full.stderr @@ -1,11 +1,11 @@ error[E0741]: using function pointers as const generic parameters is forbidden - --> $DIR/fn-const-param-call.rs:11:25 + --> $DIR/fn-const-param-call.rs:13:25 | LL | struct Wrapper u32>; | ^^^^^^^^^^^ error[E0741]: using function pointers as const generic parameters is forbidden - --> $DIR/fn-const-param-call.rs:13:15 + --> $DIR/fn-const-param-call.rs:15:15 | LL | impl u32> Wrapper { | ^^^^^^^^^^^ diff --git a/tests/ui/const-generics/fn-const-param-call.min.stderr b/tests/ui/const-generics/fn-const-param-call.min.stderr index 2d316fba1e90..d37766b28c9c 100644 --- a/tests/ui/const-generics/fn-const-param-call.min.stderr +++ b/tests/ui/const-generics/fn-const-param-call.min.stderr @@ -1,5 +1,5 @@ error: using function pointers as const generic parameters is forbidden - --> $DIR/fn-const-param-call.rs:11:25 + --> $DIR/fn-const-param-call.rs:13:25 | LL | struct Wrapper u32>; | ^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | struct Wrapper u32>; = note: the only supported types are integers, `bool` and `char` error: using function pointers as const generic parameters is forbidden - --> $DIR/fn-const-param-call.rs:13:15 + --> $DIR/fn-const-param-call.rs:15:15 | LL | impl u32> Wrapper { | ^^^^^^^^^^^ diff --git a/tests/ui/const-generics/fn-const-param-call.rs b/tests/ui/const-generics/fn-const-param-call.rs index ce780143178a..d536c2402392 100644 --- a/tests/ui/const-generics/fn-const-param-call.rs +++ b/tests/ui/const-generics/fn-const-param-call.rs @@ -1,8 +1,10 @@ // Check that functions cannot be used as const parameters. -//@ revisions: full min +//@ revisions: min adt_const_params full -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(adt_const_params, feature(adt_const_params))] +#![cfg_attr(adt_const_params, allow(incomplete_features))] fn function() -> u32 { 17 @@ -11,7 +13,7 @@ fn function() -> u32 { struct Wrapper u32>; //~ ERROR: using function pointers as const generic parameters impl u32> Wrapper { -//~^ ERROR: using function pointers as const generic parameters + //~^ ERROR: using function pointers as const generic parameters fn call() -> u32 { F() } diff --git a/tests/ui/const-generics/fn-const-param-infer.adt_const_params.stderr b/tests/ui/const-generics/fn-const-param-infer.adt_const_params.stderr new file mode 100644 index 000000000000..54f3bff172af --- /dev/null +++ b/tests/ui/const-generics/fn-const-param-infer.adt_const_params.stderr @@ -0,0 +1,30 @@ +error[E0741]: using function pointers as const generic parameters is forbidden + --> $DIR/fn-const-param-infer.rs:8:25 + | +LL | struct Checked bool>; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/fn-const-param-infer.rs:33:25 + | +LL | let _ = Checked::<{ generic_arg:: }>; + | ^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item + | + = note: expected fn pointer `fn(usize) -> _` + found fn item `fn(u32) -> _ {generic_arg::}` + +error[E0282]: type annotations needed + --> $DIR/fn-const-param-infer.rs:35:23 + | +LL | let _ = Checked::; + | ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `generic` + | +help: consider specifying the generic argument + | +LL | let _ = Checked::>; + | +++++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0282, E0308, E0741. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/const-generics/fn-const-param-infer.full.stderr b/tests/ui/const-generics/fn-const-param-infer.full.stderr index 753558636e1e..54f3bff172af 100644 --- a/tests/ui/const-generics/fn-const-param-infer.full.stderr +++ b/tests/ui/const-generics/fn-const-param-infer.full.stderr @@ -1,20 +1,20 @@ error[E0741]: using function pointers as const generic parameters is forbidden - --> $DIR/fn-const-param-infer.rs:6:25 + --> $DIR/fn-const-param-infer.rs:8:25 | LL | struct Checked bool>; | ^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/fn-const-param-infer.rs:23:24 + --> $DIR/fn-const-param-infer.rs:33:25 | -LL | let _ = Checked::<{generic_arg::}>; - | ^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item +LL | let _ = Checked::<{ generic_arg:: }>; + | ^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item | = note: expected fn pointer `fn(usize) -> _` found fn item `fn(u32) -> _ {generic_arg::}` error[E0282]: type annotations needed - --> $DIR/fn-const-param-infer.rs:25:23 + --> $DIR/fn-const-param-infer.rs:35:23 | LL | let _ = Checked::; | ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `generic` diff --git a/tests/ui/const-generics/fn-const-param-infer.min.stderr b/tests/ui/const-generics/fn-const-param-infer.min.stderr index 01e224f8d9ca..4da503d344a1 100644 --- a/tests/ui/const-generics/fn-const-param-infer.min.stderr +++ b/tests/ui/const-generics/fn-const-param-infer.min.stderr @@ -1,5 +1,5 @@ error: using function pointers as const generic parameters is forbidden - --> $DIR/fn-const-param-infer.rs:6:25 + --> $DIR/fn-const-param-infer.rs:8:25 | LL | struct Checked bool>; | ^^^^^^^^^^^^^^^^^ @@ -7,16 +7,16 @@ LL | struct Checked bool>; = note: the only supported types are integers, `bool` and `char` error[E0308]: mismatched types - --> $DIR/fn-const-param-infer.rs:23:24 + --> $DIR/fn-const-param-infer.rs:33:25 | -LL | let _ = Checked::<{generic_arg::}>; - | ^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item +LL | let _ = Checked::<{ generic_arg:: }>; + | ^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item | = note: expected fn pointer `fn(usize) -> _` found fn item `fn(u32) -> _ {generic_arg::}` error[E0282]: type annotations needed - --> $DIR/fn-const-param-infer.rs:25:23 + --> $DIR/fn-const-param-infer.rs:35:23 | LL | let _ = Checked::; | ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `generic` diff --git a/tests/ui/const-generics/fn-const-param-infer.rs b/tests/ui/const-generics/fn-const-param-infer.rs index ed0bb9f72170..5f1958df26e0 100644 --- a/tests/ui/const-generics/fn-const-param-infer.rs +++ b/tests/ui/const-generics/fn-const-param-infer.rs @@ -1,17 +1,27 @@ -//@ revisions: full min +//@ revisions: min adt_const_params full -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(adt_const_params, feature(adt_const_params))] +#![cfg_attr(adt_const_params, allow(incomplete_features))] struct Checked bool>; //~^ ERROR: using function pointers as const generic parameters -fn not_one(val: usize) -> bool { val != 1 } -fn not_two(val: usize) -> bool { val != 2 } +fn not_one(val: usize) -> bool { + val != 1 +} +fn not_two(val: usize) -> bool { + val != 2 +} -fn generic_arg(val: T) -> bool { true } +fn generic_arg(val: T) -> bool { + true +} -fn generic(val: usize) -> bool { val != 1 } +fn generic(val: usize) -> bool { + val != 1 +} fn main() { let _: Option> = None; @@ -19,11 +29,11 @@ fn main() { let _: Checked = Checked::; let _ = Checked::; - let _ = Checked::<{generic_arg::}>; - let _ = Checked::<{generic_arg::}>; //~ ERROR: mismatched types + let _ = Checked::<{ generic_arg:: }>; + let _ = Checked::<{ generic_arg:: }>; //~ ERROR: mismatched types let _ = Checked::; //~ ERROR: type annotations needed - let _ = Checked::<{generic::}>; - let _: Checked<{generic::}> = Checked::<{generic::}>; - let _: Checked<{generic::}> = Checked::<{generic::}>; + let _ = Checked::<{ generic:: }>; + let _: Checked<{ generic:: }> = Checked::<{ generic:: }>; + let _: Checked<{ generic:: }> = Checked::<{ generic:: }>; } diff --git a/tests/ui/const-generics/generic_const_exprs/issue-100360.rs b/tests/ui/const-generics/generic_const_exprs/issue-100360.rs index b7e677a4a1e5..37f015d5e0f2 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-100360.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-100360.rs @@ -1,7 +1,7 @@ //@ check-pass // (this requires debug assertions) -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] fn foo(arg: &'static bool) -> bool { diff --git a/tests/ui/const-generics/generic_const_exprs/issue-89851.rs b/tests/ui/const-generics/generic_const_exprs/issue-89851.rs index 78189c5225cd..f93ba30856dc 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-89851.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-89851.rs @@ -1,7 +1,7 @@ //@ check-pass // (this requires debug assertions) -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] pub const BAR: () = ice::<"">(); diff --git a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs index 5a6565fe2f1e..443d0a2fe87a 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs @@ -1,7 +1,7 @@ //@ check-pass -#![feature(adt_const_params, generic_const_exprs)] -//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] +#![feature(adt_const_params, unsized_const_params, generic_const_exprs)] +//~^ WARN the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] //~^^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] pub struct Changes @@ -16,9 +16,7 @@ where [(); CHANGES.len()]:, { pub const fn new() -> Self { - Self { - changes: [0; CHANGES.len()], - } + Self { changes: [0; CHANGES.len()] } } } diff --git a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr index 1cceaece715b..b6b297593a25 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr @@ -1,17 +1,17 @@ -warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-97047-ice-1.rs:3:12 +warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-97047-ice-1.rs:3:30 | -LL | #![feature(adt_const_params, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^ +LL | #![feature(adt_const_params, unsized_const_params, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #95174 for more information = note: `#[warn(incomplete_features)]` on by default warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-97047-ice-1.rs:3:30 + --> $DIR/issue-97047-ice-1.rs:3:52 | -LL | #![feature(adt_const_params, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![feature(adt_const_params, unsized_const_params, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ | = note: see issue #76560 for more information diff --git a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs index 1338f40208c5..6a91b5225672 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs @@ -1,7 +1,7 @@ //@ check-pass -#![feature(adt_const_params, generic_const_exprs)] -//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] +#![feature(adt_const_params, unsized_const_params, generic_const_exprs)] +//~^ WARN the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] //~^^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] pub struct Changes diff --git a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr index 774e842bcbea..c0c7dcc79dc4 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr @@ -1,17 +1,17 @@ -warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-97047-ice-2.rs:3:12 +warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-97047-ice-2.rs:3:30 | -LL | #![feature(adt_const_params, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^ +LL | #![feature(adt_const_params, unsized_const_params, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #95174 for more information = note: `#[warn(incomplete_features)]` on by default warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-97047-ice-2.rs:3:30 + --> $DIR/issue-97047-ice-2.rs:3:52 | -LL | #![feature(adt_const_params, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![feature(adt_const_params, unsized_const_params, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ | = note: see issue #76560 for more information diff --git a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr index 5e4acd80e933..2a6d9f533174 100644 --- a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr +++ b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr @@ -1,14 +1,14 @@ error: generic parameters may not be used in const operations - --> $DIR/intrinsics-type_name-as-const-argument.rs:15:44 + --> $DIR/intrinsics-type_name-as-const-argument.rs:14:45 | -LL | T: Trait<{std::intrinsics::type_name::()}> - | ^ cannot perform const operation using `T` +LL | T: Trait<{ std::intrinsics::type_name::() }>, + | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: `&'static str` is forbidden as the type of a const generic parameter - --> $DIR/intrinsics-type_name-as-const-argument.rs:10:22 + --> $DIR/intrinsics-type_name-as-const-argument.rs:9:22 | LL | trait Trait {} | ^^^^^^^^^^^^ @@ -18,6 +18,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.rs b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.rs index 02e6d27a27e6..79c20fe81e35 100644 --- a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.rs +++ b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.rs @@ -2,8 +2,7 @@ //@ revisions: full min #![cfg_attr(full, allow(incomplete_features))] -#![cfg_attr(full, feature(adt_const_params, generic_const_exprs))] - +#![cfg_attr(full, feature(adt_const_params, unsized_const_params, generic_const_exprs))] #![feature(core_intrinsics)] #![feature(const_type_name)] @@ -12,10 +11,10 @@ trait Trait {} struct Bug where - T: Trait<{std::intrinsics::type_name::()}> + T: Trait<{ std::intrinsics::type_name::() }>, //[min]~^ ERROR generic parameters may not be used in const operations { - t: T + t: T, } fn main() {} diff --git a/tests/ui/const-generics/issue-66451.rs b/tests/ui/const-generics/issue-66451.rs index c8d5515e9873..0b8693e0e675 100644 --- a/tests/ui/const-generics/issue-66451.rs +++ b/tests/ui/const-generics/issue-66451.rs @@ -1,30 +1,20 @@ -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] -use std::marker::ConstParamTy; +use std::marker::UnsizedConstParamTy; -#[derive(Debug, PartialEq, Eq, ConstParamTy)] +#[derive(Debug, PartialEq, Eq, UnsizedConstParamTy)] struct Foo { value: i32, nested: &'static Bar, } -#[derive(Debug, PartialEq, Eq, ConstParamTy)] +#[derive(Debug, PartialEq, Eq, UnsizedConstParamTy)] struct Bar(T); struct Test; fn main() { - let x: Test<{ - Foo { - value: 3, - nested: &Bar(4), - } - }> = Test; - let y: Test<{ - Foo { - value: 3, - nested: &Bar(5), - } - }> = x; //~ ERROR mismatched types + let x: Test<{ Foo { value: 3, nested: &Bar(4) } }> = Test; + let y: Test<{ Foo { value: 3, nested: &Bar(5) } }> = x; //~ ERROR mismatched types } diff --git a/tests/ui/const-generics/issue-66451.stderr b/tests/ui/const-generics/issue-66451.stderr index 404e3839bca9..63d193e1bca4 100644 --- a/tests/ui/const-generics/issue-66451.stderr +++ b/tests/ui/const-generics/issue-66451.stderr @@ -1,16 +1,10 @@ error[E0308]: mismatched types - --> $DIR/issue-66451.rs:29:10 + --> $DIR/issue-66451.rs:19:58 | -LL | let y: Test<{ - | ____________- -LL | | Foo { -LL | | value: 3, -LL | | nested: &Bar(5), -LL | | } -LL | | }> = x; - | | - ^ expected `Foo { value: 3, nested: &Bar::(5) }`, found `Foo { value: 3, nested: &Bar::(4) }` - | |______| - | expected due to this +LL | let y: Test<{ Foo { value: 3, nested: &Bar(5) } }> = x; + | ------------------------------------------- ^ expected `Foo { value: 3, nested: &Bar::(5) }`, found `Foo { value: 3, nested: &Bar::(4) }` + | | + | expected due to this | = note: expected struct `Test(5) }>` found struct `Test(4) }>` diff --git a/tests/ui/const-generics/issue-70408.rs b/tests/ui/const-generics/issue-70408.rs index e74bcf945a54..ea7a57d3b2f9 100644 --- a/tests/ui/const-generics/issue-70408.rs +++ b/tests/ui/const-generics/issue-70408.rs @@ -1,6 +1,6 @@ //@ build-pass -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] pub fn function_with_bytes() -> &'static [u8] { diff --git a/tests/ui/const-generics/issue-80471.rs b/tests/ui/const-generics/issue-80471.rs index fa6f1fde435a..20d92092b9fa 100644 --- a/tests/ui/const-generics/issue-80471.rs +++ b/tests/ui/const-generics/issue-80471.rs @@ -1,5 +1,4 @@ #![feature(adt_const_params)] -//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] #[derive(PartialEq, Eq)] enum Nat { diff --git a/tests/ui/const-generics/issue-80471.stderr b/tests/ui/const-generics/issue-80471.stderr index b21ad3aec795..a8514c5cc074 100644 --- a/tests/ui/const-generics/issue-80471.stderr +++ b/tests/ui/const-generics/issue-80471.stderr @@ -1,14 +1,5 @@ -warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-80471.rs:1:12 - | -LL | #![feature(adt_const_params)] - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #95174 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0741]: `Nat` must implement `ConstParamTy` to be used as the type of a const generic parameter - --> $DIR/issue-80471.rs:10:17 + --> $DIR/issue-80471.rs:9:17 | LL | fn foo() {} | ^^^ @@ -19,6 +10,6 @@ LL + #[derive(ConstParamTy)] LL | enum Nat { | -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0741`. diff --git a/tests/ui/const-generics/issues/issue-100313.rs b/tests/ui/const-generics/issues/issue-100313.rs index 4e9d3626aa89..e07fde76a4a8 100644 --- a/tests/ui/const-generics/issues/issue-100313.rs +++ b/tests/ui/const-generics/issues/issue-100313.rs @@ -1,10 +1,10 @@ #![allow(incomplete_features)] #![feature(const_mut_refs)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] struct T; -impl T { +impl T { const fn set_false(&self) { unsafe { *(B as *const bool as *mut bool) = false; @@ -14,7 +14,7 @@ impl T { } const _: () = { - let x = T::<{&true}>; + let x = T::<{ &true }>; x.set_false(); }; diff --git a/tests/ui/const-generics/issues/issue-105821.rs b/tests/ui/const-generics/issues/issue-105821.rs index ecbae4d9f35c..3092893837aa 100644 --- a/tests/ui/const-generics/issues/issue-105821.rs +++ b/tests/ui/const-generics/issues/issue-105821.rs @@ -4,7 +4,7 @@ // a failing test, we just started masking the bug. #![allow(incomplete_features)] -#![feature(adt_const_params, generic_const_exprs)] +#![feature(adt_const_params, unsized_const_params, generic_const_exprs)] #![allow(dead_code)] const fn catone(_a: &[u8; M]) -> [u8; M + 1] diff --git a/tests/ui/const-generics/issues/issue-56445-1.min.stderr b/tests/ui/const-generics/issues/issue-56445-1.min.stderr index 580542bb6da3..ff0a1bfc0b55 100644 --- a/tests/ui/const-generics/issues/issue-56445-1.min.stderr +++ b/tests/ui/const-generics/issues/issue-56445-1.min.stderr @@ -17,6 +17,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/issues/issue-56445-1.rs b/tests/ui/const-generics/issues/issue-56445-1.rs index 35126b3f55ad..53aab40b0ad4 100644 --- a/tests/ui/const-generics/issues/issue-56445-1.rs +++ b/tests/ui/const-generics/issues/issue-56445-1.rs @@ -1,6 +1,6 @@ // Regression test for https://github.com/rust-lang/rust/issues/56445#issuecomment-518402995. //@ revisions: full min -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] #![crate_type = "lib"] diff --git a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr index 5082705927ee..8ea96428deb3 100644 --- a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr +++ b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr @@ -4,7 +4,7 @@ error[E0741]: `&'static (dyn A + 'static)` can't be used as a const parameter ty LL | fn test() { | ^^^^^^^^^^^^^^ | - = note: `(dyn A + 'static)` must implement `ConstParamTy`, but it does not + = note: `(dyn A + 'static)` must implement `UnsizedConstParamTy`, but it does not error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr index 7f387cbd5a13..101ca456cd90 100644 --- a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr +++ b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr @@ -9,6 +9,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.rs b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.rs index c5b83e9d5298..9b15a8a70132 100644 --- a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.rs +++ b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.rs @@ -1,5 +1,5 @@ //@ revisions: full min -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] trait A {} diff --git a/tests/ui/const-generics/issues/issue-66596-impl-trait-for-str-const-arg.rs b/tests/ui/const-generics/issues/issue-66596-impl-trait-for-str-const-arg.rs index 113bf94b5cb0..41c5eaa0cd9c 100644 --- a/tests/ui/const-generics/issues/issue-66596-impl-trait-for-str-const-arg.rs +++ b/tests/ui/const-generics/issues/issue-66596-impl-trait-for-str-const-arg.rs @@ -1,8 +1,7 @@ //@ check-pass -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] - trait Trait { type Assoc; } diff --git a/tests/ui/const-generics/issues/issue-71547.rs b/tests/ui/const-generics/issues/issue-71547.rs index a2cea433a44d..bb9ca63bd326 100644 --- a/tests/ui/const-generics/issues/issue-71547.rs +++ b/tests/ui/const-generics/issues/issue-71547.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] pub trait GetType { diff --git a/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr b/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr index e9363d421487..cba03b1cb1f0 100644 --- a/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr +++ b/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr @@ -9,6 +9,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.rs b/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.rs index 701b3423f319..fcab1f70507c 100644 --- a/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.rs +++ b/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.rs @@ -3,12 +3,12 @@ //@ revisions: full min //@[full]check-pass -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] fn a() {} //[min]~^ ERROR `&'static [u32]` is forbidden as the type of a const generic parameter fn main() { - a::<{&[]}>(); + a::<{ &[] }>(); } diff --git a/tests/ui/const-generics/issues/issue-86535-2.rs b/tests/ui/const-generics/issues/issue-86535-2.rs index bd9431dbc85b..ab68c6b78df3 100644 --- a/tests/ui/const-generics/issues/issue-86535-2.rs +++ b/tests/ui/const-generics/issues/issue-86535-2.rs @@ -1,10 +1,12 @@ //@ run-pass -#![feature(adt_const_params, generic_const_exprs)] +#![feature(adt_const_params, unsized_const_params, generic_const_exprs)] #![allow(incomplete_features)] pub trait Foo { const ASSOC_C: usize; - fn foo() where [(); Self::ASSOC_C]:; + fn foo() + where + [(); Self::ASSOC_C]:; } #[allow(dead_code)] @@ -12,7 +14,10 @@ struct Bar; impl Foo for Bar { const ASSOC_C: usize = 3; - fn foo() where [u8; Self::ASSOC_C]: { + fn foo() + where + [u8; Self::ASSOC_C]:, + { let _: [u8; Self::ASSOC_C] = loop {}; } } diff --git a/tests/ui/const-generics/issues/issue-86535.rs b/tests/ui/const-generics/issues/issue-86535.rs index cd9934a4a997..9aaf7ddc9e86 100644 --- a/tests/ui/const-generics/issues/issue-86535.rs +++ b/tests/ui/const-generics/issues/issue-86535.rs @@ -1,5 +1,5 @@ //@ run-pass -#![feature(adt_const_params, generic_const_exprs)] +#![feature(adt_const_params, unsized_const_params, generic_const_exprs)] #![allow(incomplete_features, unused_variables)] #[allow(dead_code)] diff --git a/tests/ui/const-generics/issues/issue-90455.fixed b/tests/ui/const-generics/issues/issue-90455.fixed index 2502d47eb462..423a1fbd7657 100644 --- a/tests/ui/const-generics/issues/issue-90455.fixed +++ b/tests/ui/const-generics/issues/issue-90455.fixed @@ -1,5 +1,5 @@ //@ run-rustfix -#![feature(generic_const_exprs, adt_const_params)] +#![feature(generic_const_exprs, unsized_const_params, adt_const_params)] #![allow(incomplete_features, dead_code)] struct FieldElement where [(); num_limbs(N)]: { diff --git a/tests/ui/const-generics/issues/issue-90455.rs b/tests/ui/const-generics/issues/issue-90455.rs index 794c7d76cb1f..be4f27ec689a 100644 --- a/tests/ui/const-generics/issues/issue-90455.rs +++ b/tests/ui/const-generics/issues/issue-90455.rs @@ -1,5 +1,5 @@ //@ run-rustfix -#![feature(generic_const_exprs, adt_const_params)] +#![feature(generic_const_exprs, unsized_const_params, adt_const_params)] #![allow(incomplete_features, dead_code)] struct FieldElement { diff --git a/tests/ui/const-generics/issues/issue-99641.stderr b/tests/ui/const-generics/issues/issue-99641.stderr index 800aec3ef2ce..3365012a0384 100644 --- a/tests/ui/const-generics/issues/issue-99641.stderr +++ b/tests/ui/const-generics/issues/issue-99641.stderr @@ -4,7 +4,7 @@ error[E0741]: `(fn(),)` can't be used as a const parameter type LL | pub struct Color; | ^^^^^^^ | - = note: `fn()` must implement `ConstParamTy`, but it does not + = note: `fn()` must implement `ConstParamTy_`, but it does not error[E0741]: `(fn(),)` can't be used as a const parameter type --> $DIR/issue-99641.rs:8:23 @@ -12,7 +12,7 @@ error[E0741]: `(fn(),)` can't be used as a const parameter type LL | impl Color { | ^^^^^^^ | - = note: `fn()` must implement `ConstParamTy`, but it does not + = note: `fn()` must implement `ConstParamTy_`, but it does not error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/min_const_generics/complex-types.stderr b/tests/ui/const-generics/min_const_generics/complex-types.stderr index 8e83ea58194f..0211770f9e51 100644 --- a/tests/ui/const-generics/min_const_generics/complex-types.stderr +++ b/tests/ui/const-generics/min_const_generics/complex-types.stderr @@ -45,6 +45,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `!` is forbidden as the type of a const generic parameter --> $DIR/complex-types.rs:17:21 diff --git a/tests/ui/const-generics/raw-ptr-const-param-deref.adt_const_params.stderr b/tests/ui/const-generics/raw-ptr-const-param-deref.adt_const_params.stderr new file mode 100644 index 000000000000..18f47f7dc23e --- /dev/null +++ b/tests/ui/const-generics/raw-ptr-const-param-deref.adt_const_params.stderr @@ -0,0 +1,15 @@ +error[E0741]: using raw pointers as const generic parameters is forbidden + --> $DIR/raw-ptr-const-param-deref.rs:11:23 + | +LL | struct Const; + | ^^^^^^^^^^ + +error[E0741]: using raw pointers as const generic parameters is forbidden + --> $DIR/raw-ptr-const-param-deref.rs:13:15 + | +LL | impl Const

{ + | ^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0741`. diff --git a/tests/ui/const-generics/raw-ptr-const-param-deref.full.stderr b/tests/ui/const-generics/raw-ptr-const-param-deref.full.stderr index 657eee2be244..18f47f7dc23e 100644 --- a/tests/ui/const-generics/raw-ptr-const-param-deref.full.stderr +++ b/tests/ui/const-generics/raw-ptr-const-param-deref.full.stderr @@ -1,11 +1,11 @@ error[E0741]: using raw pointers as const generic parameters is forbidden - --> $DIR/raw-ptr-const-param-deref.rs:9:23 + --> $DIR/raw-ptr-const-param-deref.rs:11:23 | LL | struct Const; | ^^^^^^^^^^ error[E0741]: using raw pointers as const generic parameters is forbidden - --> $DIR/raw-ptr-const-param-deref.rs:11:15 + --> $DIR/raw-ptr-const-param-deref.rs:13:15 | LL | impl Const

{ | ^^^^^^^^^^ diff --git a/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr b/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr index 1eb238255abc..6027dbb01cdd 100644 --- a/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr +++ b/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr @@ -1,5 +1,5 @@ error: using raw pointers as const generic parameters is forbidden - --> $DIR/raw-ptr-const-param-deref.rs:9:23 + --> $DIR/raw-ptr-const-param-deref.rs:11:23 | LL | struct Const; | ^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | struct Const; = note: the only supported types are integers, `bool` and `char` error: using raw pointers as const generic parameters is forbidden - --> $DIR/raw-ptr-const-param-deref.rs:11:15 + --> $DIR/raw-ptr-const-param-deref.rs:13:15 | LL | impl Const

{ | ^^^^^^^^^^ diff --git a/tests/ui/const-generics/raw-ptr-const-param-deref.rs b/tests/ui/const-generics/raw-ptr-const-param-deref.rs index b7fcbb3447a6..bf077acd4fae 100644 --- a/tests/ui/const-generics/raw-ptr-const-param-deref.rs +++ b/tests/ui/const-generics/raw-ptr-const-param-deref.rs @@ -1,21 +1,22 @@ // Checks that pointers must not be used as the type of const params. -//@ revisions: full min +//@ revisions: min adt_const_params full -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(adt_const_params, feature(adt_const_params))] +#![cfg_attr(adt_const_params, allow(incomplete_features))] const A: u32 = 3; struct Const; //~ ERROR: using raw pointers as const generic parameters -impl Const

{ //~ ERROR: using raw pointers as const generic parameters +impl Const

{ + //~^ ERROR: using raw pointers as const generic parameters fn get() -> u32 { - unsafe { - *P - } + unsafe { *P } } } fn main() { - assert_eq!(Const::<{&A as *const _}>::get(), 3) + assert_eq!(Const::<{ &A as *const _ }>::get(), 3) } diff --git a/tests/ui/const-generics/raw-ptr-const-param.adt_const_params.stderr b/tests/ui/const-generics/raw-ptr-const-param.adt_const_params.stderr new file mode 100644 index 000000000000..f040d3cc36a7 --- /dev/null +++ b/tests/ui/const-generics/raw-ptr-const-param.adt_const_params.stderr @@ -0,0 +1,21 @@ +error[E0741]: using raw pointers as const generic parameters is forbidden + --> $DIR/raw-ptr-const-param.rs:8:23 + | +LL | struct Const; + | ^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/raw-ptr-const-param.rs:11:40 + | +LL | let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; + | ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}` + | | + | expected due to this + | + = note: expected struct `Const<{0xf as *const u32}>` + found struct `Const<{0xa as *const u32}>` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0741. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/raw-ptr-const-param.full.stderr b/tests/ui/const-generics/raw-ptr-const-param.full.stderr index 7ba9ac15bf3a..f040d3cc36a7 100644 --- a/tests/ui/const-generics/raw-ptr-const-param.full.stderr +++ b/tests/ui/const-generics/raw-ptr-const-param.full.stderr @@ -1,11 +1,11 @@ error[E0741]: using raw pointers as const generic parameters is forbidden - --> $DIR/raw-ptr-const-param.rs:6:23 + --> $DIR/raw-ptr-const-param.rs:8:23 | LL | struct Const; | ^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/raw-ptr-const-param.rs:9:40 + --> $DIR/raw-ptr-const-param.rs:11:40 | LL | let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; | ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}` diff --git a/tests/ui/const-generics/raw-ptr-const-param.min.stderr b/tests/ui/const-generics/raw-ptr-const-param.min.stderr index 18bbcc33c4df..c48eea069e0d 100644 --- a/tests/ui/const-generics/raw-ptr-const-param.min.stderr +++ b/tests/ui/const-generics/raw-ptr-const-param.min.stderr @@ -1,5 +1,5 @@ error: using raw pointers as const generic parameters is forbidden - --> $DIR/raw-ptr-const-param.rs:6:23 + --> $DIR/raw-ptr-const-param.rs:8:23 | LL | struct Const; | ^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | struct Const; = note: the only supported types are integers, `bool` and `char` error[E0308]: mismatched types - --> $DIR/raw-ptr-const-param.rs:9:40 + --> $DIR/raw-ptr-const-param.rs:11:40 | LL | let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; | ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}` diff --git a/tests/ui/const-generics/raw-ptr-const-param.rs b/tests/ui/const-generics/raw-ptr-const-param.rs index 19d18a2f9d2c..49e48d9905f4 100644 --- a/tests/ui/const-generics/raw-ptr-const-param.rs +++ b/tests/ui/const-generics/raw-ptr-const-param.rs @@ -1,7 +1,9 @@ -//@ revisions: full min +//@ revisions: min adt_const_params full -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(adt_const_params, feature(adt_const_params))] +#![cfg_attr(adt_const_params, allow(incomplete_features))] struct Const; //~ ERROR: using raw pointers as const generic parameters diff --git a/tests/ui/const-generics/slice-const-param-mismatch.adt_const_params.stderr b/tests/ui/const-generics/slice-const-param-mismatch.adt_const_params.stderr new file mode 100644 index 000000000000..bcb2bd255dab --- /dev/null +++ b/tests/ui/const-generics/slice-const-param-mismatch.adt_const_params.stderr @@ -0,0 +1,49 @@ +error[E0741]: `&'static str` can't be used as a const parameter type + --> $DIR/slice-const-param-mismatch.rs:8:29 + | +LL | struct ConstString; + | ^^^^^^^^^^^^ + +error[E0741]: `&'static [u8]` can't be used as a const parameter type + --> $DIR/slice-const-param-mismatch.rs:11:28 + | +LL | struct ConstBytes; + | ^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/slice-const-param-mismatch.rs:17:35 + | +LL | let _: ConstString<"Hello"> = ConstString::<"World">; + | -------------------- ^^^^^^^^^^^^^^^^^^^^^^ expected `"Hello"`, found `"World"` + | | + | expected due to this + | + = note: expected struct `ConstString<"Hello">` + found struct `ConstString<"World">` + +error[E0308]: mismatched types + --> $DIR/slice-const-param-mismatch.rs:19:33 + | +LL | let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; + | ------------------- ^^^^^^^^^^^^^^^^^^^^^ expected `"ℇ㇈↦"`, found `"ℇ㇈↥"` + | | + | expected due to this + | + = note: expected struct `ConstString<"ℇ㇈↦">` + found struct `ConstString<"ℇ㇈↥">` + +error[E0308]: mismatched types + --> $DIR/slice-const-param-mismatch.rs:21:33 + | +LL | let _: ConstBytes = ConstBytes::; + | ------------------ ^^^^^^^^^^^^^^^^^^^^ expected `b"AAA"`, found `b"BBB"` + | | + | expected due to this + | + = note: expected struct `ConstBytes` + found struct `ConstBytes` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0308, E0741. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/slice-const-param-mismatch.full.stderr b/tests/ui/const-generics/slice-const-param-mismatch.full.stderr index 80dd1be33c24..883ba988be71 100644 --- a/tests/ui/const-generics/slice-const-param-mismatch.full.stderr +++ b/tests/ui/const-generics/slice-const-param-mismatch.full.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/slice-const-param-mismatch.rs:14:35 + --> $DIR/slice-const-param-mismatch.rs:17:35 | LL | let _: ConstString<"Hello"> = ConstString::<"World">; | -------------------- ^^^^^^^^^^^^^^^^^^^^^^ expected `"Hello"`, found `"World"` @@ -10,7 +10,7 @@ LL | let _: ConstString<"Hello"> = ConstString::<"World">; found struct `ConstString<"World">` error[E0308]: mismatched types - --> $DIR/slice-const-param-mismatch.rs:16:33 + --> $DIR/slice-const-param-mismatch.rs:19:33 | LL | let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; | ------------------- ^^^^^^^^^^^^^^^^^^^^^ expected `"ℇ㇈↦"`, found `"ℇ㇈↥"` @@ -21,7 +21,7 @@ LL | let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; found struct `ConstString<"ℇ㇈↥">` error[E0308]: mismatched types - --> $DIR/slice-const-param-mismatch.rs:18:33 + --> $DIR/slice-const-param-mismatch.rs:21:33 | LL | let _: ConstBytes = ConstBytes::; | ------------------ ^^^^^^^^^^^^^^^^^^^^ expected `b"AAA"`, found `b"BBB"` diff --git a/tests/ui/const-generics/slice-const-param-mismatch.min.stderr b/tests/ui/const-generics/slice-const-param-mismatch.min.stderr index 0650dafc685d..3b2410c98947 100644 --- a/tests/ui/const-generics/slice-const-param-mismatch.min.stderr +++ b/tests/ui/const-generics/slice-const-param-mismatch.min.stderr @@ -1,5 +1,5 @@ error: `&'static str` is forbidden as the type of a const generic parameter - --> $DIR/slice-const-param-mismatch.rs:7:29 + --> $DIR/slice-const-param-mismatch.rs:8:29 | LL | struct ConstString; | ^^^^^^^^^^^^ @@ -9,9 +9,13 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `&'static [u8]` is forbidden as the type of a const generic parameter - --> $DIR/slice-const-param-mismatch.rs:9:28 + --> $DIR/slice-const-param-mismatch.rs:11:28 | LL | struct ConstBytes; | ^^^^^^^^^^^^^ @@ -21,9 +25,13 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error[E0308]: mismatched types - --> $DIR/slice-const-param-mismatch.rs:14:35 + --> $DIR/slice-const-param-mismatch.rs:17:35 | LL | let _: ConstString<"Hello"> = ConstString::<"World">; | -------------------- ^^^^^^^^^^^^^^^^^^^^^^ expected `"Hello"`, found `"World"` @@ -34,7 +42,7 @@ LL | let _: ConstString<"Hello"> = ConstString::<"World">; found struct `ConstString<"World">` error[E0308]: mismatched types - --> $DIR/slice-const-param-mismatch.rs:16:33 + --> $DIR/slice-const-param-mismatch.rs:19:33 | LL | let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; | ------------------- ^^^^^^^^^^^^^^^^^^^^^ expected `"ℇ㇈↦"`, found `"ℇ㇈↥"` @@ -45,7 +53,7 @@ LL | let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; found struct `ConstString<"ℇ㇈↥">` error[E0308]: mismatched types - --> $DIR/slice-const-param-mismatch.rs:18:33 + --> $DIR/slice-const-param-mismatch.rs:21:33 | LL | let _: ConstBytes = ConstBytes::; | ------------------ ^^^^^^^^^^^^^^^^^^^^ expected `b"AAA"`, found `b"BBB"` diff --git a/tests/ui/const-generics/slice-const-param-mismatch.rs b/tests/ui/const-generics/slice-const-param-mismatch.rs index 733eeb69fa99..feee39e602d0 100644 --- a/tests/ui/const-generics/slice-const-param-mismatch.rs +++ b/tests/ui/const-generics/slice-const-param-mismatch.rs @@ -1,19 +1,22 @@ -//@ revisions: full min +//@ revisions: min adt_const_params full -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] - +#![cfg_attr(adt_const_params, feature(adt_const_params))] +#![cfg_attr(adt_const_params, allow(incomplete_features))] struct ConstString; //[min]~^ ERROR +//[adt_const_params]~^^ ERROR struct ConstBytes; //[min]~^ ERROR +//[adt_const_params]~^^ ERROR pub fn main() { let _: ConstString<"Hello"> = ConstString::<"Hello">; let _: ConstString<"Hello"> = ConstString::<"World">; //~ ERROR mismatched types let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↦">; let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; //~ ERROR mismatched types - let _: ConstBytes = ConstBytes::<{&[0x41, 0x41, 0x41]}>; + let _: ConstBytes = ConstBytes::<{ &[0x41, 0x41, 0x41] }>; let _: ConstBytes = ConstBytes::; //~ ERROR mismatched types } diff --git a/tests/ui/const-generics/slice-const-param.rs b/tests/ui/const-generics/slice-const-param.rs index c6c0047c929b..1c5088b52835 100644 --- a/tests/ui/const-generics/slice-const-param.rs +++ b/tests/ui/const-generics/slice-const-param.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] pub fn function_with_str() -> &'static str { @@ -12,9 +12,8 @@ pub fn function_with_bytes() -> &'static [u8] { } // Also check the codepaths for custom DST -#[derive(PartialEq, Eq)] +#[derive(std::marker::UnsizedConstParamTy, PartialEq, Eq)] struct MyStr(str); -impl std::marker::ConstParamTy for MyStr {} fn function_with_my_str() -> &'static MyStr { S @@ -34,7 +33,7 @@ pub fn main() { assert_eq!(function_with_str::<"Rust">(), "Rust"); assert_eq!(function_with_str::<"ℇ㇈↦">(), "ℇ㇈↦"); assert_eq!(function_with_bytes::(), &[0x41, 0x41, 0x41, 0x41]); - assert_eq!(function_with_bytes::<{&[0x41, 0x41, 0x41, 0x41]}>(), b"AAAA"); + assert_eq!(function_with_bytes::<{ &[0x41, 0x41, 0x41, 0x41] }>(), b"AAAA"); assert_eq!(function_with_my_str::<{ MyStr::new("hello") }>().as_str(), "hello"); } diff --git a/tests/ui/const-generics/transmute-const-param-static-reference.adt_const_params.stderr b/tests/ui/const-generics/transmute-const-param-static-reference.adt_const_params.stderr new file mode 100644 index 000000000000..7a936ced0305 --- /dev/null +++ b/tests/ui/const-generics/transmute-const-param-static-reference.adt_const_params.stderr @@ -0,0 +1,9 @@ +error[E0741]: `&'static ()` can't be used as a const parameter type + --> $DIR/transmute-const-param-static-reference.rs:9:23 + | +LL | struct Const; + | ^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0741`. diff --git a/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr b/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr index fdb6ddeb578b..cf236487cf0e 100644 --- a/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr +++ b/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr @@ -1,5 +1,5 @@ error: `&'static ()` is forbidden as the type of a const generic parameter - --> $DIR/transmute-const-param-static-reference.rs:7:23 + --> $DIR/transmute-const-param-static-reference.rs:9:23 | LL | struct Const; | ^^^^^^^^^^^ @@ -9,6 +9,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/transmute-const-param-static-reference.rs b/tests/ui/const-generics/transmute-const-param-static-reference.rs index 49541233ed1f..0b47fd31eaf6 100644 --- a/tests/ui/const-generics/transmute-const-param-static-reference.rs +++ b/tests/ui/const-generics/transmute-const-param-static-reference.rs @@ -1,16 +1,17 @@ -//@ revisions: full min +//@ revisions: full adt_const_params min //@[full] check-pass -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(adt_const_params, feature(adt_const_params))] +#![cfg_attr(adt_const_params, allow(incomplete_features))] struct Const; //[min]~^ ERROR `&'static ()` is forbidden as the type of a const generic parameter +//[adt_const_params]~^^ ERROR `&'static ()` can't be used as a const parameter type fn main() { - const A: &'static () = unsafe { - std::mem::transmute(10 as *const ()) - }; + const A: &'static () = unsafe { std::mem::transmute(10 as *const ()) }; - let _ = Const::<{A}>; + let _ = Const::<{ A }>; } diff --git a/tests/ui/const-generics/type-dependent/issue-71348.min.stderr b/tests/ui/const-generics/type-dependent/issue-71348.min.stderr index f42a331a8a40..858900a500d8 100644 --- a/tests/ui/const-generics/type-dependent/issue-71348.min.stderr +++ b/tests/ui/const-generics/type-dependent/issue-71348.min.stderr @@ -9,6 +9,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `&'static str` is forbidden as the type of a const generic parameter --> $DIR/issue-71348.rs:18:25 @@ -21,6 +25,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/type-dependent/issue-71348.rs b/tests/ui/const-generics/type-dependent/issue-71348.rs index f349a88d124f..2ffbd015485a 100644 --- a/tests/ui/const-generics/type-dependent/issue-71348.rs +++ b/tests/ui/const-generics/type-dependent/issue-71348.rs @@ -1,6 +1,6 @@ //@ [full] run-pass //@ revisions: full min -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] struct Foo { diff --git a/tests/ui/consts/refs_check_const_eq-issue-88384.rs b/tests/ui/consts/refs_check_const_eq-issue-88384.rs index fb0405b651cc..46cb62751717 100644 --- a/tests/ui/consts/refs_check_const_eq-issue-88384.rs +++ b/tests/ui/consts/refs_check_const_eq-issue-88384.rs @@ -1,10 +1,10 @@ #![feature(fn_traits)] -#![feature(adt_const_params)] -//~^ WARNING the feature `adt_const_params` is incomplete +#![feature(adt_const_params, unsized_const_params)] +//~^ WARNING the feature `unsized_const_params` is incomplete #[derive(PartialEq, Eq)] -struct CompileTimeSettings{ - hooks: &'static[fn()], +struct CompileTimeSettings { + hooks: &'static [fn()], } struct Foo; @@ -12,14 +12,11 @@ struct Foo; impl Foo { //~^ ERROR `CompileTimeSettings` must implement `ConstParamTy` to be used as the type of a const generic parameter - fn call_hooks(){ - } + fn call_hooks() {} } -fn main(){ - const SETTINGS: CompileTimeSettings = CompileTimeSettings{ - hooks: &[], - }; +fn main() { + const SETTINGS: CompileTimeSettings = CompileTimeSettings { hooks: &[] }; Foo::::call_hooks(); } diff --git a/tests/ui/consts/refs_check_const_eq-issue-88384.stderr b/tests/ui/consts/refs_check_const_eq-issue-88384.stderr index c490cd053e70..62c5c5276411 100644 --- a/tests/ui/consts/refs_check_const_eq-issue-88384.stderr +++ b/tests/ui/consts/refs_check_const_eq-issue-88384.stderr @@ -1,8 +1,8 @@ -warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/refs_check_const_eq-issue-88384.rs:2:12 +warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/refs_check_const_eq-issue-88384.rs:2:30 | -LL | #![feature(adt_const_params)] - | ^^^^^^^^^^^^^^^^ +LL | #![feature(adt_const_params, unsized_const_params)] + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #95174 for more information = note: `#[warn(incomplete_features)]` on by default @@ -16,7 +16,7 @@ LL | struct Foo; help: add `#[derive(ConstParamTy)]` to the struct | LL + #[derive(ConstParamTy)] -LL | struct CompileTimeSettings{ +LL | struct CompileTimeSettings { | error[E0741]: `CompileTimeSettings` must implement `ConstParamTy` to be used as the type of a const generic parameter @@ -28,7 +28,7 @@ LL | impl Foo { help: add `#[derive(ConstParamTy)]` to the struct | LL + #[derive(ConstParamTy)] -LL | struct CompileTimeSettings{ +LL | struct CompileTimeSettings { | error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/consts/refs_check_const_value_eq-issue-88876.rs b/tests/ui/consts/refs_check_const_value_eq-issue-88876.rs index 446fdc755148..33b6b7f52ca1 100644 --- a/tests/ui/consts/refs_check_const_value_eq-issue-88876.rs +++ b/tests/ui/consts/refs_check_const_value_eq-issue-88876.rs @@ -1,7 +1,7 @@ //@ check-pass #![allow(incomplete_features)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] struct FooConst {} diff --git a/tests/ui/error-codes/E0771.rs b/tests/ui/error-codes/E0771.rs index c0a2e98a7df6..a932c5ef9815 100644 --- a/tests/ui/error-codes/E0771.rs +++ b/tests/ui/error-codes/E0771.rs @@ -1,5 +1,5 @@ -#![feature(adt_const_params)] -//~^ WARN the feature `adt_const_params` is incomplete +#![feature(adt_const_params, unsized_const_params)] +//~^ WARN the feature `unsized_const_params` is incomplete fn function_with_str<'a, const STRING: &'a str>() {} //~ ERROR E0770 diff --git a/tests/ui/error-codes/E0771.stderr b/tests/ui/error-codes/E0771.stderr index e1384effe37a..5e829e6f6d2d 100644 --- a/tests/ui/error-codes/E0771.stderr +++ b/tests/ui/error-codes/E0771.stderr @@ -6,11 +6,11 @@ LL | fn function_with_str<'a, const STRING: &'a str>() {} | = note: lifetime parameters may not be used in the type of const parameters -warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/E0771.rs:1:12 +warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/E0771.rs:1:30 | -LL | #![feature(adt_const_params)] - | ^^^^^^^^^^^^^^^^ +LL | #![feature(adt_const_params, unsized_const_params)] + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #95174 for more information = note: `#[warn(incomplete_features)]` on by default diff --git a/tests/ui/feature-gates/feature-gate-adt_const_params.stderr b/tests/ui/feature-gates/feature-gate-adt_const_params.stderr index fcb9b8a6fc57..649e936888b2 100644 --- a/tests/ui/feature-gates/feature-gate-adt_const_params.stderr +++ b/tests/ui/feature-gates/feature-gate-adt_const_params.stderr @@ -9,6 +9,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 1 previous error diff --git a/tests/ui/feature-gates/feature-gate-unsized-const-params.rs b/tests/ui/feature-gates/feature-gate-unsized-const-params.rs new file mode 100644 index 000000000000..d088d382377c --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unsized-const-params.rs @@ -0,0 +1,6 @@ +struct Foo; +//~^ ERROR: `[u8]` is forbidden as the type of a const generic parameter +//~| HELP: add `#![feature(adt_const_params)]` to the crate +//~| HELP: add `#![feature(unsized_const_params)]` to the crate + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr b/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr new file mode 100644 index 000000000000..0a87f34f4f51 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr @@ -0,0 +1,18 @@ +error: `[u8]` is forbidden as the type of a const generic parameter + --> $DIR/feature-gate-unsized-const-params.rs:1:21 + | +LL | struct Foo; + | ^^^^ + | + = note: the only supported types are integers, `bool` and `char` +help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types + | +LL + #![feature(adt_const_params)] + | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/generic-const-items/elided-lifetimes.stderr b/tests/ui/generic-const-items/elided-lifetimes.stderr index 1d4a997ff606..85807a1b631a 100644 --- a/tests/ui/generic-const-items/elided-lifetimes.stderr +++ b/tests/ui/generic-const-items/elided-lifetimes.stderr @@ -32,6 +32,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 4 previous errors diff --git a/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs b/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs index a6dcad3face0..00034fb9f447 100644 --- a/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs +++ b/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] trait Bar {} diff --git a/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs b/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs index b6395258c892..9205f1e1632c 100644 --- a/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs +++ b/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs @@ -1,7 +1,7 @@ //@ check-pass #![allow(incomplete_features)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] pub struct Element; diff --git a/tests/ui/inference/ice-cannot-relate-region-109178.rs b/tests/ui/inference/ice-cannot-relate-region-109178.rs index 3282f95a992a..2e3953646fff 100644 --- a/tests/ui/inference/ice-cannot-relate-region-109178.rs +++ b/tests/ui/inference/ice-cannot-relate-region-109178.rs @@ -2,7 +2,7 @@ #![allow(incomplete_features)] #![crate_type = "lib"] -#![feature(adt_const_params, generic_const_exprs)] +#![feature(adt_const_params, unsized_const_params, generic_const_exprs)] struct Changes //~^ ERROR `&` without an explicit lifetime name cannot be used here diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr index 70f06b4be603..e446345aedce 100644 --- a/tests/ui/lifetimes/unusual-rib-combinations.stderr +++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr @@ -63,6 +63,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 8 previous errors diff --git a/tests/ui/simd/intrinsic/generic-elements.rs b/tests/ui/simd/intrinsic/generic-elements.rs index abceb08ecc5a..aec75a673067 100644 --- a/tests/ui/simd/intrinsic/generic-elements.rs +++ b/tests/ui/simd/intrinsic/generic-elements.rs @@ -1,6 +1,6 @@ //@ build-fail -#![feature(repr_simd, intrinsics, rustc_attrs, adt_const_params)] +#![feature(repr_simd, intrinsics, rustc_attrs, adt_const_params, unsized_const_params)] #![allow(incomplete_features)] #[repr(simd)] @@ -14,8 +14,7 @@ struct i32x4(i32, i32, i32, i32); #[repr(simd)] #[derive(Copy, Clone)] #[allow(non_camel_case_types)] -struct i32x8(i32, i32, i32, i32, - i32, i32, i32, i32); +struct i32x8(i32, i32, i32, i32, i32, i32, i32, i32); #[repr(simd)] #[derive(Copy, Clone)] @@ -28,8 +27,7 @@ struct f32x4(f32, f32, f32, f32); #[repr(simd)] #[derive(Copy, Clone)] #[allow(non_camel_case_types)] -struct f32x8(f32, f32, f32, f32, - f32, f32, f32, f32); +struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); extern "rust-intrinsic" { fn simd_insert(x: T, idx: u32, y: E) -> T; @@ -61,11 +59,11 @@ fn main() { //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_shuffle::<_, _, f32x2>(x, x, IDX2); -//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` + //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` simd_shuffle::<_, _, f32x4>(x, x, IDX4); -//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` + //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` simd_shuffle::<_, _, f32x8>(x, x, IDX8); -//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` + //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` simd_shuffle::<_, _, i32x8>(x, x, IDX2); //~^ ERROR expected return type of length 2, found `i32x8` with length 8 @@ -85,11 +83,11 @@ fn main() { //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_shuffle_generic::<_, f32x2, I2>(x, x); -//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` + //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` simd_shuffle_generic::<_, f32x4, I4>(x, x); -//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` + //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` simd_shuffle_generic::<_, f32x8, I8>(x, x); -//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` + //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` simd_shuffle_generic::<_, i32x8, I2>(x, x); //~^ ERROR expected return type of length 2, found `i32x8` with length 8 diff --git a/tests/ui/simd/intrinsic/generic-elements.stderr b/tests/ui/simd/intrinsic/generic-elements.stderr index 26e01344939c..0788a7c17f99 100644 --- a/tests/ui/simd/intrinsic/generic-elements.stderr +++ b/tests/ui/simd/intrinsic/generic-elements.stderr @@ -1,125 +1,125 @@ error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:46:9 + --> $DIR/generic-elements.rs:44:9 | LL | simd_insert(0, 0, 0); | ^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected inserted type `i32` (element of input `i32x4`), found `f64` - --> $DIR/generic-elements.rs:48:9 + --> $DIR/generic-elements.rs:46:9 | LL | simd_insert(x, 0, 1.0); | ^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_extract` intrinsic: expected return type `i32` (element of input `i32x4`), found `f32` - --> $DIR/generic-elements.rs:50:9 + --> $DIR/generic-elements.rs:48:9 | LL | simd_extract::<_, f32>(x, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:54:9 + --> $DIR/generic-elements.rs:52:9 | LL | simd_shuffle::(0, 0, IDX2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:57:9 + --> $DIR/generic-elements.rs:55:9 | LL | simd_shuffle::(0, 0, IDX4); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:60:9 + --> $DIR/generic-elements.rs:58:9 | LL | simd_shuffle::(0, 0, IDX8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` - --> $DIR/generic-elements.rs:63:9 + --> $DIR/generic-elements.rs:61:9 | LL | simd_shuffle::<_, _, f32x2>(x, x, IDX2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` - --> $DIR/generic-elements.rs:65:9 + --> $DIR/generic-elements.rs:63:9 | LL | simd_shuffle::<_, _, f32x4>(x, x, IDX4); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` - --> $DIR/generic-elements.rs:67:9 + --> $DIR/generic-elements.rs:65:9 | LL | simd_shuffle::<_, _, f32x8>(x, x, IDX8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 2, found `i32x8` with length 8 - --> $DIR/generic-elements.rs:70:9 + --> $DIR/generic-elements.rs:68:9 | LL | simd_shuffle::<_, _, i32x8>(x, x, IDX2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 4, found `i32x8` with length 8 - --> $DIR/generic-elements.rs:72:9 + --> $DIR/generic-elements.rs:70:9 | LL | simd_shuffle::<_, _, i32x8>(x, x, IDX4); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 8, found `i32x2` with length 2 - --> $DIR/generic-elements.rs:74:9 + --> $DIR/generic-elements.rs:72:9 | LL | simd_shuffle::<_, _, i32x2>(x, x, IDX8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:78:9 + --> $DIR/generic-elements.rs:76:9 | LL | simd_shuffle_generic::(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:81:9 + --> $DIR/generic-elements.rs:79:9 | LL | simd_shuffle_generic::(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:84:9 + --> $DIR/generic-elements.rs:82:9 | LL | simd_shuffle_generic::(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` - --> $DIR/generic-elements.rs:87:9 + --> $DIR/generic-elements.rs:85:9 | LL | simd_shuffle_generic::<_, f32x2, I2>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` - --> $DIR/generic-elements.rs:89:9 + --> $DIR/generic-elements.rs:87:9 | LL | simd_shuffle_generic::<_, f32x4, I4>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` - --> $DIR/generic-elements.rs:91:9 + --> $DIR/generic-elements.rs:89:9 | LL | simd_shuffle_generic::<_, f32x8, I8>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return type of length 2, found `i32x8` with length 8 - --> $DIR/generic-elements.rs:94:9 + --> $DIR/generic-elements.rs:92:9 | LL | simd_shuffle_generic::<_, i32x8, I2>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return type of length 4, found `i32x8` with length 8 - --> $DIR/generic-elements.rs:96:9 + --> $DIR/generic-elements.rs:94:9 | LL | simd_shuffle_generic::<_, i32x8, I4>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return type of length 8, found `i32x2` with length 2 - --> $DIR/generic-elements.rs:98:9 + --> $DIR/generic-elements.rs:96:9 | LL | simd_shuffle_generic::<_, i32x2, I8>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/simd/monomorphize-shuffle-index.rs b/tests/ui/simd/monomorphize-shuffle-index.rs index 379616884a1b..30c345cb9047 100644 --- a/tests/ui/simd/monomorphize-shuffle-index.rs +++ b/tests/ui/simd/monomorphize-shuffle-index.rs @@ -1,7 +1,7 @@ //@[old]run-pass //@[generic_with_fn]run-pass //@ revisions: old generic generic_with_fn -#![feature(repr_simd, intrinsics, adt_const_params, generic_const_exprs)] +#![feature(repr_simd, intrinsics, adt_const_params, unsized_const_params, generic_const_exprs)] #![allow(incomplete_features)] extern "rust-intrinsic" { diff --git a/tests/ui/statics/const_generics.rs b/tests/ui/statics/const_generics.rs index 70d9b933a765..7f64f6995a45 100644 --- a/tests/ui/statics/const_generics.rs +++ b/tests/ui/statics/const_generics.rs @@ -11,7 +11,7 @@ //@[opt] compile-flags: -O #![feature(const_refs_to_static)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] static FOO: usize = 42; diff --git a/tests/ui/symbol-names/const-generics-str-demangling.rs b/tests/ui/symbol-names/const-generics-str-demangling.rs index 871f3694e00c..87b1fdf8a479 100644 --- a/tests/ui/symbol-names/const-generics-str-demangling.rs +++ b/tests/ui/symbol-names/const-generics-str-demangling.rs @@ -1,7 +1,7 @@ //@ build-fail //@ compile-flags: -C symbol-mangling-version=v0 --crate-name=c //@ normalize-stderr-test: "c\[.*?\]" -> "c[HASH]" -#![feature(adt_const_params, rustc_attrs)] +#![feature(adt_const_params, unsized_const_params, rustc_attrs)] #![allow(incomplete_features)] pub struct Str; diff --git a/tests/ui/symbol-names/const-generics-structural-demangling.rs b/tests/ui/symbol-names/const-generics-structural-demangling.rs index 6c79ed7314cf..9f5f31177b38 100644 --- a/tests/ui/symbol-names/const-generics-structural-demangling.rs +++ b/tests/ui/symbol-names/const-generics-structural-demangling.rs @@ -3,10 +3,10 @@ //@ normalize-stderr-test: "c\[[0-9a-f]+\]" -> "c[HASH]" -#![feature(adt_const_params, decl_macro, rustc_attrs)] +#![feature(adt_const_params, unsized_const_params, decl_macro, rustc_attrs)] #![allow(incomplete_features)] -use std::marker::ConstParamTy; +use std::marker::UnsizedConstParamTy; pub struct RefByte; @@ -14,7 +14,7 @@ pub struct RefByte; //~^ ERROR symbol-name //~| ERROR demangling //~| ERROR demangling-alt(>) -impl RefByte<{&123}> {} +impl RefByte<{ &123 }> {} // FIXME(eddyb) this was supposed to be `RefMutZst` with `&mut []`, // but that is currently not allowed in const generics. @@ -24,7 +24,7 @@ pub struct RefZst; //~^ ERROR symbol-name //~| ERROR demangling //~| ERROR demangling-alt(>) -impl RefZst<{&[]}> {} +impl RefZst<{ &[] }> {} pub struct Array3Bytes; @@ -32,7 +32,7 @@ pub struct Array3Bytes; //~^ ERROR symbol-name //~| ERROR demangling //~| ERROR demangling-alt(>) -impl Array3Bytes<{[1, 2, 3]}> {} +impl Array3Bytes<{ [1, 2, 3] }> {} pub struct TupleByteBool; @@ -40,9 +40,9 @@ pub struct TupleByteBool; //~^ ERROR symbol-name //~| ERROR demangling //~| ERROR demangling-alt(>) -impl TupleByteBool<{(1, false)}> {} +impl TupleByteBool<{ (1, false) }> {} -#[derive(PartialEq, Eq, ConstParamTy)] +#[derive(PartialEq, Eq, UnsizedConstParamTy)] pub enum MyOption { Some(T), None, @@ -56,7 +56,7 @@ pub struct OptionUsize>; //~^ ERROR symbol-name //~| ERROR demangling //~| ERROR demangling-alt(::None}>>) -impl OptionUsize<{MyOption::None}> {} +impl OptionUsize<{ MyOption::None }> {} // HACK(eddyb) the full mangling is only in `.stderr` because we can normalize // the `core` disambiguator hash away there, but not here. @@ -64,9 +64,9 @@ impl OptionUsize<{MyOption::None}> {} //~^ ERROR symbol-name //~| ERROR demangling //~| ERROR demangling-alt(::Some(0)}>>) -impl OptionUsize<{MyOption::Some(0)}> {} +impl OptionUsize<{ MyOption::Some(0) }> {} -#[derive(PartialEq, Eq, ConstParamTy)] +#[derive(PartialEq, Eq, UnsizedConstParamTy)] pub struct Foo { s: &'static str, ch: char, @@ -78,12 +78,12 @@ pub struct Foo_; //~^ ERROR symbol-name //~| ERROR demangling //~| ERROR demangling-alt(>) -impl Foo_<{Foo { s: "abc", ch: 'x', slice: &[1, 2, 3] }}> {} +impl Foo_<{ Foo { s: "abc", ch: 'x', slice: &[1, 2, 3] } }> {} // NOTE(eddyb) this tests specifically the use of disambiguators in field names, // using macros 2.0 hygiene to create a `struct` with conflicting field names. macro duplicate_field_name_test($x:ident) { - #[derive(PartialEq, Eq, ConstParamTy)] + #[derive(PartialEq, Eq, UnsizedConstParamTy)] pub struct Bar { $x: u8, x: u16, @@ -94,7 +94,7 @@ macro duplicate_field_name_test($x:ident) { //~^ ERROR symbol-name //~| ERROR demangling //~| ERROR demangling-alt(>) - impl Bar_<{Bar { $x: 123, x: 4096 }}> {} + impl Bar_<{ Bar { $x: 123, x: 4096 } }> {} } duplicate_field_name_test!(x); diff --git a/tests/ui/typeck/ice-unexpected-region-123863.stderr b/tests/ui/typeck/ice-unexpected-region-123863.stderr index 08f1ede95b45..0479f134a389 100644 --- a/tests/ui/typeck/ice-unexpected-region-123863.stderr +++ b/tests/ui/typeck/ice-unexpected-region-123863.stderr @@ -9,6 +9,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `&'static str` is forbidden as the type of a const generic parameter --> $DIR/ice-unexpected-region-123863.rs:3:27 @@ -21,6 +25,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error[E0223]: ambiguous associated type --> $DIR/ice-unexpected-region-123863.rs:5:5 From ec6e07b09d0c499f4f3233f04826ecf2ce77800b Mon Sep 17 00:00:00 2001 From: Jerry Wang Date: Sat, 13 Jul 2024 14:27:56 -0400 Subject: [PATCH 237/734] Migrate `crate-hash-rustc-version` to `rmake` --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../crate-hash-rustc-version/Makefile | 38 --------------- .../crate-hash-rustc-version/rmake.rs | 47 +++++++++++++++++++ 3 files changed, 47 insertions(+), 39 deletions(-) delete mode 100644 tests/run-make/crate-hash-rustc-version/Makefile create mode 100644 tests/run-make/crate-hash-rustc-version/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index f7ec7d0b3f6b..b2c1ff3f5f41 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -12,7 +12,6 @@ run-make/cdylib-dylib-linkage/Makefile run-make/compiler-lookup-paths-2/Makefile run-make/compiler-lookup-paths/Makefile run-make/compiler-rt-works-on-mingw/Makefile -run-make/crate-hash-rustc-version/Makefile run-make/cross-lang-lto-clang/Makefile run-make/cross-lang-lto-pgo-smoketest/Makefile run-make/cross-lang-lto-upstream-rlibs/Makefile diff --git a/tests/run-make/crate-hash-rustc-version/Makefile b/tests/run-make/crate-hash-rustc-version/Makefile deleted file mode 100644 index 6bf504bf01be..000000000000 --- a/tests/run-make/crate-hash-rustc-version/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# Ensure that crates compiled with different rustc versions cannot -# be dynamically linked. - -FLAGS := -Cprefer-dynamic -Csymbol-mangling-version=v0 -UNAME := $(shell uname) -ifeq ($(UNAME),Linux) - EXT=".so" - NM_CMD := nm -D -endif -ifeq ($(UNAME),Darwin) - EXT=".dylib" - NM_CMD := nm -endif - -ifndef NM_CMD -all: - exit 0 -else -all: - # a.rs is a dylib - $(RUSTC) a.rs --crate-type=dylib $(FLAGS) - # Write symbols to disk. - $(NM_CMD) $(call DYLIB,a) > $(TMPDIR)/symbolsbefore - # b.rs is a binary - $(RUSTC) b.rs --extern a=$(TMPDIR)/liba$(EXT) --crate-type=bin -Crpath $(FLAGS) - $(call RUN,b) - # Now re-compile a.rs with another rustc version - RUSTC_FORCE_RUSTC_VERSION=deadfeed $(RUSTC) a.rs --crate-type=dylib $(FLAGS) - # After compiling with a different rustc version, write symbols to disk again. - $(NM_CMD) $(call DYLIB,a) > $(TMPDIR)/symbolsafter - # As a sanity check, test if the symbols changed: - # If the symbols are identical, there's been an error. - if diff $(TMPDIR)/symbolsbefore $(TMPDIR)/symbolsafter; then exit 1; fi - $(call FAIL,b) -endif diff --git a/tests/run-make/crate-hash-rustc-version/rmake.rs b/tests/run-make/crate-hash-rustc-version/rmake.rs new file mode 100644 index 000000000000..6418deb126bd --- /dev/null +++ b/tests/run-make/crate-hash-rustc-version/rmake.rs @@ -0,0 +1,47 @@ +// Ensure that crates compiled with different rustc versions cannot +// be dynamically linked. + +//@ ignore-cross-compile +//@ only-unix + +use run_make_support::{cmd, diff, dynamic_lib_name, is_darwin, run, run_fail, rustc}; + +fn main() { + let flags = ["-Cprefer-dynamic", "-Csymbol-mangling-version=v0"]; + let nm_flag = if is_darwin() { [].as_slice() } else { ["-D"].as_slice() }; + + // a.rs is compiled to a dylib + rustc().input("a.rs").crate_type("dylib").args(&flags).run(); + + // Store symbols + let symbols_before = cmd("nm").args(nm_flag).arg(dynamic_lib_name("a")).run().stdout_utf8(); + + // b.rs is compiled to a binary + rustc() + .input("b.rs") + .extern_("a", dynamic_lib_name("a")) + .crate_type("bin") + .arg("-Crpath") + .args(&flags) + .run(); + run("b"); + + // Now re-compile a.rs with another rustc version + rustc() + .env("RUSTC_FORCE_RUSTC_VERSION", "deadfeed") + .input("a.rs") + .crate_type("dylib") + .args(&flags) + .run(); + + // After compiling with a different rustc version, store symbols again. + let symbols_after = cmd("nm").args(nm_flag).arg(dynamic_lib_name("a")).run().stdout_utf8(); + + // As a sanity check, test if the symbols changed: + // If the symbols are identical, there's been an error. + diff() + .expected_text("symbols_before", symbols_before) + .actual_text("symbols_after", symbols_after) + .run_fail(); + run_fail("b"); +} From eea6502dcb91942785b1d5cb8fea74c41bcc3f32 Mon Sep 17 00:00:00 2001 From: Jerry Wang Date: Mon, 15 Jul 2024 19:52:22 -0400 Subject: [PATCH 238/734] Use `llvm-readobj` for `run-make/crate-hash-rustc-version` --- .../run-make/crate-hash-rustc-version/rmake.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/run-make/crate-hash-rustc-version/rmake.rs b/tests/run-make/crate-hash-rustc-version/rmake.rs index 6418deb126bd..97b3dd3931e8 100644 --- a/tests/run-make/crate-hash-rustc-version/rmake.rs +++ b/tests/run-make/crate-hash-rustc-version/rmake.rs @@ -4,17 +4,27 @@ //@ ignore-cross-compile //@ only-unix -use run_make_support::{cmd, diff, dynamic_lib_name, is_darwin, run, run_fail, rustc}; +use run_make_support::llvm; +use run_make_support::{diff, dynamic_lib_name, is_darwin, run, run_fail, rustc}; + +fn llvm_readobj() -> llvm::LlvmReadobj { + let mut cmd = llvm::llvm_readobj(); + if is_darwin() { + cmd.symbols(); + } else { + cmd.dynamic_table(); + } + cmd +} fn main() { let flags = ["-Cprefer-dynamic", "-Csymbol-mangling-version=v0"]; - let nm_flag = if is_darwin() { [].as_slice() } else { ["-D"].as_slice() }; // a.rs is compiled to a dylib rustc().input("a.rs").crate_type("dylib").args(&flags).run(); // Store symbols - let symbols_before = cmd("nm").args(nm_flag).arg(dynamic_lib_name("a")).run().stdout_utf8(); + let symbols_before = llvm_readobj().arg(dynamic_lib_name("a")).run().stdout_utf8(); // b.rs is compiled to a binary rustc() @@ -35,7 +45,7 @@ fn main() { .run(); // After compiling with a different rustc version, store symbols again. - let symbols_after = cmd("nm").args(nm_flag).arg(dynamic_lib_name("a")).run().stdout_utf8(); + let symbols_after = llvm_readobj().arg(dynamic_lib_name("a")).run().stdout_utf8(); // As a sanity check, test if the symbols changed: // If the symbols are identical, there's been an error. From 40e07a3ab13913eaed0e9fa336669f590d07d89a Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 17 Jul 2024 14:18:41 +0800 Subject: [PATCH 239/734] Remove invalid further restricting for type bound --- compiler/rustc_middle/src/ty/diagnostics.rs | 14 ++++++++ ...types-invalid-trait-ref-issue-18865.stderr | 5 --- ...invalid-type-bound-suggest-issue-127555.rs | 23 +++++++++++++ ...lid-type-bound-suggest-issue-127555.stderr | 33 +++++++++++++++++++ .../in-trait/unconstrained-impl-region.stderr | 4 --- ...didate-from-env-universe-err-2.next.stderr | 4 --- ...-from-env-universe-err-project.next.stderr | 8 ----- .../hrtb-higher-ranker-supertraits.stderr | 8 ----- .../return-dont-satisfy-bounds.stderr | 4 --- 9 files changed, 70 insertions(+), 33 deletions(-) create mode 100644 tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs create mode 100644 tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 4bf223379913..f479b18c7c43 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -271,6 +271,19 @@ pub fn suggest_constraining_type_params<'a>( } } + // in the scenario like impl has stricter requirements than trait, + // we should not suggest restrict bound on the impl, here we double check + // the whether the param already has the constraint by checking `def_id` + let bound_trait_defs: Vec = generics + .bounds_for_param(param.def_id) + .flat_map(|bound| { + bound.bounds.iter().flat_map(|b| b.trait_ref().and_then(|t| t.trait_def_id())) + }) + .collect(); + + constraints + .retain(|(_, def_id)| def_id.map_or(true, |def| !bound_trait_defs.contains(&def))); + if constraints.is_empty() { continue; } @@ -332,6 +345,7 @@ pub fn suggest_constraining_type_params<'a>( // -- // | // replace with: `T: Bar +` + if let Some((span, open_paren_sp)) = generics.bounds_span_for_suggestions(param.def_id) { suggest_restrict(span, true, open_paren_sp); continue; diff --git a/tests/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr b/tests/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr index adde31b4a321..b4012d2a5b9f 100644 --- a/tests/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr +++ b/tests/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr @@ -3,11 +3,6 @@ error[E0277]: the trait bound `T: Foo` is not satisfied | LL | let u: >::Bar = t.get_bar(); | ^ the trait `Foo` is not implemented for `T` - | -help: consider further restricting this bound - | -LL | fn f + Foo>(t: &T) { - | ++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs new file mode 100644 index 000000000000..6083cc7d96dc --- /dev/null +++ b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs @@ -0,0 +1,23 @@ +//@ edition:2021 +// issue: rust-lang/rust#127555 + +pub trait Foo { + fn bar(&mut self, func: F) -> impl std::future::Future + Send + where + F: FnMut(); +} + +struct Baz {} + +impl Foo for Baz { + async fn bar(&mut self, _func: F) -> () + //~^ ERROR `F` cannot be sent between threads safely + where + F: FnMut() + Send, + //~^ ERROR impl has stricter requirements than trait + { + () + } +} + +fn main() {} diff --git a/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr new file mode 100644 index 000000000000..7f3cd2a59005 --- /dev/null +++ b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr @@ -0,0 +1,33 @@ +error[E0277]: `F` cannot be sent between threads safely + --> $DIR/remove-invalid-type-bound-suggest-issue-127555.rs:13:5 + | +LL | / async fn bar(&mut self, _func: F) -> () +LL | | +LL | | where +LL | | F: FnMut() + Send, + | |__________________________^ `F` cannot be sent between threads safely + | +note: required by a bound in `::bar` + --> $DIR/remove-invalid-type-bound-suggest-issue-127555.rs:16:22 + | +LL | async fn bar(&mut self, _func: F) -> () + | --- required by a bound in this associated function +... +LL | F: FnMut() + Send, + | ^^^^ required by this bound in `::bar` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/remove-invalid-type-bound-suggest-issue-127555.rs:16:22 + | +LL | / fn bar(&mut self, func: F) -> impl std::future::Future + Send +LL | | where +LL | | F: FnMut(); + | |___________________- definition of `bar` from trait +... +LL | F: FnMut() + Send, + | ^^^^ impl has extra requirement `F: Send` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0276, E0277. +For more information about an error, try `rustc --explain E0276`. diff --git a/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr b/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr index 66819d1fcf7d..80dc5fdc7470 100644 --- a/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr +++ b/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr @@ -9,10 +9,6 @@ note: required by a bound in `<() as Actor>::on_mount` | LL | async fn on_mount(self, _: impl Inbox<&'a ()>) {} | ^^^^^^^^^^^^^ required by this bound in `<() as Actor>::on_mount` -help: consider further restricting this bound - | -LL | async fn on_mount(self, _: impl Inbox<&'a ()> + Inbox<&'a ()>) {} - | +++++++++++++++ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates --> $DIR/unconstrained-impl-region.rs:13:6 diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr index 8771de85c192..3697bd9cf021 100644 --- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr @@ -9,10 +9,6 @@ note: required by a bound in `impl_hr` | LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {} | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impl_hr` -help: consider further restricting this bound - | -LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static> + for<'a> Trait<'a, '_>>() { - | +++++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr index 90df487c07e7..6e0ec5620da0 100644 --- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr @@ -9,10 +9,6 @@ note: required by a bound in `trait_bound` | LL | fn trait_bound Trait<'a>>() {} | ^^^^^^^^^^^^^^^^^ required by this bound in `trait_bound` -help: consider further restricting this bound - | -LL | fn function1 + for<'a> Trait<'a>>() { - | +++++++++++++++++++ error[E0277]: the trait bound `for<'a> T: Trait<'a>` is not satisfied --> $DIR/candidate-from-env-universe-err-project.rs:38:24 @@ -25,10 +21,6 @@ note: required by a bound in `projection_bound` | LL | fn projection_bound Trait<'a, Assoc = usize>>() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `projection_bound` -help: consider further restricting this bound - | -LL | fn function2 + for<'a> Trait<'a>>() { - | +++++++++++++++++++ error[E0271]: type mismatch resolving `>::Assoc == usize` --> $DIR/candidate-from-env-universe-err-project.rs:38:24 diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr index af76377de850..dc1a4c9b983f 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr @@ -11,10 +11,6 @@ note: required by a bound in `want_foo_for_any_tcx` | LL | fn want_foo_for_any_tcx Foo<'tcx>>(f: &F) { | ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_foo_for_any_tcx` -help: consider further restricting this bound - | -LL | fn want_foo_for_some_tcx<'x, F: Foo<'x> + for<'tcx> Foo<'tcx>>(f: &'x F) { - | +++++++++++++++++++++ error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied --> $DIR/hrtb-higher-ranker-supertraits.rs:28:26 @@ -29,10 +25,6 @@ note: required by a bound in `want_bar_for_any_ccx` | LL | fn want_bar_for_any_ccx Bar<'ccx>>(b: &B) { | ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx` -help: consider further restricting this bound - | -LL | fn want_bar_for_some_ccx<'x, B: Bar<'x> + for<'ccx> Bar<'ccx>>(b: &B) { - | +++++++++++++++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr index fbf82a24b501..ae4490999878 100644 --- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr @@ -22,10 +22,6 @@ note: required by a bound in `>::foo` | LL | fn foo>(self) -> impl Foo { | ^^^^^^^ required by this bound in `>::foo` -help: consider further restricting this bound - | -LL | fn foo + Foo>(self) -> impl Foo { - | +++++++++ error[E0276]: impl has stricter requirements than trait --> $DIR/return-dont-satisfy-bounds.rs:8:16 From 2c2ef6ce9dc7206c019d3b0ad4fd6dbbd0026fd1 Mon Sep 17 00:00:00 2001 From: yukang Date: Thu, 11 Jul 2024 06:48:05 +0800 Subject: [PATCH 240/734] add chenyukang to review rotation --- triagebot.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index d47d54d45c0b..eef45df0c299 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -928,6 +928,7 @@ compiler-team-contributors = [ "@fee1-dead", "@jieyouxu", "@BoxyUwU", + "@chenyukang", ] compiler = [ "compiler-team", @@ -976,6 +977,7 @@ diagnostics = [ "@estebank", "@oli-obk", "@TaKO8Ki", + "@chenyukang", ] parser = [ "@compiler-errors", @@ -989,6 +991,7 @@ lexer = [ "@nnethercote", "@petrochenkov", "@estebank", + "@chenyukang", ] arena = [ "@nnethercote", From c65ddb8728de895b53557b0aaf7df1873417f916 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 17 Jul 2024 18:23:40 +0700 Subject: [PATCH 241/734] Add regression test for issue 13110 --- tests/ui/zero_repeat_side_effects.fixed | 10 ++++++++++ tests/ui/zero_repeat_side_effects.rs | 10 ++++++++++ tests/ui/zero_repeat_side_effects.stderr | 14 +++++++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/tests/ui/zero_repeat_side_effects.fixed b/tests/ui/zero_repeat_side_effects.fixed index 6f1325219264..ce6a46b8a60b 100644 --- a/tests/ui/zero_repeat_side_effects.fixed +++ b/tests/ui/zero_repeat_side_effects.fixed @@ -58,3 +58,13 @@ fn main() { // as function param drop(vec![f(); 1]); } + +macro_rules! LEN { + () => {0}; +} + +fn issue_13110() { + f(); let _data: [i32; 0] = []; + const LENGTH: usize = LEN!(); + f(); let _data: [i32; 0] = []; +} diff --git a/tests/ui/zero_repeat_side_effects.rs b/tests/ui/zero_repeat_side_effects.rs index 9d9c367375a7..d68667dda313 100644 --- a/tests/ui/zero_repeat_side_effects.rs +++ b/tests/ui/zero_repeat_side_effects.rs @@ -58,3 +58,13 @@ fn main() { // as function param drop(vec![f(); 1]); } + +macro_rules! LEN { + () => {0}; +} + +fn issue_13110() { + let _data = [f(); LEN!()]; + const LENGTH: usize = LEN!(); + let _data = [f(); LENGTH]; +} diff --git a/tests/ui/zero_repeat_side_effects.stderr b/tests/ui/zero_repeat_side_effects.stderr index afdc60542534..6f31242a2523 100644 --- a/tests/ui/zero_repeat_side_effects.stderr +++ b/tests/ui/zero_repeat_side_effects.stderr @@ -73,5 +73,17 @@ error: function or method calls as the initial value in zero-sized array initial LL | [f(); N]; | ^^^^^^^^ help: consider using: `{ f(); [] as [i32; 0] }` -error: aborting due to 12 previous errors +error: function or method calls as the initial value in zero-sized array initializers may cause side effects + --> tests/ui/zero_repeat_side_effects.rs:67:5 + | +LL | let _data = [f(); LEN!()]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f(); let _data: [i32; 0] = [];` + +error: function or method calls as the initial value in zero-sized array initializers may cause side effects + --> tests/ui/zero_repeat_side_effects.rs:69:5 + | +LL | let _data = [f(); LENGTH]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f(); let _data: [i32; 0] = [];` + +error: aborting due to 14 previous errors From 5540060d5d29aa56842cb004e5f1c2aa30d7b091 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 17 Jul 2024 11:27:42 +0000 Subject: [PATCH 242/734] Skip linting if array length is from a macro. --- clippy_lints/src/zero_repeat_side_effects.rs | 41 ++++++++++++++++---- tests/ui/zero_repeat_side_effects.fixed | 8 ++-- tests/ui/zero_repeat_side_effects.rs | 4 +- tests/ui/zero_repeat_side_effects.stderr | 14 +------ 4 files changed, 42 insertions(+), 25 deletions(-) diff --git a/clippy_lints/src/zero_repeat_side_effects.rs b/clippy_lints/src/zero_repeat_side_effects.rs index ad041e55bdaf..6f2bfab1a301 100644 --- a/clippy_lints/src/zero_repeat_side_effects.rs +++ b/clippy_lints/src/zero_repeat_side_effects.rs @@ -4,7 +4,8 @@ use clippy_utils::source::snippet; use clippy_utils::visitors::for_each_expr_without_closures; use rustc_ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::{ExprKind, Node}; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{ArrayLen, ExprKind, ItemKind, Node, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, ConstKind, Ty}; use rustc_session::declare_lint_pass; @@ -45,7 +46,8 @@ declare_clippy_lint! { declare_lint_pass!(ZeroRepeatSideEffects => [ZERO_REPEAT_SIDE_EFFECTS]); impl LateLintPass<'_> for ZeroRepeatSideEffects { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &rustc_hir::Expr<'_>) { + let hir_map = cx.tcx.hir(); if let Some(args) = VecArgs::hir(cx, expr) && let VecArgs::Repeat(inner_expr, len) = args && let ExprKind::Lit(l) = len.kind @@ -53,12 +55,35 @@ impl LateLintPass<'_> for ZeroRepeatSideEffects { && i.0 == 0 { inner_check(cx, expr, inner_expr, true); - } else if let ExprKind::Repeat(inner_expr, _) = expr.kind - && let ty::Array(_, cst) = cx.typeck_results().expr_ty(expr).kind() - && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind() - && element_count.to_target_usize(cx.tcx) == 0 - { - inner_check(cx, expr, inner_expr, false); + } else { + let ExprKind::Repeat(inner_expr, length) = expr.kind else { + return; + }; + // Skip if the length is from a macro. + if let ArrayLen::Body(anon_const) = length { + let length_expr = hir_map.body(anon_const.body).value; + if !length_expr.span.eq_ctxt(expr.span) { + return; + } + + // Get the initialization span of a const item and compare it with the span at use-site. + if let ExprKind::Path(QPath::Resolved(None, path)) = length_expr.kind + && let Res::Def(DefKind::Const, def_id) = path.res + && let Some(def_id) = def_id.as_local() + && let Node::Item(item) = cx.tcx.hir_node_by_def_id(def_id) + && let ItemKind::Const(_ty, _, body_id) = item.kind + && let init_span = hir_map.span_with_body(body_id.hir_id) + && !init_span.eq_ctxt(length_expr.span) + { + return; + } + } + if let ty::Array(_, cst) = cx.typeck_results().expr_ty(expr).kind() + && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind() + && element_count.to_target_usize(cx.tcx) == 0 + { + inner_check(cx, expr, inner_expr, false); + } } } } diff --git a/tests/ui/zero_repeat_side_effects.fixed b/tests/ui/zero_repeat_side_effects.fixed index ce6a46b8a60b..75ebc6f35d15 100644 --- a/tests/ui/zero_repeat_side_effects.fixed +++ b/tests/ui/zero_repeat_side_effects.fixed @@ -60,11 +60,13 @@ fn main() { } macro_rules! LEN { - () => {0}; + () => { + 0 + }; } fn issue_13110() { - f(); let _data: [i32; 0] = []; + let _data = [f(); LEN!()]; const LENGTH: usize = LEN!(); - f(); let _data: [i32; 0] = []; + let _data = [f(); LENGTH]; } diff --git a/tests/ui/zero_repeat_side_effects.rs b/tests/ui/zero_repeat_side_effects.rs index d68667dda313..1a1a9f93d1f8 100644 --- a/tests/ui/zero_repeat_side_effects.rs +++ b/tests/ui/zero_repeat_side_effects.rs @@ -60,7 +60,9 @@ fn main() { } macro_rules! LEN { - () => {0}; + () => { + 0 + }; } fn issue_13110() { diff --git a/tests/ui/zero_repeat_side_effects.stderr b/tests/ui/zero_repeat_side_effects.stderr index 6f31242a2523..afdc60542534 100644 --- a/tests/ui/zero_repeat_side_effects.stderr +++ b/tests/ui/zero_repeat_side_effects.stderr @@ -73,17 +73,5 @@ error: function or method calls as the initial value in zero-sized array initial LL | [f(); N]; | ^^^^^^^^ help: consider using: `{ f(); [] as [i32; 0] }` -error: function or method calls as the initial value in zero-sized array initializers may cause side effects - --> tests/ui/zero_repeat_side_effects.rs:67:5 - | -LL | let _data = [f(); LEN!()]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f(); let _data: [i32; 0] = [];` - -error: function or method calls as the initial value in zero-sized array initializers may cause side effects - --> tests/ui/zero_repeat_side_effects.rs:69:5 - | -LL | let _data = [f(); LENGTH]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f(); let _data: [i32; 0] = [];` - -error: aborting due to 14 previous errors +error: aborting due to 12 previous errors From 21dc49c587c7df282b8e96dc01c288c7d59bbd2c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Jul 2024 13:49:32 +0200 Subject: [PATCH 243/734] ptr::metadata: avoid references to extern types --- library/core/src/ptr/metadata.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index eb86bf662065..21d1b7ea0ce7 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -5,6 +5,7 @@ use crate::hash::{Hash, Hasher}; use crate::intrinsics::aggregate_raw_ptr; use crate::intrinsics::ptr_metadata; use crate::marker::Freeze; +use crate::ptr::NonNull; /// Provides the pointer metadata type of any pointed-to type. /// @@ -153,7 +154,7 @@ pub const fn from_raw_parts_mut( /// compare equal (since identical vtables can be deduplicated within a codegen unit). #[lang = "dyn_metadata"] pub struct DynMetadata { - _vtable_ptr: &'static VTable, + _vtable_ptr: NonNull, _phantom: crate::marker::PhantomData, } @@ -174,7 +175,7 @@ impl DynMetadata { fn vtable_ptr(self) -> *const VTable { // SAFETY: this layout assumption is hard-coded into the compiler. // If it's somehow not a size match, the transmute will error. - unsafe { crate::mem::transmute::(self) } + unsafe { crate::mem::transmute::(self) } } /// Returns the size of the type associated with this vtable. From 03bfa3690ef0d0acf6ea0dd0e4ea832d6eeb5524 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 17 Jul 2024 21:19:44 +1000 Subject: [PATCH 244/734] Rename `MatchPair` to `MatchPairTree` In #120904, `MatchPair` became able to store other match pairs as children, forming a tree. That has made the old name confusing, so this patch renames the type to `MatchPairTree`. --- .../src/build/matches/match_pair.rs | 46 ++++++++++--------- .../rustc_mir_build/src/build/matches/mod.rs | 18 ++++---- .../src/build/matches/simplify.rs | 4 +- .../rustc_mir_build/src/build/matches/test.rs | 4 +- .../rustc_mir_build/src/build/matches/util.rs | 6 +-- 5 files changed, 41 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs index 2f540478674d..95fec154918a 100644 --- a/compiler/rustc_mir_build/src/build/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs @@ -3,37 +3,37 @@ use rustc_middle::thir::{self, *}; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use crate::build::expr::as_place::{PlaceBase, PlaceBuilder}; -use crate::build::matches::{FlatPat, MatchPair, TestCase}; +use crate::build::matches::{FlatPat, MatchPairTree, TestCase}; use crate::build::Builder; impl<'a, 'tcx> Builder<'a, 'tcx> { - /// Builds and returns [`MatchPair`] trees, one for each pattern in + /// Builds and returns [`MatchPairTree`] subtrees, one for each pattern in /// `subpatterns`, representing the fields of a [`PatKind::Variant`] or /// [`PatKind::Leaf`]. /// - /// Used internally by [`MatchPair::new`]. + /// Used internally by [`MatchPairTree::for_pattern`]. fn field_match_pairs<'pat>( &mut self, place: PlaceBuilder<'tcx>, subpatterns: &'pat [FieldPat<'tcx>], - ) -> Vec> { + ) -> Vec> { subpatterns .iter() .map(|fieldpat| { let place = place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty)); - MatchPair::new(place, &fieldpat.pattern, self) + MatchPairTree::for_pattern(place, &fieldpat.pattern, self) }) .collect() } - /// Builds [`MatchPair`] trees for the prefix/middle/suffix parts of an + /// Builds [`MatchPairTree`] subtrees for the prefix/middle/suffix parts of an /// array pattern or slice pattern, and adds those trees to `match_pairs`. /// - /// Used internally by [`MatchPair::new`]. + /// Used internally by [`MatchPairTree::for_pattern`]. fn prefix_slice_suffix<'pat>( &mut self, - match_pairs: &mut Vec>, + match_pairs: &mut Vec>, place: &PlaceBuilder<'tcx>, prefix: &'pat [Box>], opt_slice: &'pat Option>>, @@ -52,7 +52,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { let elem = ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; - MatchPair::new(place.clone_project(elem), subpattern, self) + MatchPairTree::for_pattern(place.clone_project(elem), subpattern, self) })); if let Some(subslice_pat) = opt_slice { @@ -62,7 +62,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { to: if exact_size { min_length - suffix_len } else { suffix_len }, from_end: !exact_size, }); - match_pairs.push(MatchPair::new(subslice, subslice_pat, self)); + match_pairs.push(MatchPairTree::for_pattern(subslice, subslice_pat, self)); } match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| { @@ -73,19 +73,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { from_end: !exact_size, }; let place = place.clone_project(elem); - MatchPair::new(place, subpattern, self) + MatchPairTree::for_pattern(place, subpattern, self) })); } } -impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { - /// Recursively builds a `MatchPair` tree for the given pattern and its +impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> { + /// Recursively builds a match pair tree for the given pattern and its /// subpatterns. - pub(in crate::build) fn new( + pub(in crate::build) fn for_pattern( mut place_builder: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>, cx: &mut Builder<'_, 'tcx>, - ) -> MatchPair<'pat, 'tcx> { + ) -> MatchPairTree<'pat, 'tcx> { // Force the place type to the pattern's type. // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? if let Some(resolved) = place_builder.resolve_upvar(cx) { @@ -138,7 +138,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { variance, }); - subpairs.push(MatchPair::new(place_builder, subpattern, cx)); + subpairs.push(MatchPairTree::for_pattern(place_builder, subpattern, cx)); TestCase::Irrefutable { ascription, binding: None } } @@ -152,7 +152,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { if let Some(subpattern) = subpattern.as_ref() { // this is the `x @ P` case; have to keep matching against `P` now - subpairs.push(MatchPair::new(place_builder, subpattern, cx)); + subpairs.push(MatchPairTree::for_pattern(place_builder, subpattern, cx)); } TestCase::Irrefutable { ascription: None, binding } } @@ -182,7 +182,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { super::Ascription { annotation, source, variance: ty::Contravariant } }); - subpairs.push(MatchPair::new(place_builder, pattern, cx)); + subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx)); TestCase::Irrefutable { ascription, binding: None } } @@ -231,7 +231,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { } PatKind::Deref { ref subpattern } => { - subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx)); + subpairs.push(MatchPairTree::for_pattern(place_builder.deref(), subpattern, cx)); default_irrefutable() } @@ -242,13 +242,17 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability), pattern.span, ); - subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx)); + subpairs.push(MatchPairTree::for_pattern( + PlaceBuilder::from(temp).deref(), + subpattern, + cx, + )); TestCase::Deref { temp, mutability } } PatKind::Never => TestCase::Never, }; - MatchPair { place, test_case, subpairs, pattern } + MatchPairTree { place, test_case, subpairs, pattern } } } diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index fc4e9ebec0a8..535ee8946f2e 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1028,15 +1028,15 @@ impl<'tcx> PatternExtraData<'tcx> { #[derive(Debug, Clone)] struct FlatPat<'pat, 'tcx> { /// To match the pattern, all of these must be satisfied... - // Invariant: all the `MatchPair`s are recursively simplified. + // Invariant: all the match pairs are recursively simplified. // Invariant: or-patterns must be sorted to the end. - match_pairs: Vec>, + match_pairs: Vec>, extra_data: PatternExtraData<'tcx>, } impl<'tcx, 'pat> FlatPat<'pat, 'tcx> { - /// Creates a `FlatPat` containing a simplified [`MatchPair`] list/forest + /// Creates a `FlatPat` containing a simplified [`MatchPairTree`] list/forest /// for the given pattern. fn new( place: PlaceBuilder<'tcx>, @@ -1044,7 +1044,7 @@ impl<'tcx, 'pat> FlatPat<'pat, 'tcx> { cx: &mut Builder<'_, 'tcx>, ) -> Self { // First, recursively build a tree of match pairs for the given pattern. - let mut match_pairs = vec![MatchPair::new(place, pattern, cx)]; + let mut match_pairs = vec![MatchPairTree::for_pattern(place, pattern, cx)]; let mut extra_data = PatternExtraData { span: pattern.span, bindings: Vec::new(), @@ -1061,9 +1061,9 @@ impl<'tcx, 'pat> FlatPat<'pat, 'tcx> { #[derive(Debug)] struct Candidate<'pat, 'tcx> { /// For the candidate to match, all of these must be satisfied... - // Invariant: all the `MatchPair`s are recursively simplified. + // Invariant: all the match pairs are recursively simplified. // Invariant: or-patterns must be sorted at the end. - match_pairs: Vec>, + match_pairs: Vec>, /// ...and if this is non-empty, one of these subcandidates also has to match... // Invariant: at the end of the algorithm, this must never contain a `is_never` candidate @@ -1122,7 +1122,7 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { /// Returns whether the first match pair of this candidate is an or-pattern. fn starts_with_or_pattern(&self) -> bool { - matches!(&*self.match_pairs, [MatchPair { test_case: TestCase::Or { .. }, .. }, ..]) + matches!(&*self.match_pairs, [MatchPairTree { test_case: TestCase::Or { .. }, .. }, ..]) } /// Visit the leaf candidates (those with no subcandidates) contained in @@ -1202,7 +1202,7 @@ impl<'pat, 'tcx> TestCase<'pat, 'tcx> { /// Each node also has a list of subpairs (possibly empty) that must also match, /// and a reference to the THIR pattern it represents. #[derive(Debug, Clone)] -pub(crate) struct MatchPair<'pat, 'tcx> { +pub(crate) struct MatchPairTree<'pat, 'tcx> { /// This place... /// /// --- @@ -1625,7 +1625,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn create_or_subcandidates<'pat>( &mut self, candidate: &mut Candidate<'pat, 'tcx>, - match_pair: MatchPair<'pat, 'tcx>, + match_pair: MatchPairTree<'pat, 'tcx>, ) { let TestCase::Or { pats } = match_pair.test_case else { bug!() }; debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats); diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 543301c71a0e..20310f608210 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -12,7 +12,7 @@ //! sort of test: for example, testing which variant an enum is, or //! testing a value against a constant. -use crate::build::matches::{MatchPair, PatternExtraData, TestCase}; +use crate::build::matches::{MatchPairTree, PatternExtraData, TestCase}; use crate::build::Builder; use tracing::{debug, instrument}; @@ -24,7 +24,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub(super) fn simplify_match_pairs<'pat>( &mut self, - match_pairs: &mut Vec>, + match_pairs: &mut Vec>, extra_data: &mut PatternExtraData<'tcx>, ) { // In order to please the borrow checker, in a pattern like `x @ pat` we must lower the diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index d29874a5ad4b..fb59cee99c06 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -5,7 +5,7 @@ // identify what tests are needed, perform the tests, and then filter // the candidates based on the result. -use crate::build::matches::{Candidate, MatchPair, Test, TestBranch, TestCase, TestKind}; +use crate::build::matches::{Candidate, MatchPairTree, Test, TestBranch, TestCase, TestKind}; use crate::build::Builder; use rustc_data_structures::fx::FxIndexMap; use rustc_hir::{LangItem, RangeEnd}; @@ -26,7 +26,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Identifies what test is needed to decide if `match_pair` is applicable. /// /// It is a bug to call this with a not-fully-simplified pattern. - pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> { + pub(super) fn test<'pat>(&mut self, match_pair: &MatchPairTree<'pat, 'tcx>) -> Test<'tcx> { let kind = match match_pair.test_case { TestCase::Variant { adt_def, variant_index: _ } => TestKind::Switch { adt_def }, diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index e67fc843285e..8fe8069b3455 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -1,7 +1,7 @@ use std::marker::PhantomData; use crate::build::expr::as_place::PlaceBase; -use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase}; +use crate::build::matches::{Binding, Candidate, FlatPat, MatchPairTree, TestCase}; use crate::build::Builder; use rustc_data_structures::fx::FxIndexMap; use rustc_middle::mir::*; @@ -152,7 +152,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { } } - fn visit_match_pair(&mut self, match_pair: &MatchPair<'_, 'tcx>) { + fn visit_match_pair(&mut self, match_pair: &MatchPairTree<'_, 'tcx>) { if let TestCase::Or { pats, .. } = &match_pair.test_case { for flat_pat in pats.iter() { self.visit_flat_pat(flat_pat) @@ -260,7 +260,7 @@ where } } - fn visit_match_pair(&mut self, match_pair: &MatchPair<'_, 'tcx>) { + fn visit_match_pair(&mut self, match_pair: &MatchPairTree<'_, 'tcx>) { if let TestCase::Or { pats, .. } = &match_pair.test_case { // All the or-alternatives should bind the same locals, so we only visit the first one. self.visit_flat_pat(&pats[0]) From 411fcb6b2df7337377626680ef5ec5d99b5eba23 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 17 Jul 2024 21:41:42 +1000 Subject: [PATCH 245/734] Rename `test` to `pick_test_for_match_pair` --- compiler/rustc_mir_build/src/build/matches/mod.rs | 4 ++-- compiler/rustc_mir_build/src/build/matches/test.rs | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 535ee8946f2e..6910b32cfa7a 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1809,8 +1809,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// [`Range`]: TestKind::Range fn pick_test(&mut self, candidates: &[&mut Candidate<'_, 'tcx>]) -> (Place<'tcx>, Test<'tcx>) { // Extract the match-pair from the highest priority candidate - let match_pair = &candidates.first().unwrap().match_pairs[0]; - let test = self.test(match_pair); + let match_pair = &candidates[0].match_pairs[0]; + let test = self.pick_test_for_match_pair(match_pair); // Unwrap is ok after simplification. let match_place = match_pair.place.unwrap(); debug!(?test, ?match_pair); diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index fb59cee99c06..6f2d2022ac56 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -26,7 +26,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Identifies what test is needed to decide if `match_pair` is applicable. /// /// It is a bug to call this with a not-fully-simplified pattern. - pub(super) fn test<'pat>(&mut self, match_pair: &MatchPairTree<'pat, 'tcx>) -> Test<'tcx> { + pub(super) fn pick_test_for_match_pair<'pat>( + &mut self, + match_pair: &MatchPairTree<'pat, 'tcx>, + ) -> Test<'tcx> { let kind = match match_pair.test_case { TestCase::Variant { adt_def, variant_index: _ } => TestKind::Switch { adt_def }, From f9c0d3370f04d08cda2da268a54bc543eb310fc7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Jul 2024 13:50:17 +0200 Subject: [PATCH 246/734] ptr::metadata: update comment on vtable_ptr work-around --- library/core/src/ptr/metadata.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 21d1b7ea0ce7..06f205c0f267 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -167,10 +167,13 @@ extern "C" { } impl DynMetadata { - /// One of the things that rustc_middle does with this being a lang item is - /// give it `FieldsShape::Primitive`, which means that as far as codegen can - /// tell, it *is* a reference, and thus doesn't have any fields. - /// That means we can't use field access, and have to transmute it instead. + /// When `DynMetadata` appears as the metadata field of a wide pointer, the rustc_middle layout + /// computation does magic and the resulting layout is *not* a `FieldsShape::Aggregate`, instead + /// it is a `FieldsShape::Primitive`. This means that the same type can have different layout + /// depending on whether it appears as the metadata field of a wide pointer or as a stand-alone + /// type, which understandably confuses codegen and leads to ICEs when trying to project to a + /// field of `DynMetadata`. To work around that issue, we use `transmute` instead of using a + /// field projection. #[inline] fn vtable_ptr(self) -> *const VTable { // SAFETY: this layout assumption is hard-coded into the compiler. From 99f879c32f43e87366a2888f146799bb659e4b21 Mon Sep 17 00:00:00 2001 From: Kriskras99 Date: Wed, 17 Jul 2024 14:10:41 +0200 Subject: [PATCH 247/734] Document the column numbers for the dbg! macro The line numbers were also made consistent, some examples used the line numbers as shown on the playground while others used the line numbers that you would expect when just seeing the documentation. The second option was chosen to make everything consistent. --- library/std/src/macros.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index 972b6015932d..ba519afc62b0 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -230,7 +230,7 @@ macro_rules! eprintln { /// ```rust /// let a = 2; /// let b = dbg!(a * 2) + 1; -/// // ^-- prints: [src/main.rs:2] a * 2 = 4 +/// // ^-- prints: [src/main.rs:2:9] a * 2 = 4 /// assert_eq!(b, 5); /// ``` /// @@ -281,7 +281,7 @@ macro_rules! eprintln { /// This prints to [stderr]: /// /// ```text,ignore -/// [src/main.rs:4] n.checked_sub(4) = None +/// [src/main.rs:2:22] n.checked_sub(4) = None /// ``` /// /// Naive factorial implementation: @@ -301,15 +301,15 @@ macro_rules! eprintln { /// This prints to [stderr]: /// /// ```text,ignore -/// [src/main.rs:3] n <= 1 = false -/// [src/main.rs:3] n <= 1 = false -/// [src/main.rs:3] n <= 1 = false -/// [src/main.rs:3] n <= 1 = true -/// [src/main.rs:4] 1 = 1 -/// [src/main.rs:5] n * factorial(n - 1) = 2 -/// [src/main.rs:5] n * factorial(n - 1) = 6 -/// [src/main.rs:5] n * factorial(n - 1) = 24 -/// [src/main.rs:11] factorial(4) = 24 +/// [src/main.rs:2:8] n <= 1 = false +/// [src/main.rs:2:8] n <= 1 = false +/// [src/main.rs:2:8] n <= 1 = false +/// [src/main.rs:2:8] n <= 1 = true +/// [src/main.rs:3:9] 1 = 1 +/// [src/main.rs:7:9] n * factorial(n - 1) = 2 +/// [src/main.rs:7:9] n * factorial(n - 1) = 6 +/// [src/main.rs:7:9] n * factorial(n - 1) = 24 +/// [src/main.rs:9:1] factorial(4) = 24 /// ``` /// /// The `dbg!(..)` macro moves the input: From 0b0c39ca4d78c73430fbcd26eecb92b6c92c17d4 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Mon, 15 Jul 2024 12:51:07 +0000 Subject: [PATCH 248/734] Show progress while running dogfood test --- .cargo/config.toml | 2 +- Cargo.toml | 5 ++++- tests/dogfood.rs | 47 +++++++++++++++++++++++++++++----------------- 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 48a63e485681..7afdd068a990 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -4,7 +4,7 @@ uibless = "test --test compile-test -- -- --bless" bless = "test -- -- --bless" dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --" lintcheck = "run --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- " -collect-metadata = "test --test dogfood --features internal -- run_metadata_collection_lint --ignored" +collect-metadata = "test --test dogfood --features internal -- collect_metadata" [build] # -Zbinary-dep-depinfo allows us to track which rlib files to use for compiling UI tests diff --git a/Cargo.toml b/Cargo.toml index 5e52fd7e57ce..6e4878440c68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,6 @@ ui_test = "0.24" regex = "1.5.5" toml = "0.7.3" walkdir = "2.3" -# This is used by the `collect-metadata` alias. filetime = "0.2.9" itertools = "0.12" @@ -63,3 +62,7 @@ rustc_private = true [[test]] name = "compile-test" harness = false + +[[test]] +name = "dogfood" +harness = false diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 36a7a651c4d2..c8a761bf509e 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -7,23 +7,41 @@ #![warn(rust_2018_idioms, unused_lifetimes)] use itertools::Itertools; +use std::fs::File; +use std::io::{self, IsTerminal}; use std::path::PathBuf; use std::process::Command; +use std::time::SystemTime; use test_utils::IS_RUSTC_TEST_SUITE; +use ui_test::Args; mod test_utils; -#[test] -fn dogfood_clippy() { +fn main() { if IS_RUSTC_TEST_SUITE { return; } + let args = Args::test().unwrap(); + + if args.list { + if !args.ignored { + println!("dogfood: test"); + } + } else if !args.skip.iter().any(|arg| arg == "dogfood") { + if args.filters.iter().any(|arg| arg == "collect_metadata") { + collect_metadata(); + } else { + dogfood(); + } + } +} + +fn dogfood() { let mut failed_packages = Vec::new(); - // "" is the root package for package in [ - "", + "./", "clippy_dev", "clippy_lints", "clippy_utils", @@ -31,6 +49,7 @@ fn dogfood_clippy() { "lintcheck", "rustc_tools_util", ] { + println!("linting {package}"); if !run_clippy_for_package(package, &["-D", "clippy::all", "-D", "clippy::pedantic"]) { failed_packages.push(if package.is_empty() { "root" } else { package }); } @@ -43,12 +62,8 @@ fn dogfood_clippy() { ); } -#[test] -#[ignore] -#[cfg(feature = "internal")] -fn run_metadata_collection_lint() { - use std::fs::File; - use std::time::SystemTime; +fn collect_metadata() { + assert!(cfg!(feature = "internal")); // Setup for validation let metadata_output_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("util/gh-pages/lints.json"); @@ -101,6 +116,10 @@ fn run_clippy_for_package(project: &str, args: &[&str]) -> bool { .arg("--all-targets") .arg("--all-features"); + if !io::stdout().is_terminal() { + command.arg("-q"); + } + if let Ok(dogfood_args) = std::env::var("__CLIPPY_DOGFOOD_ARGS") { for arg in dogfood_args.split_whitespace() { command.arg(arg); @@ -119,11 +138,5 @@ fn run_clippy_for_package(project: &str, args: &[&str]) -> bool { command.args(["-A", "unknown_lints"]); } - let output = command.output().unwrap(); - - println!("status: {}", output.status); - println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); - println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); - - output.status.success() + command.status().unwrap().success() } From 538b31e9774e3c6e0561e8dbcef378deba9f3fdc Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Fri, 28 Jun 2024 09:17:04 +0200 Subject: [PATCH 249/734] Make language around `ToOwned` for `BorrowedFd` more precise --- library/std/src/os/fd/owned.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index a1f83029d272..f11f7ef938a0 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -24,9 +24,11 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// passed as an argument, it is not captured or consumed, and it never has the /// value `-1`. /// -/// This type's `.to_owned()` implementation returns another `BorrowedFd` -/// rather than an `OwnedFd`. It just makes a trivial copy of the raw file -/// descriptor, which is then borrowed under the same lifetime. +/// This type does not have a [`ToOwned`][crate::borrow::ToOwned] +/// implementation. Calling `.to_owned()` on a variable of this type will call +/// it on `&BorrowedFd` and use `Clone::clone()` like `ToOwned` does for all +/// types implementing `Clone`. The result will be descriptor borrowed under +/// the same lifetime. #[derive(Copy, Clone)] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(0)] From 2162f3f34b2b4f9a7d603ab05bec4246a7b855c0 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Fri, 28 Jun 2024 09:17:39 +0200 Subject: [PATCH 250/734] Mention how you can go from `BorrowedFd` to `OwnedFd` and back --- library/std/src/os/fd/owned.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index f11f7ef938a0..5833c5972568 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -29,6 +29,9 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// it on `&BorrowedFd` and use `Clone::clone()` like `ToOwned` does for all /// types implementing `Clone`. The result will be descriptor borrowed under /// the same lifetime. +/// +/// To obtain an [`OwnedFd`], you can use [`BorrowedFd::try_clone_to_owned`] +/// instead, but this is not supported on all platforms. #[derive(Copy, Clone)] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(0)] @@ -52,6 +55,8 @@ pub struct BorrowedFd<'fd> { /// descriptor, so it can be used in FFI in places where a file descriptor is /// passed as a consumed argument or returned as an owned value, and it never /// has the value `-1`. +/// +/// You can use [`AsFd::as_fd`] to obtain a [`BorrowedFd`]. #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(0)] // libstd/os/raw/mod.rs assures me that every libstd-supported platform has a From bf96c56e840971e931e2e11329b8d7b32ac2eab9 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Tue, 4 Jun 2024 21:36:29 +0200 Subject: [PATCH 251/734] Rename `deprecated_safe` lint to `deprecated_safe_2024` Create a lint group `deprecated_safe` that includes `deprecated_safe_2024`. Addresses https://github.com/rust-lang/rust/issues/124866#issuecomment-2142814375. --- compiler/rustc_lint/src/lib.rs | 2 ++ compiler/rustc_lint_defs/src/builtin.rs | 12 ++++++------ compiler/rustc_mir_build/src/check_unsafety.rs | 4 ++-- src/tools/lint-docs/src/groups.rs | 1 + tests/ui/rust-2024/unsafe-env-suggestion.fixed | 2 +- tests/ui/rust-2024/unsafe-env-suggestion.rs | 2 +- tests/ui/rust-2024/unsafe-env-suggestion.stderr | 4 ++-- 7 files changed, 15 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 4e83ef0c6291..7040775e7553 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -322,6 +322,8 @@ fn register_builtins(store: &mut LintStore) { REFINING_IMPL_TRAIT_INTERNAL ); + add_lint_group!("deprecated_safe", DEPRECATED_SAFE_2024); + // Register renamed and removed lints. store.register_renamed("single_use_lifetime", "single_use_lifetimes"); store.register_renamed("elided_lifetime_in_path", "elided_lifetimes_in_paths"); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index aa7844f40121..d8fcbd836d23 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -37,7 +37,7 @@ declare_lint_pass! { DEPRECATED, DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, DEPRECATED_IN_FUTURE, - DEPRECATED_SAFE, + DEPRECATED_SAFE_2024, DEPRECATED_WHERE_CLAUSE_LOCATION, DUPLICATE_MACRO_ATTRIBUTES, ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, @@ -4812,8 +4812,8 @@ declare_lint! { } declare_lint! { - /// The `deprecated_safe` lint detects unsafe functions being used as safe - /// functions. + /// The `deprecated_safe_2024` lint detects unsafe functions being used as + /// safe functions. /// /// ### Example /// @@ -4832,8 +4832,8 @@ declare_lint! { /// /// Rust [editions] allow the language to evolve without breaking backward /// compatibility. This lint catches code that uses `unsafe` functions that - /// were declared as safe (non-`unsafe`) in earlier editions. If you switch - /// the compiler to a new edition without updating the code, then it + /// were declared as safe (non-`unsafe`) in editions prior to Rust 2024. If + /// you switch the compiler to Rust 2024 without updating the code, then it /// will fail to compile if you are using a function previously marked as /// safe. /// @@ -4850,7 +4850,7 @@ declare_lint! { /// future. /// /// [editions]: https://doc.rust-lang.org/edition-guide/ - pub DEPRECATED_SAFE, + pub DEPRECATED_SAFE_2024, Allow, "detects unsafe functions being used as safe functions", @future_incompatible = FutureIncompatibleInfo { diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index a65586ccdb7e..bff4d6af4aa8 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -10,7 +10,7 @@ use rustc_middle::thir::visit::Visitor; use rustc_middle::thir::*; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; -use rustc_session::lint::builtin::{DEPRECATED_SAFE, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; +use rustc_session::lint::builtin::{DEPRECATED_SAFE_2024, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; use rustc_session::lint::Level; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::symbol::Symbol; @@ -99,7 +99,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { { let sm = self.tcx.sess.source_map(); self.tcx.emit_node_span_lint( - DEPRECATED_SAFE, + DEPRECATED_SAFE_2024, self.hir_context, span, CallToDeprecatedSafeFnRequiresUnsafe { diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index 9eaa234bfaf3..0d827ab2e72f 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -24,6 +24,7 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ "keyword-idents", "Lints that detect identifiers which will be come keywords in later editions", ), + ("deprecated-safe", "Lints for functions which were erroneously marked as safe in the past"), ]; type LintGroups = BTreeMap>; diff --git a/tests/ui/rust-2024/unsafe-env-suggestion.fixed b/tests/ui/rust-2024/unsafe-env-suggestion.fixed index 1f3d2dc0a31e..eba35180ef65 100644 --- a/tests/ui/rust-2024/unsafe-env-suggestion.fixed +++ b/tests/ui/rust-2024/unsafe-env-suggestion.fixed @@ -1,6 +1,6 @@ //@ run-rustfix -#![deny(deprecated_safe)] +#![deny(deprecated_safe_2024)] use std::env; diff --git a/tests/ui/rust-2024/unsafe-env-suggestion.rs b/tests/ui/rust-2024/unsafe-env-suggestion.rs index 3bd169973e38..c039d7f25839 100644 --- a/tests/ui/rust-2024/unsafe-env-suggestion.rs +++ b/tests/ui/rust-2024/unsafe-env-suggestion.rs @@ -1,6 +1,6 @@ //@ run-rustfix -#![deny(deprecated_safe)] +#![deny(deprecated_safe_2024)] use std::env; diff --git a/tests/ui/rust-2024/unsafe-env-suggestion.stderr b/tests/ui/rust-2024/unsafe-env-suggestion.stderr index 7c12f4aa5ede..3aa10a3bed68 100644 --- a/tests/ui/rust-2024/unsafe-env-suggestion.stderr +++ b/tests/ui/rust-2024/unsafe-env-suggestion.stderr @@ -9,8 +9,8 @@ LL | env::set_var("FOO", "BAR"); note: the lint level is defined here --> $DIR/unsafe-env-suggestion.rs:3:9 | -LL | #![deny(deprecated_safe)] - | ^^^^^^^^^^^^^^^ +LL | #![deny(deprecated_safe_2024)] + | ^^^^^^^^^^^^^^^^^^^^ help: you can wrap the call in an `unsafe` block if you can guarantee the code is only ever called from single-threaded code | LL + // TODO: Audit that the environment access only happens in single-threaded code. From 427cf94106abb650accd6ef9e2f7252176af9a2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 15 Jul 2024 09:32:41 +0000 Subject: [PATCH 252/734] run_make_support: move `impl_common_helpers` into own `macros` module --- src/tools/run-make-support/src/cc.rs | 2 +- src/tools/run-make-support/src/clang.rs | 2 +- src/tools/run-make-support/src/lib.rs | 116 +--------------------- src/tools/run-make-support/src/llvm.rs | 10 +- src/tools/run-make-support/src/macros.rs | 113 +++++++++++++++++++++ src/tools/run-make-support/src/rustc.rs | 2 +- src/tools/run-make-support/src/rustdoc.rs | 2 +- 7 files changed, 125 insertions(+), 122 deletions(-) create mode 100644 src/tools/run-make-support/src/macros.rs diff --git a/src/tools/run-make-support/src/cc.rs b/src/tools/run-make-support/src/cc.rs index 75a20a21a310..677790b0aa95 100644 --- a/src/tools/run-make-support/src/cc.rs +++ b/src/tools/run-make-support/src/cc.rs @@ -20,7 +20,7 @@ pub struct Cc { cmd: Command, } -crate::impl_common_helpers!(Cc); +crate::macros::impl_common_helpers!(Cc); impl Cc { /// Construct a new platform-specific C compiler invocation. diff --git a/src/tools/run-make-support/src/clang.rs b/src/tools/run-make-support/src/clang.rs index c23e41ebe219..2b0712541cd5 100644 --- a/src/tools/run-make-support/src/clang.rs +++ b/src/tools/run-make-support/src/clang.rs @@ -16,7 +16,7 @@ pub struct Clang { cmd: Command, } -crate::impl_common_helpers!(Clang); +crate::macros::impl_common_helpers!(Clang); impl Clang { /// Construct a new `clang` invocation. `clang` is not always available for all targets. diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index cec2cedd15c9..cf7d235e4b56 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -9,6 +9,7 @@ mod command; pub mod diff; pub mod fs_wrapper; pub mod llvm; +mod macros; pub mod run; pub mod rustc; pub mod rustdoc; @@ -37,6 +38,8 @@ pub use run::{cmd, run, run_fail, run_with_args}; pub use rustc::{aux_build, bare_rustc, rustc, Rustc}; pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; +use command::{Command, CompletedProcess}; + #[track_caller] #[must_use] pub fn env_var(name: &str) -> String { @@ -538,116 +541,3 @@ pub fn run_in_tmpdir(callback: F) { env::set_current_dir(original_dir).unwrap(); fs::remove_dir_all(tmpdir).unwrap(); } - -/// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct -/// containing a `cmd: Command` field. The provided helpers are: -/// -/// 1. Generic argument acceptors: `arg` and `args` (delegated to [`Command`]). These are intended -/// to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add -/// new specific helper methods over relying on these generic argument providers. -/// 2. Environment manipulation methods: `env`, `env_remove` and `env_clear`: these delegate to -/// methods of the same name on [`Command`]. -/// 3. Output and execution: `run` and `run_fail` are provided. These are -/// higher-level convenience methods which wait for the command to finish running and assert -/// that the command successfully ran or failed as expected. They return -/// [`CompletedProcess`], which can be used to assert the stdout/stderr/exit code of the executed -/// process. -/// -/// Example usage: -/// -/// ```ignore (illustrative) -/// struct CommandWrapper { cmd: Command } // <- required `cmd` field -/// -/// crate::impl_common_helpers!(CommandWrapper); -/// -/// impl CommandWrapper { -/// // ... additional specific helper methods -/// } -/// ``` -macro_rules! impl_common_helpers { - ($wrapper: ident) => { - impl $wrapper { - /// Specify an environment variable. - pub fn env(&mut self, key: K, value: V) -> &mut Self - where - K: AsRef<::std::ffi::OsStr>, - V: AsRef<::std::ffi::OsStr>, - { - self.cmd.env(key, value); - self - } - - /// Remove an environmental variable. - pub fn env_remove(&mut self, key: K) -> &mut Self - where - K: AsRef<::std::ffi::OsStr>, - { - self.cmd.env_remove(key); - self - } - - /// Generic command argument provider. Prefer specific helper methods if possible. - /// Note that for some executables, arguments might be platform specific. For C/C++ - /// compilers, arguments might be platform *and* compiler specific. - pub fn arg(&mut self, arg: S) -> &mut Self - where - S: AsRef<::std::ffi::OsStr>, - { - self.cmd.arg(arg); - self - } - - /// Generic command arguments provider. Prefer specific helper methods if possible. - /// Note that for some executables, arguments might be platform specific. For C/C++ - /// compilers, arguments might be platform *and* compiler specific. - pub fn args(&mut self, args: V) -> &mut Self - where - V: AsRef<[S]>, - S: AsRef<::std::ffi::OsStr>, - { - self.cmd.args(args.as_ref()); - self - } - - /// Inspect what the underlying [`Command`] is up to the - /// current construction. - pub fn inspect(&mut self, inspector: I) -> &mut Self - where - I: FnOnce(&::std::process::Command), - { - self.cmd.inspect(inspector); - self - } - - /// Run the constructed command and assert that it is successfully run. - #[track_caller] - pub fn run(&mut self) -> crate::command::CompletedProcess { - self.cmd.run() - } - - /// Run the constructed command and assert that it does not successfully run. - #[track_caller] - pub fn run_fail(&mut self) -> crate::command::CompletedProcess { - self.cmd.run_fail() - } - - /// Run the command but do not check its exit status. - /// Only use if you explicitly don't care about the exit status. - /// Prefer to use [`Self::run`] and [`Self::run_fail`] - /// whenever possible. - #[track_caller] - pub fn run_unchecked(&mut self) -> crate::command::CompletedProcess { - self.cmd.run_unchecked() - } - - /// Set the path where the command will be run. - pub fn current_dir>(&mut self, path: P) -> &mut Self { - self.cmd.current_dir(path); - self - } - } - }; -} - -use crate::command::{Command, CompletedProcess}; -pub(crate) use impl_common_helpers; diff --git a/src/tools/run-make-support/src/llvm.rs b/src/tools/run-make-support/src/llvm.rs index 064dc62a4afa..e7715a905fb7 100644 --- a/src/tools/run-make-support/src/llvm.rs +++ b/src/tools/run-make-support/src/llvm.rs @@ -70,11 +70,11 @@ pub struct LlvmAr { cmd: Command, } -crate::impl_common_helpers!(LlvmReadobj); -crate::impl_common_helpers!(LlvmProfdata); -crate::impl_common_helpers!(LlvmFilecheck); -crate::impl_common_helpers!(LlvmObjdump); -crate::impl_common_helpers!(LlvmAr); +crate::macros::impl_common_helpers!(LlvmReadobj); +crate::macros::impl_common_helpers!(LlvmProfdata); +crate::macros::impl_common_helpers!(LlvmFilecheck); +crate::macros::impl_common_helpers!(LlvmObjdump); +crate::macros::impl_common_helpers!(LlvmAr); /// Generate the path to the bin directory of LLVM. #[must_use] diff --git a/src/tools/run-make-support/src/macros.rs b/src/tools/run-make-support/src/macros.rs new file mode 100644 index 000000000000..f7fe4f542239 --- /dev/null +++ b/src/tools/run-make-support/src/macros.rs @@ -0,0 +1,113 @@ +/// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct +/// containing a `cmd: Command` field. The provided helpers are: +/// +/// 1. Generic argument acceptors: `arg` and `args` (delegated to [`Command`]). These are intended +/// to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add +/// new specific helper methods over relying on these generic argument providers. +/// 2. Environment manipulation methods: `env`, `env_remove` and `env_clear`: these delegate to +/// methods of the same name on [`Command`]. +/// 3. Output and execution: `run` and `run_fail` are provided. These are higher-level convenience +/// methods which wait for the command to finish running and assert that the command successfully +/// ran or failed as expected. They return [`CompletedProcess`], which can be used to assert the +/// stdout/stderr/exit code of the executed process. +/// +/// Example usage: +/// +/// ```ignore (illustrative) +/// struct CommandWrapper { cmd: Command } // <- required `cmd` field +/// +/// crate::macros::impl_common_helpers!(CommandWrapper); +/// +/// impl CommandWrapper { +/// // ... additional specific helper methods +/// } +/// ``` +/// +/// [`Command`]: crate::command::Command +/// [`CompletedProcess`]: crate::command::CompletedProcess +macro_rules! impl_common_helpers { + ($wrapper: ident) => { + impl $wrapper { + /// Specify an environment variable. + pub fn env(&mut self, key: K, value: V) -> &mut Self + where + K: AsRef<::std::ffi::OsStr>, + V: AsRef<::std::ffi::OsStr>, + { + self.cmd.env(key, value); + self + } + + /// Remove an environmental variable. + pub fn env_remove(&mut self, key: K) -> &mut Self + where + K: AsRef<::std::ffi::OsStr>, + { + self.cmd.env_remove(key); + self + } + + /// Generic command argument provider. Prefer specific helper methods if possible. + /// Note that for some executables, arguments might be platform specific. For C/C++ + /// compilers, arguments might be platform *and* compiler specific. + pub fn arg(&mut self, arg: S) -> &mut Self + where + S: AsRef<::std::ffi::OsStr>, + { + self.cmd.arg(arg); + self + } + + /// Generic command arguments provider. Prefer specific helper methods if possible. + /// Note that for some executables, arguments might be platform specific. For C/C++ + /// compilers, arguments might be platform *and* compiler specific. + pub fn args(&mut self, args: V) -> &mut Self + where + V: AsRef<[S]>, + S: AsRef<::std::ffi::OsStr>, + { + self.cmd.args(args.as_ref()); + self + } + + /// Inspect what the underlying [`Command`] is up to the + /// current construction. + pub fn inspect(&mut self, inspector: I) -> &mut Self + where + I: FnOnce(&::std::process::Command), + { + self.cmd.inspect(inspector); + self + } + + /// Run the constructed command and assert that it is successfully run. + #[track_caller] + pub fn run(&mut self) -> crate::command::CompletedProcess { + self.cmd.run() + } + + /// Run the constructed command and assert that it does not successfully run. + #[track_caller] + pub fn run_fail(&mut self) -> crate::command::CompletedProcess { + self.cmd.run_fail() + } + + /// Run the command but do not check its exit status. + /// Only use if you explicitly don't care about the exit status. + /// Prefer to use [`Self::run`] and [`Self::run_fail`] + /// whenever possible. + #[track_caller] + pub fn run_unchecked(&mut self) -> crate::command::CompletedProcess { + self.cmd.run_unchecked() + } + + /// Set the path where the command will be run. + pub fn current_dir>(&mut self, path: P) -> &mut Self { + self.cmd.current_dir(path); + self + } + } + }; +} + +pub(crate) use impl_common_helpers; diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index 6b08608cc62f..8dc6d1238b34 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -31,7 +31,7 @@ pub struct Rustc { cmd: Command, } -crate::impl_common_helpers!(Rustc); +crate::macros::impl_common_helpers!(Rustc); #[track_caller] fn setup_common() -> Command { diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs index 2be962ad8882..547ab0c49c67 100644 --- a/src/tools/run-make-support/src/rustdoc.rs +++ b/src/tools/run-make-support/src/rustdoc.rs @@ -22,7 +22,7 @@ pub struct Rustdoc { cmd: Command, } -crate::impl_common_helpers!(Rustdoc); +crate::macros::impl_common_helpers!(Rustdoc); #[track_caller] fn setup_common() -> Command { From 544dda382892ce6fe228c6dcea756a8e91dd8112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 15 Jul 2024 09:38:01 +0000 Subject: [PATCH 253/734] run_make_support: move target checks into `targets` module --- src/tools/run-make-support/src/lib.rs | 54 ++++++++--------------- src/tools/run-make-support/src/targets.rs | 41 +++++++++++++++++ 2 files changed, 59 insertions(+), 36 deletions(-) create mode 100644 src/tools/run-make-support/src/targets.rs diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index cf7d235e4b56..1dbbad9132b7 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -13,6 +13,7 @@ mod macros; pub mod run; pub mod rustc; pub mod rustdoc; +pub mod targets; use std::env; use std::ffi::OsString; @@ -37,6 +38,7 @@ pub use llvm::{ pub use run::{cmd, run, run_fail, run_with_args}; pub use rustc::{aux_build, bare_rustc, rustc, Rustc}; pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; +pub use targets::{is_darwin, is_msvc, is_windows, target, uname}; use command::{Command, CompletedProcess}; @@ -58,28 +60,17 @@ pub fn env_var_os(name: &str) -> OsString { } } -/// `TARGET` -#[must_use] -pub fn target() -> String { - env_var("TARGET") -} - -/// Check if target is windows-like. -#[must_use] -pub fn is_windows() -> bool { - target().contains("windows") -} - -/// Check if target uses msvc. -#[must_use] -pub fn is_msvc() -> bool { - target().contains("msvc") -} - -/// Check if target uses macOS. -#[must_use] -pub fn is_darwin() -> bool { - target().contains("darwin") +/// `AR` +#[track_caller] +pub fn ar(inputs: &[impl AsRef], output_path: impl AsRef) { + let output = fs::File::create(&output_path).expect(&format!( + "the file in path \"{}\" could not be created", + output_path.as_ref().display() + )); + let mut builder = ar::Builder::new(output); + for input in inputs { + builder.append_path(input).unwrap(); + } } #[track_caller] @@ -348,20 +339,11 @@ pub fn cygpath_windows>(path: P) -> String { output.stdout_utf8().trim().to_string() } -/// Run `uname`. This assumes that `uname` is available on the platform! -#[track_caller] -#[must_use] -pub fn uname() -> String { - let caller = panic::Location::caller(); - let mut uname = Command::new("uname"); - let output = uname.run(); - if !output.status().success() { - handle_failed_output(&uname, output, caller.line()); - } - output.stdout_utf8() -} - -fn handle_failed_output(cmd: &Command, output: CompletedProcess, caller_line_number: u32) -> ! { +pub(crate) fn handle_failed_output( + cmd: &Command, + output: CompletedProcess, + caller_line_number: u32, +) -> ! { if output.status().success() { eprintln!("command unexpectedly succeeded at line {caller_line_number}"); } else { diff --git a/src/tools/run-make-support/src/targets.rs b/src/tools/run-make-support/src/targets.rs new file mode 100644 index 000000000000..68b66e68448c --- /dev/null +++ b/src/tools/run-make-support/src/targets.rs @@ -0,0 +1,41 @@ +use std::panic; + +use crate::command::Command; +use crate::{env_var, handle_failed_output}; + +/// `TARGET` +#[must_use] +pub fn target() -> String { + env_var("TARGET") +} + +/// Check if target is windows-like. +#[must_use] +pub fn is_windows() -> bool { + target().contains("windows") +} + +/// Check if target uses msvc. +#[must_use] +pub fn is_msvc() -> bool { + target().contains("msvc") +} + +/// Check if target uses macOS. +#[must_use] +pub fn is_darwin() -> bool { + target().contains("darwin") +} + +/// Run `uname`. This assumes that `uname` is available on the platform! +#[track_caller] +#[must_use] +pub fn uname() -> String { + let caller = panic::Location::caller(); + let mut uname = Command::new("uname"); + let output = uname.run(); + if !output.status().success() { + handle_failed_output(&uname, output, caller.line()); + } + output.stdout_utf8() +} From a02008edac2b13e27822c916453fdb8356bebd4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 15 Jul 2024 09:45:59 +0000 Subject: [PATCH 254/734] run_make_support: move `env_var{,_os}` into `env_checked` module --- src/tools/run-make-support/src/env_checked.rs | 20 ++++++++++++ src/tools/run-make-support/src/lib.rs | 32 ++++--------------- 2 files changed, 27 insertions(+), 25 deletions(-) create mode 100644 src/tools/run-make-support/src/env_checked.rs diff --git a/src/tools/run-make-support/src/env_checked.rs b/src/tools/run-make-support/src/env_checked.rs new file mode 100644 index 000000000000..adde8b02ac23 --- /dev/null +++ b/src/tools/run-make-support/src/env_checked.rs @@ -0,0 +1,20 @@ +use std::ffi::OsString; +use std::env; + +#[track_caller] +#[must_use] +pub fn env_var(name: &str) -> String { + match env::var(name) { + Ok(v) => v, + Err(err) => panic!("failed to retrieve environment variable {name:?}: {err:?}"), + } +} + +#[track_caller] +#[must_use] +pub fn env_var_os(name: &str) -> OsString { + match env::var_os(name) { + Some(v) => v, + None => panic!("failed to retrieve environment variable {name:?}"), + } +} diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 1dbbad9132b7..6ef1b6b92ad8 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -7,6 +7,7 @@ pub mod cc; pub mod clang; mod command; pub mod diff; +pub mod env_checked; pub mod fs_wrapper; pub mod llvm; mod macros; @@ -15,8 +16,6 @@ pub mod rustc; pub mod rustdoc; pub mod targets; -use std::env; -use std::ffi::OsString; use std::fs; use std::io; use std::panic; @@ -31,6 +30,7 @@ pub use wasmparser; pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc}; pub use clang::{clang, Clang}; pub use diff::{diff, Diff}; +pub use env_checked::{env_var, env_var_os}; pub use llvm::{ llvm_ar, llvm_filecheck, llvm_objdump, llvm_profdata, llvm_readobj, LlvmAr, LlvmFilecheck, LlvmObjdump, LlvmProfdata, LlvmReadobj, @@ -42,24 +42,6 @@ pub use targets::{is_darwin, is_msvc, is_windows, target, uname}; use command::{Command, CompletedProcess}; -#[track_caller] -#[must_use] -pub fn env_var(name: &str) -> String { - match env::var(name) { - Ok(v) => v, - Err(err) => panic!("failed to retrieve environment variable {name:?}: {err:?}"), - } -} - -#[track_caller] -#[must_use] -pub fn env_var_os(name: &str) -> OsString { - match env::var_os(name) { - Some(v) => v, - None => panic!("failed to retrieve environment variable {name:?}"), - } -} - /// `AR` #[track_caller] pub fn ar(inputs: &[impl AsRef], output_path: impl AsRef) { @@ -206,7 +188,7 @@ pub fn bin_name(name: &str) -> String { /// Return the current working directory. #[must_use] pub fn cwd() -> PathBuf { - env::current_dir().unwrap() + std::env::current_dir().unwrap() } // FIXME(Oneirical): This will no longer be required after compiletest receives the ability @@ -363,10 +345,10 @@ pub fn set_host_rpath(cmd: &mut Command) { let mut paths = vec![]; paths.push(cwd()); paths.push(PathBuf::from(env_var("HOST_RPATH_DIR"))); - for p in env::split_paths(&env_var(&ld_lib_path_envvar)) { + for p in std::env::split_paths(&env_var(&ld_lib_path_envvar)) { paths.push(p.to_path_buf()); } - env::join_paths(paths.iter()).unwrap() + std::env::join_paths(paths.iter()).unwrap() }); } @@ -518,8 +500,8 @@ pub fn run_in_tmpdir(callback: F) { let tmpdir = original_dir.join("../temporary-directory"); copy_dir_all(".", &tmpdir); - env::set_current_dir(&tmpdir).unwrap(); + std::env::set_current_dir(&tmpdir).unwrap(); callback(); - env::set_current_dir(original_dir).unwrap(); + std::env::set_current_dir(original_dir).unwrap(); fs::remove_dir_all(tmpdir).unwrap(); } From 288c572745c5cf0ff14e2645b571adb41540afe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 15 Jul 2024 10:00:18 +0000 Subject: [PATCH 255/734] run_make_support: move external deps to `external_deps` module --- src/tools/run-make-support/src/env_checked.rs | 2 +- .../src/{ => external_deps}/cc.rs | 0 .../src/{ => external_deps}/clang.rs | 0 .../src/external_deps/htmldocck.rs | 14 ++++++++ .../src/{ => external_deps}/llvm.rs | 0 .../run-make-support/src/external_deps/mod.rs | 10 ++++++ .../src/external_deps/python.rs | 11 ++++++ .../src/{ => external_deps}/rustc.rs | 0 .../src/{ => external_deps}/rustdoc.rs | 0 src/tools/run-make-support/src/lib.rs | 36 +++++++------------ 10 files changed, 49 insertions(+), 24 deletions(-) rename src/tools/run-make-support/src/{ => external_deps}/cc.rs (100%) rename src/tools/run-make-support/src/{ => external_deps}/clang.rs (100%) create mode 100644 src/tools/run-make-support/src/external_deps/htmldocck.rs rename src/tools/run-make-support/src/{ => external_deps}/llvm.rs (100%) create mode 100644 src/tools/run-make-support/src/external_deps/mod.rs create mode 100644 src/tools/run-make-support/src/external_deps/python.rs rename src/tools/run-make-support/src/{ => external_deps}/rustc.rs (100%) rename src/tools/run-make-support/src/{ => external_deps}/rustdoc.rs (100%) diff --git a/src/tools/run-make-support/src/env_checked.rs b/src/tools/run-make-support/src/env_checked.rs index adde8b02ac23..9f9d2445ef66 100644 --- a/src/tools/run-make-support/src/env_checked.rs +++ b/src/tools/run-make-support/src/env_checked.rs @@ -1,5 +1,5 @@ -use std::ffi::OsString; use std::env; +use std::ffi::OsString; #[track_caller] #[must_use] diff --git a/src/tools/run-make-support/src/cc.rs b/src/tools/run-make-support/src/external_deps/cc.rs similarity index 100% rename from src/tools/run-make-support/src/cc.rs rename to src/tools/run-make-support/src/external_deps/cc.rs diff --git a/src/tools/run-make-support/src/clang.rs b/src/tools/run-make-support/src/external_deps/clang.rs similarity index 100% rename from src/tools/run-make-support/src/clang.rs rename to src/tools/run-make-support/src/external_deps/clang.rs diff --git a/src/tools/run-make-support/src/external_deps/htmldocck.rs b/src/tools/run-make-support/src/external_deps/htmldocck.rs new file mode 100644 index 000000000000..afd0711ee047 --- /dev/null +++ b/src/tools/run-make-support/src/external_deps/htmldocck.rs @@ -0,0 +1,14 @@ +use crate::command::Command; +use crate::source_root; + +use super::python::python_command; + +/// `htmldocck` is a python script which is used for rustdoc test suites, it is assumed to be +/// available at `$SOURCE_ROOT/src/etc/htmldocck.py`. +#[track_caller] +#[must_use] +pub fn htmldocck() -> Command { + let mut python = python_command(); + python.arg(source_root().join("src/etc/htmldocck.py")); + python +} diff --git a/src/tools/run-make-support/src/llvm.rs b/src/tools/run-make-support/src/external_deps/llvm.rs similarity index 100% rename from src/tools/run-make-support/src/llvm.rs rename to src/tools/run-make-support/src/external_deps/llvm.rs diff --git a/src/tools/run-make-support/src/external_deps/mod.rs b/src/tools/run-make-support/src/external_deps/mod.rs new file mode 100644 index 000000000000..f4f03aa7efbd --- /dev/null +++ b/src/tools/run-make-support/src/external_deps/mod.rs @@ -0,0 +1,10 @@ +//! This module contains external tool dependencies that we assume are available in the environment, +//! such as `cc` or `python`. + +pub mod cc; +pub mod clang; +pub mod htmldocck; +pub mod llvm; +pub mod python; +pub mod rustc; +pub mod rustdoc; diff --git a/src/tools/run-make-support/src/external_deps/python.rs b/src/tools/run-make-support/src/external_deps/python.rs new file mode 100644 index 000000000000..59e725fd73e9 --- /dev/null +++ b/src/tools/run-make-support/src/external_deps/python.rs @@ -0,0 +1,11 @@ +use crate::command::Command; +use crate::env_checked::env_var; + +/// Obtain path of python as provided by the `PYTHON` environment variable. It is up to the caller +/// to document and check if the python version is compatible with its intended usage. +#[track_caller] +#[must_use] +pub fn python_command() -> Command { + let python_path = env_var("PYTHON"); + Command::new(python_path) +} diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs similarity index 100% rename from src/tools/run-make-support/src/rustc.rs rename to src/tools/run-make-support/src/external_deps/rustc.rs diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/external_deps/rustdoc.rs similarity index 100% rename from src/tools/run-make-support/src/rustdoc.rs rename to src/tools/run-make-support/src/external_deps/rustdoc.rs diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 6ef1b6b92ad8..57c53a309e21 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -3,17 +3,13 @@ //! notably is built via cargo: this means that if your test wants some non-trivial utility, such //! as `object` or `wasmparser`, they can be re-exported and be made available through this library. -pub mod cc; -pub mod clang; mod command; pub mod diff; pub mod env_checked; +pub mod external_deps; pub mod fs_wrapper; -pub mod llvm; mod macros; pub mod run; -pub mod rustc; -pub mod rustdoc; pub mod targets; use std::fs; @@ -27,17 +23,26 @@ pub use object; pub use regex; pub use wasmparser; +// Re-exports of external dependencies. +pub use external_deps::{cc, clang, htmldocck, llvm, python, rustc, rustdoc}; + pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc}; pub use clang::{clang, Clang}; -pub use diff::{diff, Diff}; -pub use env_checked::{env_var, env_var_os}; +pub use htmldocck::htmldocck; pub use llvm::{ llvm_ar, llvm_filecheck, llvm_objdump, llvm_profdata, llvm_readobj, LlvmAr, LlvmFilecheck, LlvmObjdump, LlvmProfdata, LlvmReadobj, }; -pub use run::{cmd, run, run_fail, run_with_args}; +pub use python::python_command; pub use rustc::{aux_build, bare_rustc, rustc, Rustc}; pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; + +pub use diff::{diff, Diff}; + +pub use env_checked::{env_var, env_var_os}; + +pub use run::{cmd, run, run_fail, run_with_args}; + pub use targets::{is_darwin, is_msvc, is_windows, target, uname}; use command::{Command, CompletedProcess}; @@ -55,21 +60,6 @@ pub fn ar(inputs: &[impl AsRef], output_path: impl AsRef) { } } -#[track_caller] -#[must_use] -pub fn python_command() -> Command { - let python_path = env_var("PYTHON"); - Command::new(python_path) -} - -#[track_caller] -#[must_use] -pub fn htmldocck() -> Command { - let mut python = python_command(); - python.arg(source_root().join("src/etc/htmldocck.py")); - python -} - /// Returns the path for a local test file. pub fn path>(p: P) -> PathBuf { cwd().join(p.as_ref()) From f042e72d1e8eb5e098a139b0ea80a6399cb7174e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 15 Jul 2024 10:19:02 +0000 Subject: [PATCH 256/734] run_make_support: cleanup and document some lib.rs reexports --- src/tools/run-make-support/src/lib.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 57c53a309e21..e7ac23f63104 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -4,11 +4,12 @@ //! as `object` or `wasmparser`, they can be re-exported and be made available through this library. mod command; +mod macros; + pub mod diff; pub mod env_checked; pub mod external_deps; pub mod fs_wrapper; -mod macros; pub mod run; pub mod targets; @@ -17,6 +18,7 @@ use std::io; use std::panic; use std::path::{Path, PathBuf}; +// Re-exports of third-party library crates. pub use bstr; pub use gimli; pub use object; @@ -26,6 +28,7 @@ pub use wasmparser; // Re-exports of external dependencies. pub use external_deps::{cc, clang, htmldocck, llvm, python, rustc, rustdoc}; +// These rely on external dependencies. pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc}; pub use clang::{clang, Clang}; pub use htmldocck::htmldocck; @@ -37,12 +40,18 @@ pub use python::python_command; pub use rustc::{aux_build, bare_rustc, rustc, Rustc}; pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; +/// [`diff`] is implemented in terms of the [similar] library. +/// +/// [similar]: https://github.com/mitsuhiko/similar pub use diff::{diff, Diff}; +/// Panic-on-fail [`std::env::var`] and [`std::env::var_os`] wrappers. pub use env_checked::{env_var, env_var_os}; +/// Convenience helpers for running binaries and other commands. pub use run::{cmd, run, run_fail, run_with_args}; +/// Helpers for checking target information. pub use targets::{is_darwin, is_msvc, is_windows, target, uname}; use command::{Command, CompletedProcess}; From 439c6f60c76e64f50b176a0153f81d83be56b5fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 15 Jul 2024 10:30:21 +0000 Subject: [PATCH 257/734] run_make_support: move `ar` into own module --- src/tools/run-make-support/src/ar.rs | 22 ++++++++++++++++++++++ src/tools/run-make-support/src/lib.rs | 22 ++++++++-------------- 2 files changed, 30 insertions(+), 14 deletions(-) create mode 100644 src/tools/run-make-support/src/ar.rs diff --git a/src/tools/run-make-support/src/ar.rs b/src/tools/run-make-support/src/ar.rs new file mode 100644 index 000000000000..6f46a1dad34c --- /dev/null +++ b/src/tools/run-make-support/src/ar.rs @@ -0,0 +1,22 @@ +use std::fs; +use std::path::Path; + +/// Archive utility. +/// +/// # Notes +/// +/// This *currently* uses the [ar][rust-ar] crate, but this is subject to changes. We may need to +/// use `llvm-ar`, and if that is the case, this should be moved under `external_deps`. +/// +/// [rust-ar]: https://github.com/mdsteele/rust-ar +#[track_caller] +pub fn ar(inputs: &[impl AsRef], output_path: impl AsRef) { + let output = fs::File::create(&output_path).expect(&format!( + "the file in path `{}` could not be created", + output_path.as_ref().display() + )); + let mut builder = ar::Builder::new(output); + for input in inputs { + builder.append_path(input).unwrap(); + } +} diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index e7ac23f63104..cb9d5ff90a78 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -6,6 +6,7 @@ mod command; mod macros; +pub mod ar; pub mod diff; pub mod env_checked; pub mod external_deps; @@ -40,7 +41,13 @@ pub use python::python_command; pub use rustc::{aux_build, bare_rustc, rustc, Rustc}; pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; -/// [`diff`] is implemented in terms of the [similar] library. +/// [`ar`][mod@ar] currently uses the [ar][rust-ar] rust library, but that is subject to changes, we +/// may switch to `llvm-ar` subject to experimentation. +/// +/// [rust-ar]: https://github.com/mdsteele/rust-ar +pub use ar::ar; + +/// [`diff`][mod@diff] is implemented in terms of the [similar] library. /// /// [similar]: https://github.com/mitsuhiko/similar pub use diff::{diff, Diff}; @@ -56,19 +63,6 @@ pub use targets::{is_darwin, is_msvc, is_windows, target, uname}; use command::{Command, CompletedProcess}; -/// `AR` -#[track_caller] -pub fn ar(inputs: &[impl AsRef], output_path: impl AsRef) { - let output = fs::File::create(&output_path).expect(&format!( - "the file in path \"{}\" could not be created", - output_path.as_ref().display() - )); - let mut builder = ar::Builder::new(output); - for input in inputs { - builder.append_path(input).unwrap(); - } -} - /// Returns the path for a local test file. pub fn path>(p: P) -> PathBuf { cwd().join(p.as_ref()) From 483328d40163784f1114d78f0c326403f246e03f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 15 Jul 2024 10:39:00 +0000 Subject: [PATCH 258/734] run_make_support: move artifact name helpers into `artifact_names` module --- .../run-make-support/src/artifact_names.rs | 81 ++++++++++++++++++ src/tools/run-make-support/src/lib.rs | 82 ++----------------- 2 files changed, 87 insertions(+), 76 deletions(-) create mode 100644 src/tools/run-make-support/src/artifact_names.rs diff --git a/src/tools/run-make-support/src/artifact_names.rs b/src/tools/run-make-support/src/artifact_names.rs new file mode 100644 index 000000000000..a2c58f4e4b67 --- /dev/null +++ b/src/tools/run-make-support/src/artifact_names.rs @@ -0,0 +1,81 @@ +//! A collection of helpers to construct artifact names, such as names of dynamic or static +//! librarys which are target-dependent. + +use crate::targets::{is_darwin, is_msvc, is_windows}; + +/// Construct the static library name based on the target. +#[must_use] +pub fn static_lib_name(name: &str) -> String { + // See tools.mk (irrelevant lines omitted): + // + // ```makefile + // ifeq ($(UNAME),Darwin) + // STATICLIB = $(TMPDIR)/lib$(1).a + // else + // ifdef IS_WINDOWS + // ifdef IS_MSVC + // STATICLIB = $(TMPDIR)/$(1).lib + // else + // STATICLIB = $(TMPDIR)/lib$(1).a + // endif + // else + // STATICLIB = $(TMPDIR)/lib$(1).a + // endif + // endif + // ``` + assert!(!name.contains(char::is_whitespace), "static library name cannot contain whitespace"); + + if is_msvc() { format!("{name}.lib") } else { format!("lib{name}.a") } +} + +/// Construct the dynamic library name based on the target. +#[must_use] +pub fn dynamic_lib_name(name: &str) -> String { + // See tools.mk (irrelevant lines omitted): + // + // ```makefile + // ifeq ($(UNAME),Darwin) + // DYLIB = $(TMPDIR)/lib$(1).dylib + // else + // ifdef IS_WINDOWS + // DYLIB = $(TMPDIR)/$(1).dll + // else + // DYLIB = $(TMPDIR)/lib$(1).so + // endif + // endif + // ``` + assert!(!name.contains(char::is_whitespace), "dynamic library name cannot contain whitespace"); + + let extension = dynamic_lib_extension(); + if is_darwin() { + format!("lib{name}.{extension}") + } else if is_windows() { + format!("{name}.{extension}") + } else { + format!("lib{name}.{extension}") + } +} + +/// Construct the dynamic library extension based on the target. +#[must_use] +pub fn dynamic_lib_extension() -> &'static str { + if is_darwin() { + "dylib" + } else if is_windows() { + "dll" + } else { + "so" + } +} + +/// Construct the name of a rust library (rlib). +#[must_use] +pub fn rust_lib_name(name: &str) -> String { + format!("lib{name}.rlib") +} + +/// Construct the binary (executable) name based on the target. +#[must_use] +pub fn bin_name(name: &str) -> String { + if is_windows() { format!("{name}.exe") } else { name.to_string() } +} diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index cb9d5ff90a78..5ca15b885307 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -7,6 +7,7 @@ mod command; mod macros; pub mod ar; +pub mod artifact_names; pub mod diff; pub mod env_checked; pub mod external_deps; @@ -61,6 +62,11 @@ pub use run::{cmd, run, run_fail, run_with_args}; /// Helpers for checking target information. pub use targets::{is_darwin, is_msvc, is_windows, target, uname}; +/// Helpers for building names of output artifacts that are potentially target-specific. +pub use artifact_names::{ + bin_name, dynamic_lib_extension, dynamic_lib_name, rust_lib_name, static_lib_name, +}; + use command::{Command, CompletedProcess}; /// Returns the path for a local test file. @@ -102,82 +108,6 @@ pub fn create_symlink, Q: AsRef>(original: P, link: Q) { )); } -/// Construct the static library name based on the platform. -#[must_use] -pub fn static_lib_name(name: &str) -> String { - // See tools.mk (irrelevant lines omitted): - // - // ```makefile - // ifeq ($(UNAME),Darwin) - // STATICLIB = $(TMPDIR)/lib$(1).a - // else - // ifdef IS_WINDOWS - // ifdef IS_MSVC - // STATICLIB = $(TMPDIR)/$(1).lib - // else - // STATICLIB = $(TMPDIR)/lib$(1).a - // endif - // else - // STATICLIB = $(TMPDIR)/lib$(1).a - // endif - // endif - // ``` - assert!(!name.contains(char::is_whitespace), "static library name cannot contain whitespace"); - - if is_msvc() { format!("{name}.lib") } else { format!("lib{name}.a") } -} - -/// Construct the dynamic library name based on the platform. -#[must_use] -pub fn dynamic_lib_name(name: &str) -> String { - // See tools.mk (irrelevant lines omitted): - // - // ```makefile - // ifeq ($(UNAME),Darwin) - // DYLIB = $(TMPDIR)/lib$(1).dylib - // else - // ifdef IS_WINDOWS - // DYLIB = $(TMPDIR)/$(1).dll - // else - // DYLIB = $(TMPDIR)/lib$(1).so - // endif - // endif - // ``` - assert!(!name.contains(char::is_whitespace), "dynamic library name cannot contain whitespace"); - - let extension = dynamic_lib_extension(); - if is_darwin() { - format!("lib{name}.{extension}") - } else if is_windows() { - format!("{name}.{extension}") - } else { - format!("lib{name}.{extension}") - } -} - -#[must_use] -pub fn dynamic_lib_extension() -> &'static str { - if is_darwin() { - "dylib" - } else if is_windows() { - "dll" - } else { - "so" - } -} - -/// Generate the name a rust library (rlib) would have. -#[must_use] -pub fn rust_lib_name(name: &str) -> String { - format!("lib{name}.rlib") -} - -/// Construct the binary name based on platform. -#[must_use] -pub fn bin_name(name: &str) -> String { - if is_windows() { format!("{name}.exe") } else { name.to_string() } -} - /// Return the current working directory. #[must_use] pub fn cwd() -> PathBuf { From dc9531533c50ade680b98b3ed7e4e1a2f408b474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 15 Jul 2024 10:50:28 +0000 Subject: [PATCH 259/734] run_make_support: move path-related helpers into own module --- .../run-make-support/src/external_deps/mod.rs | 5 ++ src/tools/run-make-support/src/lib.rs | 38 ++--------- .../run-make-support/src/path_helpers.rs | 66 +++++++++++++++++++ 3 files changed, 75 insertions(+), 34 deletions(-) create mode 100644 src/tools/run-make-support/src/path_helpers.rs diff --git a/src/tools/run-make-support/src/external_deps/mod.rs b/src/tools/run-make-support/src/external_deps/mod.rs index f4f03aa7efbd..bcd7dce0f965 100644 --- a/src/tools/run-make-support/src/external_deps/mod.rs +++ b/src/tools/run-make-support/src/external_deps/mod.rs @@ -1,5 +1,10 @@ //! This module contains external tool dependencies that we assume are available in the environment, //! such as `cc` or `python`. +//! +//! # Notes +//! +//! - This is not the *only* place where external dependencies are assumed or referenced. For +//! example, see [`cygpath_windows`][crate::path_helpers::cygpath_windows]. pub mod cc; pub mod clang; diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 5ca15b885307..5ec466af6cef 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -12,6 +12,7 @@ pub mod diff; pub mod env_checked; pub mod external_deps; pub mod fs_wrapper; +pub mod path_helpers; pub mod run; pub mod targets; @@ -67,19 +68,11 @@ pub use artifact_names::{ bin_name, dynamic_lib_extension, dynamic_lib_name, rust_lib_name, static_lib_name, }; +/// Path-related helpers. +pub use path_helpers::{cwd, cygpath_windows, path, source_root}; + use command::{Command, CompletedProcess}; -/// Returns the path for a local test file. -pub fn path>(p: P) -> PathBuf { - cwd().join(p.as_ref()) -} - -/// Path to the root rust-lang/rust source checkout. -#[must_use] -pub fn source_root() -> PathBuf { - env_var("SOURCE_ROOT").into() -} - /// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. #[cfg(target_family = "windows")] pub fn create_symlink, Q: AsRef>(original: P, link: Q) { @@ -108,12 +101,6 @@ pub fn create_symlink, Q: AsRef>(original: P, link: Q) { )); } -/// Return the current working directory. -#[must_use] -pub fn cwd() -> PathBuf { - std::env::current_dir().unwrap() -} - // FIXME(Oneirical): This will no longer be required after compiletest receives the ability // to manipulate read-only files. See https://github.com/rust-lang/rust/issues/126334 /// Ensure that the path P is read-only while the test runs, and restore original permissions @@ -227,23 +214,6 @@ pub fn count_regex_matches_in_files_with_extension(re: ®ex::Regex, ext: &str) count } -/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is -/// available on the platform! -#[track_caller] -#[must_use] -pub fn cygpath_windows>(path: P) -> String { - let caller = panic::Location::caller(); - let mut cygpath = Command::new("cygpath"); - cygpath.arg("-w"); - cygpath.arg(path.as_ref()); - let output = cygpath.run(); - if !output.status().success() { - handle_failed_output(&cygpath, output, caller.line()); - } - // cygpath -w can attach a newline - output.stdout_utf8().trim().to_string() -} - pub(crate) fn handle_failed_output( cmd: &Command, output: CompletedProcess, diff --git a/src/tools/run-make-support/src/path_helpers.rs b/src/tools/run-make-support/src/path_helpers.rs new file mode 100644 index 000000000000..59e0cec0be48 --- /dev/null +++ b/src/tools/run-make-support/src/path_helpers.rs @@ -0,0 +1,66 @@ +//! Collection of path-related helpers. + +use std::panic; +use std::path::{Path, PathBuf}; + +use crate::command::Command; +use crate::env_checked::env_var; +use crate::handle_failed_output; + +/// Return the current working directory. +/// +/// This forwards to [`std::env::current_dir`], please see its docs regarding platform-specific +/// behavior. +#[must_use] +pub fn cwd() -> PathBuf { + std::env::current_dir().unwrap() +} + +/// Construct a `PathBuf` relative to the current working directory by joining `cwd()` with the +/// relative path. This is mostly a convenience helper so the test writer does not need to write +/// `PathBuf::from(path_like_string)`. +/// +/// # Example +/// +/// ```rust +/// let p = path("support_file.txt"); +/// ``` +pub fn path>(p: P) -> PathBuf { + cwd().join(p.as_ref()) +} + +/// Path to the root `rust-lang/rust` source checkout. +#[must_use] +pub fn source_root() -> PathBuf { + env_var("SOURCE_ROOT").into() +} + +/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is +/// available on the platform! +/// +/// # FIXME +/// +/// FIXME(jieyouxu): we should consider not depending on `cygpath`. +/// +/// > The cygpath program is a utility that converts Windows native filenames to Cygwin POSIX-style +/// > pathnames and vice versa. +/// > +/// > [irrelevant entries omitted...] +/// > +/// > `-w, --windows print Windows form of NAMEs (C:\WINNT)` +/// > +/// > -- *from [cygpath documentation](https://cygwin.com/cygwin-ug-net/cygpath.html)*. +#[track_caller] +#[must_use] +pub fn cygpath_windows>(path: P) -> String { + let caller = panic::Location::caller(); + let mut cygpath = Command::new("cygpath"); + cygpath.arg("-w"); + cygpath.arg(path.as_ref()); + let output = cygpath.run(); + if !output.status().success() { + handle_failed_output(&cygpath, output, caller.line()); + } + // cygpath -w can attach a newline + output.stdout_utf8().trim().to_string() +} From 17212abd1a75a83a5e7ccc4aebaf573bf5766c48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 15 Jul 2024 11:30:59 +0000 Subject: [PATCH 260/734] run_make_support: move fs helpers to own module --- src/tools/run-make-support/src/fs_helpers.rs | 71 ++++++++++++++++++++ src/tools/run-make-support/src/lib.rs | 69 ++----------------- 2 files changed, 75 insertions(+), 65 deletions(-) create mode 100644 src/tools/run-make-support/src/fs_helpers.rs diff --git a/src/tools/run-make-support/src/fs_helpers.rs b/src/tools/run-make-support/src/fs_helpers.rs new file mode 100644 index 000000000000..07e0900842ab --- /dev/null +++ b/src/tools/run-make-support/src/fs_helpers.rs @@ -0,0 +1,71 @@ +use std::io; +use std::path::Path; + +use crate::fs_wrapper; + +// FIXME(jieyouxu): modify create_symlink to panic on windows. + +/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. +#[cfg(target_family = "windows")] +pub fn create_symlink, Q: AsRef>(original: P, link: Q) { + if link.as_ref().exists() { + std::fs::remove_dir(link.as_ref()).unwrap(); + } + use std::os::windows::fs; + fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!( + "failed to create symlink {:?} for {:?}", + link.as_ref().display(), + original.as_ref().display(), + )); +} + +/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. +#[cfg(target_family = "unix")] +pub fn create_symlink, Q: AsRef>(original: P, link: Q) { + if link.as_ref().exists() { + std::fs::remove_dir(link.as_ref()).unwrap(); + } + use std::os::unix::fs; + fs::symlink(original.as_ref(), link.as_ref()).expect(&format!( + "failed to create symlink {:?} for {:?}", + link.as_ref().display(), + original.as_ref().display(), + )); +} + +/// Copy a directory into another. +pub fn copy_dir_all(src: impl AsRef, dst: impl AsRef) { + fn copy_dir_all_inner(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { + let dst = dst.as_ref(); + if !dst.is_dir() { + std::fs::create_dir_all(&dst)?; + } + for entry in std::fs::read_dir(src)? { + let entry = entry?; + let ty = entry.file_type()?; + if ty.is_dir() { + copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?; + } else { + std::fs::copy(entry.path(), dst.join(entry.file_name()))?; + } + } + Ok(()) + } + + if let Err(e) = copy_dir_all_inner(&src, &dst) { + // Trying to give more context about what exactly caused the failure + panic!( + "failed to copy `{}` to `{}`: {:?}", + src.as_ref().display(), + dst.as_ref().display(), + e + ); + } +} + +/// Helper for reading entries in a given directory. +pub fn read_dir, F: FnMut(&Path)>(dir: P, mut callback: F) { + for entry in fs_wrapper::read_dir(dir) { + callback(&entry.unwrap().path()); + } +} diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 5ec466af6cef..33248527f0a4 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -11,13 +11,13 @@ pub mod artifact_names; pub mod diff; pub mod env_checked; pub mod external_deps; +pub mod fs_helpers; pub mod fs_wrapper; pub mod path_helpers; pub mod run; pub mod targets; use std::fs; -use std::io; use std::panic; use std::path::{Path, PathBuf}; @@ -71,36 +71,11 @@ pub use artifact_names::{ /// Path-related helpers. pub use path_helpers::{cwd, cygpath_windows, path, source_root}; +/// Helpers for common fs operations. +pub use fs_helpers::{copy_dir_all, create_symlink, read_dir}; + use command::{Command, CompletedProcess}; -/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. -#[cfg(target_family = "windows")] -pub fn create_symlink, Q: AsRef>(original: P, link: Q) { - if link.as_ref().exists() { - std::fs::remove_dir(link.as_ref()).unwrap(); - } - use std::os::windows::fs; - fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!( - "failed to create symlink {:?} for {:?}", - link.as_ref().display(), - original.as_ref().display(), - )); -} - -/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. -#[cfg(target_family = "unix")] -pub fn create_symlink, Q: AsRef>(original: P, link: Q) { - if link.as_ref().exists() { - std::fs::remove_dir(link.as_ref()).unwrap(); - } - use std::os::unix::fs; - fs::symlink(original.as_ref(), link.as_ref()).expect(&format!( - "failed to create symlink {:?} for {:?}", - link.as_ref().display(), - original.as_ref().display(), - )); -} - // FIXME(Oneirical): This will no longer be required after compiletest receives the ability // to manipulate read-only files. See https://github.com/rust-lang/rust/issues/126334 /// Ensure that the path P is read-only while the test runs, and restore original permissions @@ -275,36 +250,6 @@ pub fn invalid_utf8_not_contains, S: AsRef>(path: P, expecte } } -/// Copy a directory into another. -pub fn copy_dir_all(src: impl AsRef, dst: impl AsRef) { - fn copy_dir_all_inner(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { - let dst = dst.as_ref(); - if !dst.is_dir() { - std::fs::create_dir_all(&dst)?; - } - for entry in std::fs::read_dir(src)? { - let entry = entry?; - let ty = entry.file_type()?; - if ty.is_dir() { - copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?; - } else { - std::fs::copy(entry.path(), dst.join(entry.file_name()))?; - } - } - Ok(()) - } - - if let Err(e) = copy_dir_all_inner(&src, &dst) { - // Trying to give more context about what exactly caused the failure - panic!( - "failed to copy `{}` to `{}`: {:?}", - src.as_ref().display(), - dst.as_ref().display(), - e - ); - } -} - /// Check that all files in `dir1` exist and have the same content in `dir2`. Panic otherwise. pub fn recursive_diff(dir1: impl AsRef, dir2: impl AsRef) { let dir2 = dir2.as_ref(); @@ -330,12 +275,6 @@ pub fn recursive_diff(dir1: impl AsRef, dir2: impl AsRef) { }); } -pub fn read_dir(dir: impl AsRef, mut callback: F) { - for entry in fs_wrapper::read_dir(dir) { - callback(&entry.unwrap().path()); - } -} - /// Check that `actual` is equal to `expected`. Panic otherwise. #[track_caller] pub fn assert_equals, S2: AsRef>(actual: S1, expected: S2) { From 66cef19d11553dcc48848200afbdf113021af76c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 15 Jul 2024 11:38:47 +0000 Subject: [PATCH 261/734] run_make_support: move `run_in_tmpdir` and `test_while_readonly` to `scoped_run` module --- src/tools/run-make-support/src/lib.rs | 58 ++-------------- src/tools/run-make-support/src/scoped_run.rs | 71 ++++++++++++++++++++ 2 files changed, 75 insertions(+), 54 deletions(-) create mode 100644 src/tools/run-make-support/src/scoped_run.rs diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 33248527f0a4..0f8fc6af0b3c 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -15,9 +15,9 @@ pub mod fs_helpers; pub mod fs_wrapper; pub mod path_helpers; pub mod run; +pub mod scoped_run; pub mod targets; -use std::fs; use std::panic; use std::path::{Path, PathBuf}; @@ -74,40 +74,11 @@ pub use path_helpers::{cwd, cygpath_windows, path, source_root}; /// Helpers for common fs operations. pub use fs_helpers::{copy_dir_all, create_symlink, read_dir}; +/// Helpers for scoped test execution where certain properties are attempted to be maintained. +pub use scoped_run::{run_in_tmpdir, test_while_readonly}; + use command::{Command, CompletedProcess}; -// FIXME(Oneirical): This will no longer be required after compiletest receives the ability -// to manipulate read-only files. See https://github.com/rust-lang/rust/issues/126334 -/// Ensure that the path P is read-only while the test runs, and restore original permissions -/// at the end so compiletest can clean up. -/// This will panic on Windows if the path is a directory (as it would otherwise do nothing) -#[track_caller] -pub fn test_while_readonly, F: FnOnce() + std::panic::UnwindSafe>( - path: P, - closure: F, -) { - let path = path.as_ref(); - if is_windows() && path.is_dir() { - eprintln!("This helper function cannot be used on Windows to make directories readonly."); - eprintln!( - "See the official documentation: - https://doc.rust-lang.org/std/fs/struct.Permissions.html#method.set_readonly" - ); - panic!("`test_while_readonly` on directory detected while on Windows."); - } - let metadata = fs_wrapper::metadata(&path); - let original_perms = metadata.permissions(); - - let mut new_perms = original_perms.clone(); - new_perms.set_readonly(true); - fs_wrapper::set_permissions(&path, new_perms); - - let success = std::panic::catch_unwind(closure); - - fs_wrapper::set_permissions(&path, original_perms); - success.unwrap(); -} - /// Browse the directory `path` non-recursively and return all files which respect the parameters /// outlined by `closure`. #[track_caller] @@ -316,24 +287,3 @@ pub fn assert_not_contains, S2: AsRef>(haystack: S1, needle: panic!("needle was unexpectedly found in haystack"); } } - -/// This function is designed for running commands in a temporary directory -/// that is cleared after the function ends. -/// -/// What this function does: -/// 1) Creates a temporary directory (`tmpdir`) -/// 2) Copies all files from the current directory to `tmpdir` -/// 3) Changes the current working directory to `tmpdir` -/// 4) Calls `callback` -/// 5) Switches working directory back to the original one -/// 6) Removes `tmpdir` -pub fn run_in_tmpdir(callback: F) { - let original_dir = cwd(); - let tmpdir = original_dir.join("../temporary-directory"); - copy_dir_all(".", &tmpdir); - - std::env::set_current_dir(&tmpdir).unwrap(); - callback(); - std::env::set_current_dir(original_dir).unwrap(); - fs::remove_dir_all(tmpdir).unwrap(); -} diff --git a/src/tools/run-make-support/src/scoped_run.rs b/src/tools/run-make-support/src/scoped_run.rs new file mode 100644 index 000000000000..ab8d2429b6ae --- /dev/null +++ b/src/tools/run-make-support/src/scoped_run.rs @@ -0,0 +1,71 @@ +//! Collection of helpers that try to maintain certain properties while running a test closure. + +use std::fs; +use std::path::Path; + +use crate::fs_helpers::copy_dir_all; +use crate::fs_wrapper; +use crate::path_helpers::cwd; +use crate::targets::is_windows; + +/// Ensure that the path P is read-only while the test runs, and restore original permissions at the +/// end so compiletest can clean up. This will panic on Windows if the path is a directory (as it +/// would otherwise do nothing) +/// +/// # Pitfalls +/// +/// - Some CI runners are ran as root which may bypass read-only permission restrictions. Unclear +/// exactly when such scenarios occur. +/// +/// # FIXME +/// +/// FIXME(Oneirical): This will no longer be required after compiletest receives the ability to +/// manipulate read-only files. See . +#[track_caller] +pub fn test_while_readonly(path: P, closure: F) +where + P: AsRef, + F: FnOnce() + std::panic::UnwindSafe, +{ + let path = path.as_ref(); + if is_windows() && path.is_dir() { + eprintln!("This helper function cannot be used on Windows to make directories readonly."); + eprintln!( + "See the official documentation: + https://doc.rust-lang.org/std/fs/struct.Permissions.html#method.set_readonly" + ); + panic!("`test_while_readonly` on directory detected while on Windows."); + } + let metadata = fs_wrapper::metadata(&path); + let original_perms = metadata.permissions(); + + let mut new_perms = original_perms.clone(); + new_perms.set_readonly(true); + fs_wrapper::set_permissions(&path, new_perms); + + let success = std::panic::catch_unwind(closure); + + fs_wrapper::set_permissions(&path, original_perms); + success.unwrap(); +} + +/// This function is designed for running commands in a temporary directory that is cleared after +/// the function ends. +/// +/// What this function does: +/// 1. Creates a temporary directory (`tmpdir`) +/// 2. Copies all files from the current directory to `tmpdir` +/// 3. Changes the current working directory to `tmpdir` +/// 4. Calls `callback` +/// 5. Switches working directory back to the original one +/// 6. Removes `tmpdir` +pub fn run_in_tmpdir(callback: F) { + let original_dir = cwd(); + let tmpdir = original_dir.join("../temporary-directory"); + copy_dir_all(".", &tmpdir); + + std::env::set_current_dir(&tmpdir).unwrap(); + callback(); + std::env::set_current_dir(original_dir).unwrap(); + fs::remove_dir_all(tmpdir).unwrap(); +} From f66d3d33e4a6481123ed03d9100d1330c1828521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 15 Jul 2024 11:47:53 +0000 Subject: [PATCH 262/734] run_make_support: move assertions and helpers into own module --- .../run-make-support/src/assertion_helpers.rs | 142 ++++++++++++++++++ src/tools/run-make-support/src/lib.rs | 142 +----------------- 2 files changed, 150 insertions(+), 134 deletions(-) create mode 100644 src/tools/run-make-support/src/assertion_helpers.rs diff --git a/src/tools/run-make-support/src/assertion_helpers.rs b/src/tools/run-make-support/src/assertion_helpers.rs new file mode 100644 index 000000000000..96f6296b304c --- /dev/null +++ b/src/tools/run-make-support/src/assertion_helpers.rs @@ -0,0 +1,142 @@ +//! Collection of assertions and assertion-related helpers. + +use std::path::{Path, PathBuf}; +use std::panic; + +use crate::fs_wrapper; +use crate::path_helpers::cwd; + +/// Browse the directory `path` non-recursively and return all files which respect the parameters +/// outlined by `closure`. +#[track_caller] +pub fn shallow_find_files, F: Fn(&PathBuf) -> bool>( + path: P, + filter: F, +) -> Vec { + let mut matching_files = Vec::new(); + for entry in fs_wrapper::read_dir(path) { + let entry = entry.expect("failed to read directory entry."); + let path = entry.path(); + + if path.is_file() && filter(&path) { + matching_files.push(path); + } + } + matching_files +} + +/// Returns true if the filename at `path` starts with `prefix`. +pub fn has_prefix>(path: P, prefix: &str) -> bool { + path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().starts_with(prefix)) +} + +/// Returns true if the filename at `path` has the extension `extension`. +pub fn has_extension>(path: P, extension: &str) -> bool { + path.as_ref().extension().is_some_and(|ext| ext == extension) +} + +/// Returns true if the filename at `path` does not contain `expected`. +pub fn not_contains>(path: P, expected: &str) -> bool { + !path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().contains(expected)) +} + +/// Returns true if the filename at `path` is not in `expected`. +pub fn filename_not_in_denylist, V: AsRef<[String]>>(path: P, expected: V) -> bool { + let expected = expected.as_ref(); + path.as_ref() + .file_name() + .is_some_and(|name| !expected.contains(&name.to_str().unwrap().to_owned())) +} + +/// Returns true if the filename at `path` ends with `suffix`. +pub fn has_suffix>(path: P, suffix: &str) -> bool { + path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().ends_with(suffix)) +} + +/// Gathers all files in the current working directory that have the extension `ext`, and counts +/// the number of lines within that contain a match with the regex pattern `re`. +pub fn count_regex_matches_in_files_with_extension(re: ®ex::Regex, ext: &str) -> usize { + let fetched_files = shallow_find_files(cwd(), |path| has_extension(path, ext)); + + let mut count = 0; + for file in fetched_files { + let content = fs_wrapper::read_to_string(file); + count += content.lines().filter(|line| re.is_match(&line)).count(); + } + + count +} + +/// Read the contents of a file that cannot simply be read by +/// [`read_to_string`][crate::fs_wrapper::read_to_string], due to invalid UTF-8 data, then assert +/// that it contains `expected`. +#[track_caller] +pub fn invalid_utf8_contains, S: AsRef>(path: P, expected: S) { + let buffer = fs_wrapper::read(path.as_ref()); + let expected = expected.as_ref(); + if !String::from_utf8_lossy(&buffer).contains(expected) { + eprintln!("=== FILE CONTENTS (LOSSY) ==="); + eprintln!("{}", String::from_utf8_lossy(&buffer)); + eprintln!("=== SPECIFIED TEXT ==="); + eprintln!("{}", expected); + panic!("specified text was not found in file"); + } +} + +/// Read the contents of a file that cannot simply be read by +/// [`read_to_string`][crate::fs_wrapper::read_to_string], due to invalid UTF-8 data, then assert +/// that it does not contain `expected`. +#[track_caller] +pub fn invalid_utf8_not_contains, S: AsRef>(path: P, expected: S) { + let buffer = fs_wrapper::read(path.as_ref()); + let expected = expected.as_ref(); + if String::from_utf8_lossy(&buffer).contains(expected) { + eprintln!("=== FILE CONTENTS (LOSSY) ==="); + eprintln!("{}", String::from_utf8_lossy(&buffer)); + eprintln!("=== SPECIFIED TEXT ==="); + eprintln!("{}", expected); + panic!("specified text was unexpectedly found in file"); + } +} + +/// Assert that `actual` is equal to `expected`. +#[track_caller] +pub fn assert_equals, E: AsRef>(actual: A, expected: E) { + let actual = actual.as_ref(); + let expected = expected.as_ref(); + if actual != expected { + eprintln!("=== ACTUAL TEXT ==="); + eprintln!("{}", actual); + eprintln!("=== EXPECTED ==="); + eprintln!("{}", expected); + panic!("expected text was not found in actual text"); + } +} + +/// Assert that `haystack` contains `needle`. +#[track_caller] +pub fn assert_contains, N: AsRef>(haystack: H, needle: N) { + let haystack = haystack.as_ref(); + let needle = needle.as_ref(); + if !haystack.contains(needle) { + eprintln!("=== HAYSTACK ==="); + eprintln!("{}", haystack); + eprintln!("=== NEEDLE ==="); + eprintln!("{}", needle); + panic!("needle was not found in haystack"); + } +} + +/// Assert that `haystack` does not contain `needle`. +#[track_caller] +pub fn assert_not_contains, N: AsRef>(haystack: H, needle: N) { + let haystack = haystack.as_ref(); + let needle = needle.as_ref(); + if haystack.contains(needle) { + eprintln!("=== HAYSTACK ==="); + eprintln!("{}", haystack); + eprintln!("=== NEEDLE ==="); + eprintln!("{}", needle); + panic!("needle was unexpectedly found in haystack"); + } +} diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 0f8fc6af0b3c..60b775082891 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -8,6 +8,7 @@ mod macros; pub mod ar; pub mod artifact_names; +pub mod assertion_helpers; pub mod diff; pub mod env_checked; pub mod external_deps; @@ -18,7 +19,6 @@ pub mod run; pub mod scoped_run; pub mod targets; -use std::panic; use std::path::{Path, PathBuf}; // Re-exports of third-party library crates. @@ -77,42 +77,15 @@ pub use fs_helpers::{copy_dir_all, create_symlink, read_dir}; /// Helpers for scoped test execution where certain properties are attempted to be maintained. pub use scoped_run::{run_in_tmpdir, test_while_readonly}; +pub use assertion_helpers::{ + assert_contains, assert_equals, assert_not_contains, + count_regex_matches_in_files_with_extension, filename_not_in_denylist, has_extension, + has_prefix, has_suffix, invalid_utf8_contains, invalid_utf8_not_contains, not_contains, + shallow_find_files, +}; + use command::{Command, CompletedProcess}; -/// Browse the directory `path` non-recursively and return all files which respect the parameters -/// outlined by `closure`. -#[track_caller] -pub fn shallow_find_files, F: Fn(&PathBuf) -> bool>( - path: P, - filter: F, -) -> Vec { - let mut matching_files = Vec::new(); - for entry in fs_wrapper::read_dir(path) { - let entry = entry.expect("failed to read directory entry."); - let path = entry.path(); - - if path.is_file() && filter(&path) { - matching_files.push(path); - } - } - matching_files -} - -/// Returns true if the filename at `path` starts with `prefix`. -pub fn has_prefix>(path: P, prefix: &str) -> bool { - path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().starts_with(prefix)) -} - -/// Returns true if the filename at `path` has the extension `extension`. -pub fn has_extension>(path: P, extension: &str) -> bool { - path.as_ref().extension().is_some_and(|ext| ext == extension) -} - -/// Returns true if the filename at `path` does not contain `expected`. -pub fn not_contains>(path: P, expected: &str) -> bool { - !path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().contains(expected)) -} - /// Builds a static lib (`.lib` on Windows MSVC and `.a` for the rest) with the given name. #[track_caller] pub fn build_native_static_lib(lib_name: &str) -> PathBuf { @@ -133,33 +106,6 @@ pub fn build_native_static_lib(lib_name: &str) -> PathBuf { path(lib_path) } -/// Returns true if the filename at `path` is not in `expected`. -pub fn filename_not_in_denylist, V: AsRef<[String]>>(path: P, expected: V) -> bool { - let expected = expected.as_ref(); - path.as_ref() - .file_name() - .is_some_and(|name| !expected.contains(&name.to_str().unwrap().to_owned())) -} - -/// Returns true if the filename at `path` ends with `suffix`. -pub fn has_suffix>(path: P, suffix: &str) -> bool { - path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().ends_with(suffix)) -} - -/// Gathers all files in the current working directory that have the extension `ext`, and counts -/// the number of lines within that contain a match with the regex pattern `re`. -pub fn count_regex_matches_in_files_with_extension(re: ®ex::Regex, ext: &str) -> usize { - let fetched_files = shallow_find_files(cwd(), |path| has_extension(path, ext)); - - let mut count = 0; - for file in fetched_files { - let content = fs_wrapper::read_to_string(file); - count += content.lines().filter(|line| re.is_match(&line)).count(); - } - - count -} - pub(crate) fn handle_failed_output( cmd: &Command, output: CompletedProcess, @@ -191,36 +137,6 @@ pub fn set_host_rpath(cmd: &mut Command) { }); } -/// Read the contents of a file that cannot simply be read by -/// read_to_string, due to invalid utf8 data, then assert that it contains `expected`. -#[track_caller] -pub fn invalid_utf8_contains, S: AsRef>(path: P, expected: S) { - let buffer = fs_wrapper::read(path.as_ref()); - let expected = expected.as_ref(); - if !String::from_utf8_lossy(&buffer).contains(expected) { - eprintln!("=== FILE CONTENTS (LOSSY) ==="); - eprintln!("{}", String::from_utf8_lossy(&buffer)); - eprintln!("=== SPECIFIED TEXT ==="); - eprintln!("{}", expected); - panic!("specified text was not found in file"); - } -} - -/// Read the contents of a file that cannot simply be read by -/// read_to_string, due to invalid utf8 data, then assert that it does not contain `expected`. -#[track_caller] -pub fn invalid_utf8_not_contains, S: AsRef>(path: P, expected: S) { - let buffer = fs_wrapper::read(path.as_ref()); - let expected = expected.as_ref(); - if String::from_utf8_lossy(&buffer).contains(expected) { - eprintln!("=== FILE CONTENTS (LOSSY) ==="); - eprintln!("{}", String::from_utf8_lossy(&buffer)); - eprintln!("=== SPECIFIED TEXT ==="); - eprintln!("{}", expected); - panic!("specified text was unexpectedly found in file"); - } -} - /// Check that all files in `dir1` exist and have the same content in `dir2`. Panic otherwise. pub fn recursive_diff(dir1: impl AsRef, dir2: impl AsRef) { let dir2 = dir2.as_ref(); @@ -245,45 +161,3 @@ pub fn recursive_diff(dir1: impl AsRef, dir2: impl AsRef) { } }); } - -/// Check that `actual` is equal to `expected`. Panic otherwise. -#[track_caller] -pub fn assert_equals, S2: AsRef>(actual: S1, expected: S2) { - let actual = actual.as_ref(); - let expected = expected.as_ref(); - if actual != expected { - eprintln!("=== ACTUAL TEXT ==="); - eprintln!("{}", actual); - eprintln!("=== EXPECTED ==="); - eprintln!("{}", expected); - panic!("expected text was not found in actual text"); - } -} - -/// Check that `haystack` contains `needle`. Panic otherwise. -#[track_caller] -pub fn assert_contains, S2: AsRef>(haystack: S1, needle: S2) { - let haystack = haystack.as_ref(); - let needle = needle.as_ref(); - if !haystack.contains(needle) { - eprintln!("=== HAYSTACK ==="); - eprintln!("{}", haystack); - eprintln!("=== NEEDLE ==="); - eprintln!("{}", needle); - panic!("needle was not found in haystack"); - } -} - -/// Check that `haystack` does not contain `needle`. Panic otherwise. -#[track_caller] -pub fn assert_not_contains, S2: AsRef>(haystack: S1, needle: S2) { - let haystack = haystack.as_ref(); - let needle = needle.as_ref(); - if haystack.contains(needle) { - eprintln!("=== HAYSTACK ==="); - eprintln!("{}", haystack); - eprintln!("=== NEEDLE ==="); - eprintln!("{}", needle); - panic!("needle was unexpectedly found in haystack"); - } -} From 230804dc3a92c640935f34f16325b0c0e93b9ec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 15 Jul 2024 11:55:57 +0000 Subject: [PATCH 263/734] run_make_support: rename `recursive_diff` to `assert_recursive_eq` --- src/tools/run-make-support/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 60b775082891..1a2a648c47ad 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -137,13 +137,13 @@ pub fn set_host_rpath(cmd: &mut Command) { }); } -/// Check that all files in `dir1` exist and have the same content in `dir2`. Panic otherwise. -pub fn recursive_diff(dir1: impl AsRef, dir2: impl AsRef) { +/// Assert that all files in `dir1` exist and have the same content in `dir2` +pub fn assert_recursive_eq(dir1: impl AsRef, dir2: impl AsRef) { let dir2 = dir2.as_ref(); read_dir(dir1, |entry_path| { let entry_name = entry_path.file_name().unwrap(); if entry_path.is_dir() { - recursive_diff(&entry_path, &dir2.join(entry_name)); + assert_recursive_eq(&entry_path, &dir2.join(entry_name)); } else { let path2 = dir2.join(entry_name); let file1 = fs_wrapper::read(&entry_path); From 56cbfa8749d18fedc0133b2f501b8d5678e89ce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 15 Jul 2024 12:15:36 +0000 Subject: [PATCH 264/734] tests: update rustdoc test for renamed `assert_recursive_eq` --- tests/run-make/rustdoc-verify-output-files/rmake.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-make/rustdoc-verify-output-files/rmake.rs b/tests/run-make/rustdoc-verify-output-files/rmake.rs index 1bf41c68114c..61dd97e09a91 100644 --- a/tests/run-make/rustdoc-verify-output-files/rmake.rs +++ b/tests/run-make/rustdoc-verify-output-files/rmake.rs @@ -1,7 +1,7 @@ use run_make_support::fs_wrapper::copy; use std::path::{Path, PathBuf}; -use run_make_support::{copy_dir_all, recursive_diff, rustdoc}; +use run_make_support::{assert_recursive_eq, copy_dir_all, rustdoc}; #[derive(PartialEq)] enum JsonOutput { @@ -45,5 +45,5 @@ fn main() { // Check if all docs(including both json and html formats) are still the same after multiple // compilations. - recursive_diff(&out_dir, &tmp_out_dir); + assert_recursive_eq(&out_dir, &tmp_out_dir); } From 88fd1df017d7652ffd82ad11cb9f63d8a660f95f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 15 Jul 2024 11:59:06 +0000 Subject: [PATCH 265/734] run_make_support: move `assert_recursive_eq` into `assertion_helpers` --- .../run-make-support/src/assertion_helpers.rs | 28 ++++++++++++++++++- src/tools/run-make-support/src/lib.rs | 27 +----------------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/tools/run-make-support/src/assertion_helpers.rs b/src/tools/run-make-support/src/assertion_helpers.rs index 96f6296b304c..3fdcc94a034f 100644 --- a/src/tools/run-make-support/src/assertion_helpers.rs +++ b/src/tools/run-make-support/src/assertion_helpers.rs @@ -1,8 +1,9 @@ //! Collection of assertions and assertion-related helpers. -use std::path::{Path, PathBuf}; use std::panic; +use std::path::{Path, PathBuf}; +use crate::fs_helpers; use crate::fs_wrapper; use crate::path_helpers::cwd; @@ -140,3 +141,28 @@ pub fn assert_not_contains, N: AsRef>(haystack: H, needle: N) panic!("needle was unexpectedly found in haystack"); } } + +/// Assert that all files in `dir1` exist and have the same content in `dir2` +pub fn assert_recursive_eq(dir1: impl AsRef, dir2: impl AsRef) { + let dir2 = dir2.as_ref(); + fs_helpers::read_dir(dir1, |entry_path| { + let entry_name = entry_path.file_name().unwrap(); + if entry_path.is_dir() { + assert_recursive_eq(&entry_path, &dir2.join(entry_name)); + } else { + let path2 = dir2.join(entry_name); + let file1 = fs_wrapper::read(&entry_path); + let file2 = fs_wrapper::read(&path2); + + // We don't use `assert_eq!` because they are `Vec`, so not great for display. + // Why not using String? Because there might be minified files or even potentially + // binary ones, so that would display useless output. + assert!( + file1 == file2, + "`{}` and `{}` have different content", + entry_path.display(), + path2.display(), + ); + } + }); +} diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 1a2a648c47ad..658b6cc3559b 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -78,7 +78,7 @@ pub use fs_helpers::{copy_dir_all, create_symlink, read_dir}; pub use scoped_run::{run_in_tmpdir, test_while_readonly}; pub use assertion_helpers::{ - assert_contains, assert_equals, assert_not_contains, + assert_contains, assert_equals, assert_not_contains, assert_recursive_eq, count_regex_matches_in_files_with_extension, filename_not_in_denylist, has_extension, has_prefix, has_suffix, invalid_utf8_contains, invalid_utf8_not_contains, not_contains, shallow_find_files, @@ -136,28 +136,3 @@ pub fn set_host_rpath(cmd: &mut Command) { std::env::join_paths(paths.iter()).unwrap() }); } - -/// Assert that all files in `dir1` exist and have the same content in `dir2` -pub fn assert_recursive_eq(dir1: impl AsRef, dir2: impl AsRef) { - let dir2 = dir2.as_ref(); - read_dir(dir1, |entry_path| { - let entry_name = entry_path.file_name().unwrap(); - if entry_path.is_dir() { - assert_recursive_eq(&entry_path, &dir2.join(entry_name)); - } else { - let path2 = dir2.join(entry_name); - let file1 = fs_wrapper::read(&entry_path); - let file2 = fs_wrapper::read(&path2); - - // We don't use `assert_eq!` because they are `Vec`, so not great for display. - // Why not using String? Because there might be minified files or even potentially - // binary ones, so that would display useless output. - assert!( - file1 == file2, - "`{}` and `{}` have different content", - entry_path.display(), - path2.display(), - ); - } - }); -} From e956808c6c5117b85ebc0eb6b3d92f6e512a593c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 15 Jul 2024 12:07:36 +0000 Subject: [PATCH 266/734] run_make_support: move `handle_failed_output` into `util` module --- src/tools/run-make-support/src/command.rs | 4 +++- src/tools/run-make-support/src/lib.rs | 22 +++---------------- .../run-make-support/src/path_helpers.rs | 2 +- src/tools/run-make-support/src/run.rs | 3 +-- src/tools/run-make-support/src/targets.rs | 3 ++- src/tools/run-make-support/src/util.rs | 21 ++++++++++++++++++ 6 files changed, 31 insertions(+), 24 deletions(-) create mode 100644 src/tools/run-make-support/src/util.rs diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index 5017a4b88dad..47376c401bb6 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -5,7 +5,9 @@ use std::panic; use std::path::Path; use std::process::{Command as StdCommand, ExitStatus, Output, Stdio}; -use crate::{assert_contains, assert_equals, assert_not_contains, handle_failed_output}; +use crate::util::handle_failed_output; +use crate::{assert_contains, assert_equals, assert_not_contains}; + use build_helper::drop_bomb::DropBomb; /// This is a custom command wrapper that simplifies working with commands and makes it easier to diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 658b6cc3559b..7c7b890f6ed5 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -5,6 +5,7 @@ mod command; mod macros; +mod util; pub mod ar; pub mod artifact_names; @@ -19,7 +20,7 @@ pub mod run; pub mod scoped_run; pub mod targets; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; // Re-exports of third-party library crates. pub use bstr; @@ -84,7 +85,7 @@ pub use assertion_helpers::{ shallow_find_files, }; -use command::{Command, CompletedProcess}; +use command::Command; /// Builds a static lib (`.lib` on Windows MSVC and `.a` for the rest) with the given name. #[track_caller] @@ -106,23 +107,6 @@ pub fn build_native_static_lib(lib_name: &str) -> PathBuf { path(lib_path) } -pub(crate) fn handle_failed_output( - cmd: &Command, - output: CompletedProcess, - caller_line_number: u32, -) -> ! { - if output.status().success() { - eprintln!("command unexpectedly succeeded at line {caller_line_number}"); - } else { - eprintln!("command failed at line {caller_line_number}"); - } - eprintln!("{cmd:?}"); - eprintln!("output status: `{}`", output.status()); - eprintln!("=== STDOUT ===\n{}\n\n", output.stdout_utf8()); - eprintln!("=== STDERR ===\n{}\n\n", output.stderr_utf8()); - std::process::exit(1) -} - /// Set the runtime library path as needed for running the host rustc/rustdoc/etc. pub fn set_host_rpath(cmd: &mut Command) { let ld_lib_path_envvar = env_var("LD_LIB_PATH_ENVVAR"); diff --git a/src/tools/run-make-support/src/path_helpers.rs b/src/tools/run-make-support/src/path_helpers.rs index 59e0cec0be48..a35c32cbe48b 100644 --- a/src/tools/run-make-support/src/path_helpers.rs +++ b/src/tools/run-make-support/src/path_helpers.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; use crate::command::Command; use crate::env_checked::env_var; -use crate::handle_failed_output; +use crate::util::handle_failed_output; /// Return the current working directory. /// diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs index 54730bb7de73..d47e009fe9f9 100644 --- a/src/tools/run-make-support/src/run.rs +++ b/src/tools/run-make-support/src/run.rs @@ -4,10 +4,9 @@ use std::panic; use std::path::{Path, PathBuf}; use crate::command::{Command, CompletedProcess}; +use crate::util::handle_failed_output; use crate::{cwd, env_var, is_windows, set_host_rpath}; -use super::handle_failed_output; - #[track_caller] fn run_common(name: &str, args: Option<&[&str]>) -> Command { let mut bin_path = PathBuf::new(); diff --git a/src/tools/run-make-support/src/targets.rs b/src/tools/run-make-support/src/targets.rs index 68b66e68448c..42d4a45680d1 100644 --- a/src/tools/run-make-support/src/targets.rs +++ b/src/tools/run-make-support/src/targets.rs @@ -1,7 +1,8 @@ use std::panic; use crate::command::Command; -use crate::{env_var, handle_failed_output}; +use crate::env_var; +use crate::util::handle_failed_output; /// `TARGET` #[must_use] diff --git a/src/tools/run-make-support/src/util.rs b/src/tools/run-make-support/src/util.rs new file mode 100644 index 000000000000..41fdaf55aad5 --- /dev/null +++ b/src/tools/run-make-support/src/util.rs @@ -0,0 +1,21 @@ +use crate::command::{Command, CompletedProcess}; + +/// If a given [`Command`] failed (as indicated by its [`CompletedProcess`]), verbose print the +/// executed command, failure location, output status and stdout/stderr, and abort the process with +/// exit code `1`. +pub(crate) fn handle_failed_output( + cmd: &Command, + output: CompletedProcess, + caller_line_number: u32, +) -> ! { + if output.status().success() { + eprintln!("command unexpectedly succeeded at line {caller_line_number}"); + } else { + eprintln!("command failed at line {caller_line_number}"); + } + eprintln!("{cmd:?}"); + eprintln!("output status: `{}`", output.status()); + eprintln!("=== STDOUT ===\n{}\n\n", output.stdout_utf8()); + eprintln!("=== STDERR ===\n{}\n\n", output.stderr_utf8()); + std::process::exit(1) +} From aadd08576d6b407f76e7ac5a08fa6e3fa633e35e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Mon, 15 Jul 2024 12:14:19 +0000 Subject: [PATCH 267/734] run_make_support: make `set_host_rpath` private and move into `util` --- .../run-make-support/src/external_deps/llvm.rs | 3 ++- .../src/external_deps/rustc.rs | 6 ++++-- .../src/external_deps/rustdoc.rs | 3 ++- src/tools/run-make-support/src/lib.rs | 18 ------------------ src/tools/run-make-support/src/run.rs | 4 ++-- src/tools/run-make-support/src/util.rs | 18 ++++++++++++++++++ 6 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/tools/run-make-support/src/external_deps/llvm.rs b/src/tools/run-make-support/src/external_deps/llvm.rs index e7715a905fb7..9c821dfc03d2 100644 --- a/src/tools/run-make-support/src/external_deps/llvm.rs +++ b/src/tools/run-make-support/src/external_deps/llvm.rs @@ -1,6 +1,7 @@ use std::path::{Path, PathBuf}; -use crate::{env_var, Command}; +use crate::command::Command; +use crate::env_checked::env_var; /// Construct a new `llvm-readobj` invocation with the `GNU` output style. /// This assumes that `llvm-readobj` is available at `$LLVM_BIN_DIR/llvm-readobj`. diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index 8dc6d1238b34..ce04caf6d341 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -1,8 +1,10 @@ -use command::Command; use std::ffi::{OsStr, OsString}; use std::path::Path; -use crate::{command, cwd, env_var, set_host_rpath}; +use crate::command::Command; +use crate::env_checked::env_var; +use crate::path_helpers::cwd; +use crate::util::set_host_rpath; /// Construct a new `rustc` invocation. This will automatically set the library /// search path as `-L cwd()`. Use [`bare_rustc`] to avoid this. diff --git a/src/tools/run-make-support/src/external_deps/rustdoc.rs b/src/tools/run-make-support/src/external_deps/rustdoc.rs index 547ab0c49c67..db324f07c7e9 100644 --- a/src/tools/run-make-support/src/external_deps/rustdoc.rs +++ b/src/tools/run-make-support/src/external_deps/rustdoc.rs @@ -2,7 +2,8 @@ use std::ffi::OsStr; use std::path::Path; use crate::command::Command; -use crate::{env_var, env_var_os, set_host_rpath}; +use crate::env_checked::{env_var, env_var_os}; +use crate::util::set_host_rpath; /// Construct a plain `rustdoc` invocation with no flags set. #[track_caller] diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 7c7b890f6ed5..593655d7fd20 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -20,8 +20,6 @@ pub mod run; pub mod scoped_run; pub mod targets; -use std::path::PathBuf; - // Re-exports of third-party library crates. pub use bstr; pub use gimli; @@ -85,8 +83,6 @@ pub use assertion_helpers::{ shallow_find_files, }; -use command::Command; - /// Builds a static lib (`.lib` on Windows MSVC and `.a` for the rest) with the given name. #[track_caller] pub fn build_native_static_lib(lib_name: &str) -> PathBuf { @@ -106,17 +102,3 @@ pub fn build_native_static_lib(lib_name: &str) -> PathBuf { llvm_ar().obj_to_ar().output_input(&lib_path, &obj_file).run(); path(lib_path) } - -/// Set the runtime library path as needed for running the host rustc/rustdoc/etc. -pub fn set_host_rpath(cmd: &mut Command) { - let ld_lib_path_envvar = env_var("LD_LIB_PATH_ENVVAR"); - cmd.env(&ld_lib_path_envvar, { - let mut paths = vec![]; - paths.push(cwd()); - paths.push(PathBuf::from(env_var("HOST_RPATH_DIR"))); - for p in std::env::split_paths(&env_var(&ld_lib_path_envvar)) { - paths.push(p.to_path_buf()); - } - std::env::join_paths(paths.iter()).unwrap() - }); -} diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs index d47e009fe9f9..17f8ce34f19c 100644 --- a/src/tools/run-make-support/src/run.rs +++ b/src/tools/run-make-support/src/run.rs @@ -4,8 +4,8 @@ use std::panic; use std::path::{Path, PathBuf}; use crate::command::{Command, CompletedProcess}; -use crate::util::handle_failed_output; -use crate::{cwd, env_var, is_windows, set_host_rpath}; +use crate::util::{handle_failed_output, set_host_rpath}; +use crate::{cwd, env_var, is_windows}; #[track_caller] fn run_common(name: &str, args: Option<&[&str]>) -> Command { diff --git a/src/tools/run-make-support/src/util.rs b/src/tools/run-make-support/src/util.rs index 41fdaf55aad5..9ed92ac41567 100644 --- a/src/tools/run-make-support/src/util.rs +++ b/src/tools/run-make-support/src/util.rs @@ -1,4 +1,8 @@ +use std::path::PathBuf; + use crate::command::{Command, CompletedProcess}; +use crate::env_checked::env_var; +use crate::path_helpers::cwd; /// If a given [`Command`] failed (as indicated by its [`CompletedProcess`]), verbose print the /// executed command, failure location, output status and stdout/stderr, and abort the process with @@ -19,3 +23,17 @@ pub(crate) fn handle_failed_output( eprintln!("=== STDERR ===\n{}\n\n", output.stderr_utf8()); std::process::exit(1) } + +/// Set the runtime library path as needed for running the host rustc/rustdoc/etc. +pub(crate) fn set_host_rpath(cmd: &mut Command) { + let ld_lib_path_envvar = env_var("LD_LIB_PATH_ENVVAR"); + cmd.env(&ld_lib_path_envvar, { + let mut paths = vec![]; + paths.push(cwd()); + paths.push(PathBuf::from(env_var("HOST_RPATH_DIR"))); + for p in std::env::split_paths(&env_var(&ld_lib_path_envvar)) { + paths.push(p.to_path_buf()); + } + std::env::join_paths(paths.iter()).unwrap() + }); +} From b7f7205212bed592c14c5292b6ed1c02e0361acc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Wed, 17 Jul 2024 11:12:05 +0000 Subject: [PATCH 268/734] run_make_support: move `build_native_static_lib` under `external_deps` And fix some `ar`-related rebase mishaps. --- src/tools/run-make-support/src/ar.rs | 22 -------------- .../src/external_deps/c_build.rs | 27 +++++++++++++++++ .../run-make-support/src/external_deps/mod.rs | 1 + src/tools/run-make-support/src/lib.rs | 30 ++----------------- 4 files changed, 30 insertions(+), 50 deletions(-) delete mode 100644 src/tools/run-make-support/src/ar.rs create mode 100644 src/tools/run-make-support/src/external_deps/c_build.rs diff --git a/src/tools/run-make-support/src/ar.rs b/src/tools/run-make-support/src/ar.rs deleted file mode 100644 index 6f46a1dad34c..000000000000 --- a/src/tools/run-make-support/src/ar.rs +++ /dev/null @@ -1,22 +0,0 @@ -use std::fs; -use std::path::Path; - -/// Archive utility. -/// -/// # Notes -/// -/// This *currently* uses the [ar][rust-ar] crate, but this is subject to changes. We may need to -/// use `llvm-ar`, and if that is the case, this should be moved under `external_deps`. -/// -/// [rust-ar]: https://github.com/mdsteele/rust-ar -#[track_caller] -pub fn ar(inputs: &[impl AsRef], output_path: impl AsRef) { - let output = fs::File::create(&output_path).expect(&format!( - "the file in path `{}` could not be created", - output_path.as_ref().display() - )); - let mut builder = ar::Builder::new(output); - for input in inputs { - builder.append_path(input).unwrap(); - } -} diff --git a/src/tools/run-make-support/src/external_deps/c_build.rs b/src/tools/run-make-support/src/external_deps/c_build.rs new file mode 100644 index 000000000000..35b2bf75c95f --- /dev/null +++ b/src/tools/run-make-support/src/external_deps/c_build.rs @@ -0,0 +1,27 @@ +use std::path::PathBuf; + +use crate::artifact_names::static_lib_name; +use crate::external_deps::cc::cc; +use crate::external_deps::llvm::llvm_ar; +use crate::path_helpers::path; +use crate::targets::is_msvc; + +/// Builds a static lib (`.lib` on Windows MSVC and `.a` for the rest) with the given name. +#[track_caller] +pub fn build_native_static_lib(lib_name: &str) -> PathBuf { + let obj_file = if is_msvc() { format!("{lib_name}") } else { format!("{lib_name}.o") }; + let src = format!("{lib_name}.c"); + let lib_path = static_lib_name(lib_name); + if is_msvc() { + cc().arg("-c").out_exe(&obj_file).input(src).run(); + } else { + cc().arg("-v").arg("-c").out_exe(&obj_file).input(src).run(); + }; + let obj_file = if is_msvc() { + PathBuf::from(format!("{lib_name}.obj")) + } else { + PathBuf::from(format!("{lib_name}.o")) + }; + llvm_ar().obj_to_ar().output_input(&lib_path, &obj_file).run(); + path(lib_path) +} diff --git a/src/tools/run-make-support/src/external_deps/mod.rs b/src/tools/run-make-support/src/external_deps/mod.rs index bcd7dce0f965..13020b51563b 100644 --- a/src/tools/run-make-support/src/external_deps/mod.rs +++ b/src/tools/run-make-support/src/external_deps/mod.rs @@ -6,6 +6,7 @@ //! - This is not the *only* place where external dependencies are assumed or referenced. For //! example, see [`cygpath_windows`][crate::path_helpers::cygpath_windows]. +pub mod c_build; pub mod cc; pub mod clang; pub mod htmldocck; diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 593655d7fd20..5befea533515 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -7,7 +7,6 @@ mod command; mod macros; mod util; -pub mod ar; pub mod artifact_names; pub mod assertion_helpers; pub mod diff; @@ -28,9 +27,10 @@ pub use regex; pub use wasmparser; // Re-exports of external dependencies. -pub use external_deps::{cc, clang, htmldocck, llvm, python, rustc, rustdoc}; +pub use external_deps::{c_build, cc, clang, htmldocck, llvm, python, rustc, rustdoc}; // These rely on external dependencies. +pub use c_build::build_native_static_lib; pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc}; pub use clang::{clang, Clang}; pub use htmldocck::htmldocck; @@ -42,12 +42,6 @@ pub use python::python_command; pub use rustc::{aux_build, bare_rustc, rustc, Rustc}; pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; -/// [`ar`][mod@ar] currently uses the [ar][rust-ar] rust library, but that is subject to changes, we -/// may switch to `llvm-ar` subject to experimentation. -/// -/// [rust-ar]: https://github.com/mdsteele/rust-ar -pub use ar::ar; - /// [`diff`][mod@diff] is implemented in terms of the [similar] library. /// /// [similar]: https://github.com/mitsuhiko/similar @@ -82,23 +76,3 @@ pub use assertion_helpers::{ has_prefix, has_suffix, invalid_utf8_contains, invalid_utf8_not_contains, not_contains, shallow_find_files, }; - -/// Builds a static lib (`.lib` on Windows MSVC and `.a` for the rest) with the given name. -#[track_caller] -pub fn build_native_static_lib(lib_name: &str) -> PathBuf { - let obj_file = if is_msvc() { format!("{lib_name}") } else { format!("{lib_name}.o") }; - let src = format!("{lib_name}.c"); - let lib_path = static_lib_name(lib_name); - if is_msvc() { - cc().arg("-c").out_exe(&obj_file).input(src).run(); - } else { - cc().arg("-v").arg("-c").out_exe(&obj_file).input(src).run(); - }; - let obj_file = if is_msvc() { - PathBuf::from(format!("{lib_name}.obj")) - } else { - PathBuf::from(format!("{lib_name}.o")) - }; - llvm_ar().obj_to_ar().output_input(&lib_path, &obj_file).run(); - path(lib_path) -} From a443dc4ecdc2e85fbfabdd972028d51616ee20c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Wed, 17 Jul 2024 11:17:28 +0000 Subject: [PATCH 269/734] run_make_support: rename `env_checked` -> `env` --- src/tools/run-make-support/src/{env_checked.rs => env.rs} | 5 ++--- src/tools/run-make-support/src/external_deps/llvm.rs | 2 +- src/tools/run-make-support/src/external_deps/python.rs | 2 +- src/tools/run-make-support/src/external_deps/rustc.rs | 2 +- src/tools/run-make-support/src/external_deps/rustdoc.rs | 2 +- src/tools/run-make-support/src/lib.rs | 4 ++-- src/tools/run-make-support/src/path_helpers.rs | 2 +- src/tools/run-make-support/src/util.rs | 2 +- 8 files changed, 10 insertions(+), 11 deletions(-) rename src/tools/run-make-support/src/{env_checked.rs => env.rs} (84%) diff --git a/src/tools/run-make-support/src/env_checked.rs b/src/tools/run-make-support/src/env.rs similarity index 84% rename from src/tools/run-make-support/src/env_checked.rs rename to src/tools/run-make-support/src/env.rs index 9f9d2445ef66..f52524e7d54c 100644 --- a/src/tools/run-make-support/src/env_checked.rs +++ b/src/tools/run-make-support/src/env.rs @@ -1,10 +1,9 @@ -use std::env; use std::ffi::OsString; #[track_caller] #[must_use] pub fn env_var(name: &str) -> String { - match env::var(name) { + match std::env::var(name) { Ok(v) => v, Err(err) => panic!("failed to retrieve environment variable {name:?}: {err:?}"), } @@ -13,7 +12,7 @@ pub fn env_var(name: &str) -> String { #[track_caller] #[must_use] pub fn env_var_os(name: &str) -> OsString { - match env::var_os(name) { + match std::env::var_os(name) { Some(v) => v, None => panic!("failed to retrieve environment variable {name:?}"), } diff --git a/src/tools/run-make-support/src/external_deps/llvm.rs b/src/tools/run-make-support/src/external_deps/llvm.rs index 9c821dfc03d2..5e8ad7ed3125 100644 --- a/src/tools/run-make-support/src/external_deps/llvm.rs +++ b/src/tools/run-make-support/src/external_deps/llvm.rs @@ -1,7 +1,7 @@ use std::path::{Path, PathBuf}; use crate::command::Command; -use crate::env_checked::env_var; +use crate::env::env_var; /// Construct a new `llvm-readobj` invocation with the `GNU` output style. /// This assumes that `llvm-readobj` is available at `$LLVM_BIN_DIR/llvm-readobj`. diff --git a/src/tools/run-make-support/src/external_deps/python.rs b/src/tools/run-make-support/src/external_deps/python.rs index 59e725fd73e9..fb885069371b 100644 --- a/src/tools/run-make-support/src/external_deps/python.rs +++ b/src/tools/run-make-support/src/external_deps/python.rs @@ -1,5 +1,5 @@ use crate::command::Command; -use crate::env_checked::env_var; +use crate::env::env_var; /// Obtain path of python as provided by the `PYTHON` environment variable. It is up to the caller /// to document and check if the python version is compatible with its intended usage. diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index ce04caf6d341..71d28dd9675f 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -2,7 +2,7 @@ use std::ffi::{OsStr, OsString}; use std::path::Path; use crate::command::Command; -use crate::env_checked::env_var; +use crate::env::env_var; use crate::path_helpers::cwd; use crate::util::set_host_rpath; diff --git a/src/tools/run-make-support/src/external_deps/rustdoc.rs b/src/tools/run-make-support/src/external_deps/rustdoc.rs index db324f07c7e9..96c2218a563e 100644 --- a/src/tools/run-make-support/src/external_deps/rustdoc.rs +++ b/src/tools/run-make-support/src/external_deps/rustdoc.rs @@ -2,7 +2,7 @@ use std::ffi::OsStr; use std::path::Path; use crate::command::Command; -use crate::env_checked::{env_var, env_var_os}; +use crate::env::{env_var, env_var_os}; use crate::util::set_host_rpath; /// Construct a plain `rustdoc` invocation with no flags set. diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 5befea533515..38070f79edc5 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -10,7 +10,7 @@ mod util; pub mod artifact_names; pub mod assertion_helpers; pub mod diff; -pub mod env_checked; +pub mod env; pub mod external_deps; pub mod fs_helpers; pub mod fs_wrapper; @@ -48,7 +48,7 @@ pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; pub use diff::{diff, Diff}; /// Panic-on-fail [`std::env::var`] and [`std::env::var_os`] wrappers. -pub use env_checked::{env_var, env_var_os}; +pub use env::{env_var, env_var_os}; /// Convenience helpers for running binaries and other commands. pub use run::{cmd, run, run_fail, run_with_args}; diff --git a/src/tools/run-make-support/src/path_helpers.rs b/src/tools/run-make-support/src/path_helpers.rs index a35c32cbe48b..f46368b53f8b 100644 --- a/src/tools/run-make-support/src/path_helpers.rs +++ b/src/tools/run-make-support/src/path_helpers.rs @@ -4,7 +4,7 @@ use std::panic; use std::path::{Path, PathBuf}; use crate::command::Command; -use crate::env_checked::env_var; +use crate::env::env_var; use crate::util::handle_failed_output; /// Return the current working directory. diff --git a/src/tools/run-make-support/src/util.rs b/src/tools/run-make-support/src/util.rs index 9ed92ac41567..703e3ad1c6cd 100644 --- a/src/tools/run-make-support/src/util.rs +++ b/src/tools/run-make-support/src/util.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use crate::command::{Command, CompletedProcess}; -use crate::env_checked::env_var; +use crate::env::env_var; use crate::path_helpers::cwd; /// If a given [`Command`] failed (as indicated by its [`CompletedProcess`]), verbose print the From 13a175106141cdac24e241cb558e529c72be943b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Wed, 17 Jul 2024 11:23:29 +0000 Subject: [PATCH 270/734] run_make_support: rename `cygpath_windows` to `get_windows_path` and move under `external_deps` as private --- .../run-make-support/src/external_deps/cc.rs | 9 +++-- .../src/external_deps/cygpath.rs | 35 +++++++++++++++++++ .../run-make-support/src/external_deps/mod.rs | 8 ++--- src/tools/run-make-support/src/lib.rs | 2 +- .../run-make-support/src/path_helpers.rs | 33 ----------------- 5 files changed, 45 insertions(+), 42 deletions(-) create mode 100644 src/tools/run-make-support/src/external_deps/cygpath.rs diff --git a/src/tools/run-make-support/src/external_deps/cc.rs b/src/tools/run-make-support/src/external_deps/cc.rs index 677790b0aa95..840bfa0d2b46 100644 --- a/src/tools/run-make-support/src/external_deps/cc.rs +++ b/src/tools/run-make-support/src/external_deps/cc.rs @@ -1,7 +1,10 @@ use std::path::Path; use crate::command::Command; -use crate::{cygpath_windows, env_var, is_msvc, is_windows, uname}; +use crate::{env_var, is_msvc, is_windows, uname}; + +// FIXME(jieyouxu): can we get rid of the `cygpath` external dependency? +use super::cygpath::get_windows_path; /// Construct a new platform-specific C compiler invocation. /// @@ -72,10 +75,10 @@ impl Cc { if is_msvc() { path.set_extension("exe"); - let fe_path = cygpath_windows(&path); + let fe_path = get_windows_path(&path); path.set_extension(""); path.set_extension("obj"); - let fo_path = cygpath_windows(path); + let fo_path = get_windows_path(path); self.cmd.arg(format!("-Fe:{fe_path}")); self.cmd.arg(format!("-Fo:{fo_path}")); } else { diff --git a/src/tools/run-make-support/src/external_deps/cygpath.rs b/src/tools/run-make-support/src/external_deps/cygpath.rs new file mode 100644 index 000000000000..07d8e840a63a --- /dev/null +++ b/src/tools/run-make-support/src/external_deps/cygpath.rs @@ -0,0 +1,35 @@ +use std::panic; +use std::path::Path; + +use crate::command::Command; +use crate::util::handle_failed_output; + +/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is +/// available on the platform! +/// +/// # FIXME +/// +/// FIXME(jieyouxu): we should consider not depending on `cygpath`. +/// +/// > The cygpath program is a utility that converts Windows native filenames to Cygwin POSIX-style +/// > pathnames and vice versa. +/// > +/// > [irrelevant entries omitted...] +/// > +/// > `-w, --windows print Windows form of NAMEs (C:\WINNT)` +/// > +/// > -- *from [cygpath documentation](https://cygwin.com/cygwin-ug-net/cygpath.html)*. +#[track_caller] +#[must_use] +pub fn get_windows_path>(path: P) -> String { + let caller = panic::Location::caller(); + let mut cygpath = Command::new("cygpath"); + cygpath.arg("-w"); + cygpath.arg(path.as_ref()); + let output = cygpath.run(); + if !output.status().success() { + handle_failed_output(&cygpath, output, caller.line()); + } + // cygpath -w can attach a newline + output.stdout_utf8().trim().to_string() +} diff --git a/src/tools/run-make-support/src/external_deps/mod.rs b/src/tools/run-make-support/src/external_deps/mod.rs index 13020b51563b..a2dc426f3f22 100644 --- a/src/tools/run-make-support/src/external_deps/mod.rs +++ b/src/tools/run-make-support/src/external_deps/mod.rs @@ -1,10 +1,5 @@ //! This module contains external tool dependencies that we assume are available in the environment, //! such as `cc` or `python`. -//! -//! # Notes -//! -//! - This is not the *only* place where external dependencies are assumed or referenced. For -//! example, see [`cygpath_windows`][crate::path_helpers::cygpath_windows]. pub mod c_build; pub mod cc; @@ -14,3 +9,6 @@ pub mod llvm; pub mod python; pub mod rustc; pub mod rustdoc; + +// Library-internal external dependency. +mod cygpath; diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 38070f79edc5..5416a6920a57 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -62,7 +62,7 @@ pub use artifact_names::{ }; /// Path-related helpers. -pub use path_helpers::{cwd, cygpath_windows, path, source_root}; +pub use path_helpers::{cwd, path, source_root}; /// Helpers for common fs operations. pub use fs_helpers::{copy_dir_all, create_symlink, read_dir}; diff --git a/src/tools/run-make-support/src/path_helpers.rs b/src/tools/run-make-support/src/path_helpers.rs index f46368b53f8b..b29d8727d2b3 100644 --- a/src/tools/run-make-support/src/path_helpers.rs +++ b/src/tools/run-make-support/src/path_helpers.rs @@ -1,11 +1,8 @@ //! Collection of path-related helpers. -use std::panic; use std::path::{Path, PathBuf}; -use crate::command::Command; use crate::env::env_var; -use crate::util::handle_failed_output; /// Return the current working directory. /// @@ -34,33 +31,3 @@ pub fn path>(p: P) -> PathBuf { pub fn source_root() -> PathBuf { env_var("SOURCE_ROOT").into() } - -/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is -/// available on the platform! -/// -/// # FIXME -/// -/// FIXME(jieyouxu): we should consider not depending on `cygpath`. -/// -/// > The cygpath program is a utility that converts Windows native filenames to Cygwin POSIX-style -/// > pathnames and vice versa. -/// > -/// > [irrelevant entries omitted...] -/// > -/// > `-w, --windows print Windows form of NAMEs (C:\WINNT)` -/// > -/// > -- *from [cygpath documentation](https://cygwin.com/cygwin-ug-net/cygpath.html)*. -#[track_caller] -#[must_use] -pub fn cygpath_windows>(path: P) -> String { - let caller = panic::Location::caller(); - let mut cygpath = Command::new("cygpath"); - cygpath.arg("-w"); - cygpath.arg(path.as_ref()); - let output = cygpath.run(); - if !output.status().success() { - handle_failed_output(&cygpath, output, caller.line()); - } - // cygpath -w can attach a newline - output.stdout_utf8().trim().to_string() -} From e1569fde3efee2955e0a32beefc108c6874c9fd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Wed, 17 Jul 2024 12:39:17 +0000 Subject: [PATCH 271/734] run_make_support: coalesce fs helpers into single `fs` module There were *two* `read_dir` helpers, one being a simple `std::fs::read_dir` wrapper, the other has a different callback-based signature. We also rename the callback-based `read_dir` as `read_dir_entries`. Also don't top-level re-export most `fs::*` helpers. --- .../run-make-support/src/assertion_helpers.rs | 21 ++-- src/tools/run-make-support/src/diff/mod.rs | 10 +- .../src/{fs_wrapper.rs => fs.rs} | 99 +++++++++++++++---- src/tools/run-make-support/src/fs_helpers.rs | 71 ------------- src/tools/run-make-support/src/lib.rs | 6 +- src/tools/run-make-support/src/scoped_run.rs | 14 ++- 6 files changed, 104 insertions(+), 117 deletions(-) rename src/tools/run-make-support/src/{fs_wrapper.rs => fs.rs} (52%) delete mode 100644 src/tools/run-make-support/src/fs_helpers.rs diff --git a/src/tools/run-make-support/src/assertion_helpers.rs b/src/tools/run-make-support/src/assertion_helpers.rs index 3fdcc94a034f..b57ac475e087 100644 --- a/src/tools/run-make-support/src/assertion_helpers.rs +++ b/src/tools/run-make-support/src/assertion_helpers.rs @@ -3,8 +3,7 @@ use std::panic; use std::path::{Path, PathBuf}; -use crate::fs_helpers; -use crate::fs_wrapper; +use crate::fs as rfs; use crate::path_helpers::cwd; /// Browse the directory `path` non-recursively and return all files which respect the parameters @@ -15,7 +14,7 @@ pub fn shallow_find_files, F: Fn(&PathBuf) -> bool>( filter: F, ) -> Vec { let mut matching_files = Vec::new(); - for entry in fs_wrapper::read_dir(path) { + for entry in rfs::read_dir(path) { let entry = entry.expect("failed to read directory entry."); let path = entry.path(); @@ -61,7 +60,7 @@ pub fn count_regex_matches_in_files_with_extension(re: ®ex::Regex, ext: &str) let mut count = 0; for file in fetched_files { - let content = fs_wrapper::read_to_string(file); + let content = rfs::read_to_string(file); count += content.lines().filter(|line| re.is_match(&line)).count(); } @@ -69,11 +68,11 @@ pub fn count_regex_matches_in_files_with_extension(re: ®ex::Regex, ext: &str) } /// Read the contents of a file that cannot simply be read by -/// [`read_to_string`][crate::fs_wrapper::read_to_string], due to invalid UTF-8 data, then assert +/// [`read_to_string`][crate::fs::read_to_string], due to invalid UTF-8 data, then assert /// that it contains `expected`. #[track_caller] pub fn invalid_utf8_contains, S: AsRef>(path: P, expected: S) { - let buffer = fs_wrapper::read(path.as_ref()); + let buffer = rfs::read(path.as_ref()); let expected = expected.as_ref(); if !String::from_utf8_lossy(&buffer).contains(expected) { eprintln!("=== FILE CONTENTS (LOSSY) ==="); @@ -85,11 +84,11 @@ pub fn invalid_utf8_contains, S: AsRef>(path: P, expected: S } /// Read the contents of a file that cannot simply be read by -/// [`read_to_string`][crate::fs_wrapper::read_to_string], due to invalid UTF-8 data, then assert +/// [`read_to_string`][crate::fs::read_to_string], due to invalid UTF-8 data, then assert /// that it does not contain `expected`. #[track_caller] pub fn invalid_utf8_not_contains, S: AsRef>(path: P, expected: S) { - let buffer = fs_wrapper::read(path.as_ref()); + let buffer = rfs::read(path.as_ref()); let expected = expected.as_ref(); if String::from_utf8_lossy(&buffer).contains(expected) { eprintln!("=== FILE CONTENTS (LOSSY) ==="); @@ -145,14 +144,14 @@ pub fn assert_not_contains, N: AsRef>(haystack: H, needle: N) /// Assert that all files in `dir1` exist and have the same content in `dir2` pub fn assert_recursive_eq(dir1: impl AsRef, dir2: impl AsRef) { let dir2 = dir2.as_ref(); - fs_helpers::read_dir(dir1, |entry_path| { + rfs::read_dir_entries(dir1, |entry_path| { let entry_name = entry_path.file_name().unwrap(); if entry_path.is_dir() { assert_recursive_eq(&entry_path, &dir2.join(entry_name)); } else { let path2 = dir2.join(entry_name); - let file1 = fs_wrapper::read(&entry_path); - let file2 = fs_wrapper::read(&path2); + let file1 = rfs::read(&entry_path); + let file2 = rfs::read(&path2); // We don't use `assert_eq!` because they are `Vec`, so not great for display. // Why not using String? Because there might be minified files or even potentially diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs index ad989b74e4d9..9f3548891192 100644 --- a/src/tools/run-make-support/src/diff/mod.rs +++ b/src/tools/run-make-support/src/diff/mod.rs @@ -2,7 +2,7 @@ use regex::Regex; use similar::TextDiff; use std::path::{Path, PathBuf}; -use crate::fs_wrapper; +use crate::fs as rfs; use build_helper::drop_bomb::DropBomb; #[cfg(test)] @@ -43,7 +43,7 @@ impl Diff { /// Specify the expected output for the diff from a file. pub fn expected_file>(&mut self, path: P) -> &mut Self { let path = path.as_ref(); - let content = fs_wrapper::read_to_string(path); + let content = rfs::read_to_string(path); let name = path.to_string_lossy().to_string(); self.expected_file = Some(path.into()); @@ -62,7 +62,7 @@ impl Diff { /// Specify the actual output for the diff from a file. pub fn actual_file>(&mut self, path: P) -> &mut Self { let path = path.as_ref(); - let content = fs_wrapper::read_to_string(path); + let content = rfs::read_to_string(path); let name = path.to_string_lossy().to_string(); self.actual = Some(content); @@ -116,7 +116,7 @@ impl Diff { if let Some(ref expected_file) = self.expected_file { if std::env::var("RUSTC_BLESS_TEST").is_ok() { println!("Blessing `{}`", expected_file.display()); - fs_wrapper::write(expected_file, actual); + rfs::write(expected_file, actual); return; } } @@ -138,7 +138,7 @@ impl Diff { if let Some(ref expected_file) = self.expected_file { if std::env::var("RUSTC_BLESS_TEST").is_ok() { println!("Blessing `{}`", expected_file.display()); - fs_wrapper::write(expected_file, actual); + rfs::write(expected_file, actual); return; } } diff --git a/src/tools/run-make-support/src/fs_wrapper.rs b/src/tools/run-make-support/src/fs.rs similarity index 52% rename from src/tools/run-make-support/src/fs_wrapper.rs rename to src/tools/run-make-support/src/fs.rs index 0f0d6f6618ce..f346e983aea8 100644 --- a/src/tools/run-make-support/src/fs_wrapper.rs +++ b/src/tools/run-make-support/src/fs.rs @@ -1,17 +1,82 @@ -use std::fs; +use std::io; use std::path::Path; +// FIXME(jieyouxu): modify create_symlink to panic on windows. + +/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. +#[cfg(target_family = "windows")] +pub fn create_symlink, Q: AsRef>(original: P, link: Q) { + if link.as_ref().exists() { + std::fs::remove_dir(link.as_ref()).unwrap(); + } + std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!( + "failed to create symlink {:?} for {:?}", + link.as_ref().display(), + original.as_ref().display(), + )); +} + +/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. +#[cfg(target_family = "unix")] +pub fn create_symlink, Q: AsRef>(original: P, link: Q) { + if link.as_ref().exists() { + std::fs::remove_dir(link.as_ref()).unwrap(); + } + std::os::unix::fs::symlink(original.as_ref(), link.as_ref()).expect(&format!( + "failed to create symlink {:?} for {:?}", + link.as_ref().display(), + original.as_ref().display(), + )); +} + +/// Copy a directory into another. +pub fn copy_dir_all(src: impl AsRef, dst: impl AsRef) { + fn copy_dir_all_inner(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { + let dst = dst.as_ref(); + if !dst.is_dir() { + std::fs::create_dir_all(&dst)?; + } + for entry in std::fs::read_dir(src)? { + let entry = entry?; + let ty = entry.file_type()?; + if ty.is_dir() { + copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?; + } else { + std::fs::copy(entry.path(), dst.join(entry.file_name()))?; + } + } + Ok(()) + } + + if let Err(e) = copy_dir_all_inner(&src, &dst) { + // Trying to give more context about what exactly caused the failure + panic!( + "failed to copy `{}` to `{}`: {:?}", + src.as_ref().display(), + dst.as_ref().display(), + e + ); + } +} + +/// Helper for reading entries in a given directory. +pub fn read_dir_entries, F: FnMut(&Path)>(dir: P, mut callback: F) { + for entry in read_dir(dir) { + callback(&entry.unwrap().path()); + } +} + /// A wrapper around [`std::fs::remove_file`] which includes the file path in the panic message. #[track_caller] pub fn remove_file>(path: P) { - fs::remove_file(path.as_ref()) + std::fs::remove_file(path.as_ref()) .expect(&format!("the file in path \"{}\" could not be removed", path.as_ref().display())); } /// A wrapper around [`std::fs::copy`] which includes the file path in the panic message. #[track_caller] pub fn copy, Q: AsRef>(from: P, to: Q) { - fs::copy(from.as_ref(), to.as_ref()).expect(&format!( + std::fs::copy(from.as_ref(), to.as_ref()).expect(&format!( "the file \"{}\" could not be copied over to \"{}\"", from.as_ref().display(), to.as_ref().display(), @@ -21,21 +86,21 @@ pub fn copy, Q: AsRef>(from: P, to: Q) { /// A wrapper around [`std::fs::File::create`] which includes the file path in the panic message. #[track_caller] pub fn create_file>(path: P) { - fs::File::create(path.as_ref()) + std::fs::File::create(path.as_ref()) .expect(&format!("the file in path \"{}\" could not be created", path.as_ref().display())); } /// A wrapper around [`std::fs::read`] which includes the file path in the panic message. #[track_caller] pub fn read>(path: P) -> Vec { - fs::read(path.as_ref()) + std::fs::read(path.as_ref()) .expect(&format!("the file in path \"{}\" could not be read", path.as_ref().display())) } /// A wrapper around [`std::fs::read_to_string`] which includes the file path in the panic message. #[track_caller] pub fn read_to_string>(path: P) -> String { - fs::read_to_string(path.as_ref()).expect(&format!( + std::fs::read_to_string(path.as_ref()).expect(&format!( "the file in path \"{}\" could not be read into a String", path.as_ref().display() )) @@ -43,15 +108,15 @@ pub fn read_to_string>(path: P) -> String { /// A wrapper around [`std::fs::read_dir`] which includes the file path in the panic message. #[track_caller] -pub fn read_dir>(path: P) -> fs::ReadDir { - fs::read_dir(path.as_ref()) +pub fn read_dir>(path: P) -> std::fs::ReadDir { + std::fs::read_dir(path.as_ref()) .expect(&format!("the directory in path \"{}\" could not be read", path.as_ref().display())) } /// A wrapper around [`std::fs::write`] which includes the file path in the panic message. #[track_caller] pub fn write, C: AsRef<[u8]>>(path: P, contents: C) { - fs::write(path.as_ref(), contents.as_ref()).expect(&format!( + std::fs::write(path.as_ref(), contents.as_ref()).expect(&format!( "the file in path \"{}\" could not be written to", path.as_ref().display() )); @@ -60,7 +125,7 @@ pub fn write, C: AsRef<[u8]>>(path: P, contents: C) { /// A wrapper around [`std::fs::remove_dir_all`] which includes the file path in the panic message. #[track_caller] pub fn remove_dir_all>(path: P) { - fs::remove_dir_all(path.as_ref()).expect(&format!( + std::fs::remove_dir_all(path.as_ref()).expect(&format!( "the directory in path \"{}\" could not be removed alongside all its contents", path.as_ref().display(), )); @@ -69,7 +134,7 @@ pub fn remove_dir_all>(path: P) { /// A wrapper around [`std::fs::create_dir`] which includes the file path in the panic message. #[track_caller] pub fn create_dir>(path: P) { - fs::create_dir(path.as_ref()).expect(&format!( + std::fs::create_dir(path.as_ref()).expect(&format!( "the directory in path \"{}\" could not be created", path.as_ref().display() )); @@ -78,7 +143,7 @@ pub fn create_dir>(path: P) { /// A wrapper around [`std::fs::create_dir_all`] which includes the file path in the panic message. #[track_caller] pub fn create_dir_all>(path: P) { - fs::create_dir_all(path.as_ref()).expect(&format!( + std::fs::create_dir_all(path.as_ref()).expect(&format!( "the directory (and all its parents) in path \"{}\" could not be created", path.as_ref().display() )); @@ -86,8 +151,8 @@ pub fn create_dir_all>(path: P) { /// A wrapper around [`std::fs::metadata`] which includes the file path in the panic message. #[track_caller] -pub fn metadata>(path: P) -> fs::Metadata { - fs::metadata(path.as_ref()).expect(&format!( +pub fn metadata>(path: P) -> std::fs::Metadata { + std::fs::metadata(path.as_ref()).expect(&format!( "the file's metadata in path \"{}\" could not be read", path.as_ref().display() )) @@ -96,7 +161,7 @@ pub fn metadata>(path: P) -> fs::Metadata { /// A wrapper around [`std::fs::rename`] which includes the file path in the panic message. #[track_caller] pub fn rename, Q: AsRef>(from: P, to: Q) { - fs::rename(from.as_ref(), to.as_ref()).expect(&format!( + std::fs::rename(from.as_ref(), to.as_ref()).expect(&format!( "the file \"{}\" could not be moved over to \"{}\"", from.as_ref().display(), to.as_ref().display(), @@ -105,8 +170,8 @@ pub fn rename, Q: AsRef>(from: P, to: Q) { /// A wrapper around [`std::fs::set_permissions`] which includes the file path in the panic message. #[track_caller] -pub fn set_permissions>(path: P, perm: fs::Permissions) { - fs::set_permissions(path.as_ref(), perm).expect(&format!( +pub fn set_permissions>(path: P, perm: std::fs::Permissions) { + std::fs::set_permissions(path.as_ref(), perm).expect(&format!( "the file's permissions in path \"{}\" could not be changed", path.as_ref().display() )); diff --git a/src/tools/run-make-support/src/fs_helpers.rs b/src/tools/run-make-support/src/fs_helpers.rs deleted file mode 100644 index 07e0900842ab..000000000000 --- a/src/tools/run-make-support/src/fs_helpers.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::io; -use std::path::Path; - -use crate::fs_wrapper; - -// FIXME(jieyouxu): modify create_symlink to panic on windows. - -/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. -#[cfg(target_family = "windows")] -pub fn create_symlink, Q: AsRef>(original: P, link: Q) { - if link.as_ref().exists() { - std::fs::remove_dir(link.as_ref()).unwrap(); - } - use std::os::windows::fs; - fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!( - "failed to create symlink {:?} for {:?}", - link.as_ref().display(), - original.as_ref().display(), - )); -} - -/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. -#[cfg(target_family = "unix")] -pub fn create_symlink, Q: AsRef>(original: P, link: Q) { - if link.as_ref().exists() { - std::fs::remove_dir(link.as_ref()).unwrap(); - } - use std::os::unix::fs; - fs::symlink(original.as_ref(), link.as_ref()).expect(&format!( - "failed to create symlink {:?} for {:?}", - link.as_ref().display(), - original.as_ref().display(), - )); -} - -/// Copy a directory into another. -pub fn copy_dir_all(src: impl AsRef, dst: impl AsRef) { - fn copy_dir_all_inner(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { - let dst = dst.as_ref(); - if !dst.is_dir() { - std::fs::create_dir_all(&dst)?; - } - for entry in std::fs::read_dir(src)? { - let entry = entry?; - let ty = entry.file_type()?; - if ty.is_dir() { - copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?; - } else { - std::fs::copy(entry.path(), dst.join(entry.file_name()))?; - } - } - Ok(()) - } - - if let Err(e) = copy_dir_all_inner(&src, &dst) { - // Trying to give more context about what exactly caused the failure - panic!( - "failed to copy `{}` to `{}`: {:?}", - src.as_ref().display(), - dst.as_ref().display(), - e - ); - } -} - -/// Helper for reading entries in a given directory. -pub fn read_dir, F: FnMut(&Path)>(dir: P, mut callback: F) { - for entry in fs_wrapper::read_dir(dir) { - callback(&entry.unwrap().path()); - } -} diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 5416a6920a57..ae34ecd8d972 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -12,8 +12,7 @@ pub mod assertion_helpers; pub mod diff; pub mod env; pub mod external_deps; -pub mod fs_helpers; -pub mod fs_wrapper; +pub mod fs; pub mod path_helpers; pub mod run; pub mod scoped_run; @@ -64,9 +63,6 @@ pub use artifact_names::{ /// Path-related helpers. pub use path_helpers::{cwd, path, source_root}; -/// Helpers for common fs operations. -pub use fs_helpers::{copy_dir_all, create_symlink, read_dir}; - /// Helpers for scoped test execution where certain properties are attempted to be maintained. pub use scoped_run::{run_in_tmpdir, test_while_readonly}; diff --git a/src/tools/run-make-support/src/scoped_run.rs b/src/tools/run-make-support/src/scoped_run.rs index ab8d2429b6ae..63837e98904a 100644 --- a/src/tools/run-make-support/src/scoped_run.rs +++ b/src/tools/run-make-support/src/scoped_run.rs @@ -1,10 +1,8 @@ //! Collection of helpers that try to maintain certain properties while running a test closure. -use std::fs; use std::path::Path; -use crate::fs_helpers::copy_dir_all; -use crate::fs_wrapper; +use crate::fs as rfs; use crate::path_helpers::cwd; use crate::targets::is_windows; @@ -36,16 +34,16 @@ where ); panic!("`test_while_readonly` on directory detected while on Windows."); } - let metadata = fs_wrapper::metadata(&path); + let metadata = rfs::metadata(&path); let original_perms = metadata.permissions(); let mut new_perms = original_perms.clone(); new_perms.set_readonly(true); - fs_wrapper::set_permissions(&path, new_perms); + rfs::set_permissions(&path, new_perms); let success = std::panic::catch_unwind(closure); - fs_wrapper::set_permissions(&path, original_perms); + rfs::set_permissions(&path, original_perms); success.unwrap(); } @@ -62,10 +60,10 @@ where pub fn run_in_tmpdir(callback: F) { let original_dir = cwd(); let tmpdir = original_dir.join("../temporary-directory"); - copy_dir_all(".", &tmpdir); + rfs::copy_dir_all(".", &tmpdir); std::env::set_current_dir(&tmpdir).unwrap(); callback(); std::env::set_current_dir(original_dir).unwrap(); - fs::remove_dir_all(tmpdir).unwrap(); + rfs::remove_dir_all(tmpdir); } From 636be91cc0d8e406171ec4aa1b5dea4b77d1a714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Wed, 17 Jul 2024 12:42:06 +0000 Subject: [PATCH 272/734] tests: update for renamed `fs` module in run_make_support --- tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs | 4 ++-- tests/run-make/c-link-to-rust-dylib/rmake.rs | 8 +++---- .../c-link-to-rust-staticlib/rmake.rs | 2 +- tests/run-make/cdylib/rmake.rs | 4 ++-- tests/run-make/comment-section/rmake.rs | 5 +++-- tests/run-make/compiler-builtins/rmake.rs | 2 +- tests/run-make/compiler-lookup-paths/rmake.rs | 14 ++++++------ tests/run-make/const-prop-lint/rmake.rs | 4 ++-- tests/run-make/crate-name-priority/rmake.rs | 10 ++++----- .../run-make/doctests-keep-binaries/rmake.rs | 2 +- tests/run-make/doctests-runtool/rmake.rs | 2 +- tests/run-make/dump-mono-stats/rmake.rs | 4 ++-- tests/run-make/dylib-chain/rmake.rs | 8 +++---- tests/run-make/emit-named-files/rmake.rs | 4 ++-- tests/run-make/emit-path-unhashed/rmake.rs | 10 ++++----- tests/run-make/extern-flag-pathless/rmake.rs | 18 +++++++-------- .../extra-filename-with-temp-outputs/rmake.rs | 6 ++--- .../run-make/ice-dep-cannot-find-dep/rmake.rs | 2 +- tests/run-make/inaccessible-temp-dir/rmake.rs | 4 ++-- .../incr-prev-body-beyond-eof/rmake.rs | 10 ++++----- tests/run-make/incr-test-moved-file/rmake.rs | 12 +++++----- .../incremental-debugger-visualizer/rmake.rs | 22 +++++++++---------- .../incremental-session-fail/rmake.rs | 4 ++-- .../run-make/inline-always-many-cgu/rmake.rs | 8 +++---- tests/run-make/intrinsic-unreachable/rmake.rs | 6 ++--- tests/run-make/invalid-library/rmake.rs | 4 ++-- tests/run-make/invalid-so/rmake.rs | 4 ++-- tests/run-make/invalid-staticlib/rmake.rs | 4 ++-- .../issue-107495-archive-permissions/rmake.rs | 4 ++-- tests/run-make/ls-metadata/rmake.rs | 4 ++-- tests/run-make/lto-readonly-lib/rmake.rs | 2 +- .../many-crates-but-no-match/rmake.rs | 8 +++---- tests/run-make/mixing-libs/rmake.rs | 4 ++-- .../moved-src-dir-fingerprint-ice/rmake.rs | 14 ++++++------ tests/run-make/non-unicode-env/rmake.rs | 4 ++-- .../non-unicode-in-incremental-dir/rmake.rs | 6 ++--- tests/run-make/obey-crate-type-flag/rmake.rs | 4 ++-- .../rmake.rs | 4 ++-- .../output-filename-overwrites-input/rmake.rs | 6 ++--- .../output-type-permutations/rmake.rs | 13 +++++------ .../parallel-rustc-no-overwrite/rmake.rs | 4 ++-- tests/run-make/pgo-branch-weights/rmake.rs | 9 +++----- tests/run-make/pgo-use/rmake.rs | 6 ++--- tests/run-make/prefer-dylib/rmake.rs | 4 ++-- tests/run-make/prefer-rlib/rmake.rs | 6 ++--- .../pretty-print-with-dep-file/rmake.rs | 4 ++-- tests/run-make/print-cfg/rmake.rs | 4 ++-- tests/run-make/print-to-output/rmake.rs | 4 ++-- tests/run-make/remap-path-prefix/rmake.rs | 16 +++++--------- tests/run-make/repr128-dwarf/rmake.rs | 4 ++-- tests/run-make/reset-codegen-1/rmake.rs | 2 +- tests/run-make/resolve-rename/rmake.rs | 4 ++-- tests/run-make/rlib-chain/rmake.rs | 8 +++---- .../rustdoc-scrape-examples-remap/scrape.rs | 4 ++-- tests/run-make/rustdoc-test-args/rmake.rs | 4 ++-- tests/run-make/rustdoc-themes/rmake.rs | 11 +++++----- .../rustdoc-verify-output-files/rmake.rs | 8 +++---- tests/run-make/sepcomp-cci-copies/rmake.rs | 2 +- tests/run-make/sepcomp-inlining/rmake.rs | 2 +- tests/run-make/sepcomp-separate/rmake.rs | 2 +- tests/run-make/silly-file-names/rmake.rs | 10 ++++----- tests/run-make/symlinked-extern/rmake.rs | 6 ++--- tests/run-make/symlinked-libraries/rmake.rs | 6 ++--- tests/run-make/symlinked-rlib/rmake.rs | 4 ++-- tests/run-make/target-specs/rmake.rs | 8 +++---- tests/run-make/track-path-dep-info/rmake.rs | 4 ++-- tests/run-make/track-pgo-dep-info/rmake.rs | 4 ++-- tests/run-make/volatile-intrinsics/rmake.rs | 4 ++-- tests/run-make/wasm-custom-section/rmake.rs | 4 ++-- .../wasm-custom-sections-opt/rmake.rs | 4 ++-- .../run-make/wasm-export-all-symbols/rmake.rs | 4 ++-- tests/run-make/wasm-import-module/rmake.rs | 4 ++-- tests/run-make/wasm-panic-small/rmake.rs | 4 ++-- tests/run-make/wasm-spurious-import/rmake.rs | 4 ++-- .../wasm-stringify-ints-small/rmake.rs | 4 ++-- .../wasm-symbols-different-module/rmake.rs | 4 ++-- .../wasm-symbols-not-exported/rmake.rs | 4 ++-- .../wasm-symbols-not-imported/rmake.rs | 4 ++-- .../run-make/weird-output-filenames/rmake.rs | 6 ++--- tests/run-make/windows-ws2_32/rmake.rs | 4 ++-- 80 files changed, 225 insertions(+), 239 deletions(-) diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs index d937514c2ca2..5dd05f151df4 100644 --- a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs +++ b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs @@ -5,14 +5,14 @@ use std::path::PathBuf; -use run_make_support::{aux_build, fs_wrapper, rustc, source_root}; +use run_make_support::{aux_build, fs as rfs, rustc, source_root}; fn main() { aux_build().input("stable.rs").emit("metadata").run(); let output = rustc().input("main.rs").emit("metadata").extern_("stable", "libstable.rmeta").run(); - let version = fs_wrapper::read_to_string(source_root().join("src/version")); + let version = rfs::read_to_string(source_root().join("src/version")); let expected_string = format!("stable since {}", version.trim()); output.assert_stderr_contains(expected_string); } diff --git a/tests/run-make/c-link-to-rust-dylib/rmake.rs b/tests/run-make/c-link-to-rust-dylib/rmake.rs index b8ea0b6b345b..e4441ac0c3be 100644 --- a/tests/run-make/c-link-to-rust-dylib/rmake.rs +++ b/tests/run-make/c-link-to-rust-dylib/rmake.rs @@ -3,9 +3,7 @@ //@ ignore-cross-compile -use run_make_support::{ - cc, cwd, dynamic_lib_extension, fs_wrapper, is_msvc, read_dir, run, run_fail, rustc, -}; +use run_make_support::{cc, cwd, dynamic_lib_extension, fs as rfs, is_msvc, run, run_fail, rustc}; fn main() { rustc().input("foo.rs").run(); @@ -21,14 +19,14 @@ fn main() { run("bar"); let expected_extension = dynamic_lib_extension(); - read_dir(cwd(), |path| { + rfs::read_dir_entries(cwd(), |path| { if path.is_file() && path.extension().is_some_and(|ext| ext == expected_extension) && path.file_name().and_then(|name| name.to_str()).is_some_and(|name| { name.ends_with(".so") || name.ends_with(".dll") || name.ends_with(".dylib") }) { - fs_wrapper::remove_file(path); + rfs::remove_file(path); } }); run_fail("bar"); diff --git a/tests/run-make/c-link-to-rust-staticlib/rmake.rs b/tests/run-make/c-link-to-rust-staticlib/rmake.rs index d60b37524f43..8c845f8b6f2d 100644 --- a/tests/run-make/c-link-to-rust-staticlib/rmake.rs +++ b/tests/run-make/c-link-to-rust-staticlib/rmake.rs @@ -3,7 +3,7 @@ //@ ignore-cross-compile -use run_make_support::fs_wrapper::remove_file; +use run_make_support::fs::remove_file; use run_make_support::{cc, extra_c_flags, run, rustc, static_lib_name}; use std::fs; diff --git a/tests/run-make/cdylib/rmake.rs b/tests/run-make/cdylib/rmake.rs index 55ea227ab519..b6f2a9be0b22 100644 --- a/tests/run-make/cdylib/rmake.rs +++ b/tests/run-make/cdylib/rmake.rs @@ -10,7 +10,7 @@ //@ ignore-cross-compile -use run_make_support::{cc, cwd, dynamic_lib_name, fs_wrapper, is_msvc, run, rustc}; +use run_make_support::{cc, cwd, dynamic_lib_name, fs as rfs, is_msvc, run, rustc}; fn main() { rustc().input("bar.rs").run(); @@ -23,7 +23,7 @@ fn main() { } run("foo"); - fs_wrapper::remove_file(dynamic_lib_name("foo")); + rfs::remove_file(dynamic_lib_name("foo")); rustc().input("foo.rs").arg("-Clto").run(); run("foo"); diff --git a/tests/run-make/comment-section/rmake.rs b/tests/run-make/comment-section/rmake.rs index 188c6dcb25d2..f6978ab259dd 100644 --- a/tests/run-make/comment-section/rmake.rs +++ b/tests/run-make/comment-section/rmake.rs @@ -9,9 +9,10 @@ use std::path::PathBuf; +use run_make_support::fs as rfs; use run_make_support::llvm_readobj; use run_make_support::rustc; -use run_make_support::{cwd, env_var, read_dir, run_in_tmpdir}; +use run_make_support::{cwd, env_var, run_in_tmpdir}; fn main() { let target = env_var("TARGET"); @@ -33,7 +34,7 @@ fn main() { // Check all object files (including temporary outputs) have a `.comment` // section with the expected content. - read_dir(cwd(), |f| { + rfs::read_dir_entries(cwd(), |f| { if !f.extension().is_some_and(|ext| ext == "o") { return; } diff --git a/tests/run-make/compiler-builtins/rmake.rs b/tests/run-make/compiler-builtins/rmake.rs index 10ff9cd282d8..b9dacdd0b905 100644 --- a/tests/run-make/compiler-builtins/rmake.rs +++ b/tests/run-make/compiler-builtins/rmake.rs @@ -14,7 +14,7 @@ #![deny(warnings)] -use run_make_support::fs_wrapper::{read, read_dir}; +use run_make_support::fs::{read, read_dir}; use run_make_support::object::read::archive::ArchiveFile; use run_make_support::object::read::Object; use run_make_support::object::ObjectSection; diff --git a/tests/run-make/compiler-lookup-paths/rmake.rs b/tests/run-make/compiler-lookup-paths/rmake.rs index 0f7918528213..cfb7ef90ce43 100644 --- a/tests/run-make/compiler-lookup-paths/rmake.rs +++ b/tests/run-make/compiler-lookup-paths/rmake.rs @@ -9,16 +9,16 @@ //@ ignore-wasm64 // Reason: a C compiler is required for build_native_static_lib -use run_make_support::{build_native_static_lib, fs_wrapper, rustc, static_lib_name}; +use run_make_support::{build_native_static_lib, fs as rfs, rustc, static_lib_name}; fn main() { build_native_static_lib("native"); let lib_native = static_lib_name("native"); - fs_wrapper::create_dir_all("crate"); - fs_wrapper::create_dir_all("native"); - fs_wrapper::rename(&lib_native, format!("native/{}", &lib_native)); + rfs::create_dir_all("crate"); + rfs::create_dir_all("native"); + rfs::rename(&lib_native, format!("native/{}", &lib_native)); rustc().input("a.rs").run(); - fs_wrapper::rename("liba.rlib", "crate/liba.rlib"); + rfs::rename("liba.rlib", "crate/liba.rlib"); rustc().input("b.rs").specific_library_search_path("native", "crate").run_fail(); rustc().input("b.rs").specific_library_search_path("dependency", "crate").run_fail(); rustc().input("b.rs").specific_library_search_path("crate", "crate").run(); @@ -35,8 +35,8 @@ fn main() { rustc().input("d.rs").specific_library_search_path("all", "native").run(); // Deduplication tests. - fs_wrapper::create_dir_all("e1"); - fs_wrapper::create_dir_all("e2"); + rfs::create_dir_all("e1"); + rfs::create_dir_all("e2"); rustc().input("e.rs").output("e1/libe.rlib").run(); rustc().input("e.rs").output("e2/libe.rlib").run(); diff --git a/tests/run-make/const-prop-lint/rmake.rs b/tests/run-make/const-prop-lint/rmake.rs index d194f70d9169..25d9ccad4177 100644 --- a/tests/run-make/const-prop-lint/rmake.rs +++ b/tests/run-make/const-prop-lint/rmake.rs @@ -1,11 +1,11 @@ // Tests that const prop lints interrupting codegen don't leave `.o` files around. -use run_make_support::{cwd, fs_wrapper, rustc}; +use run_make_support::{cwd, fs as rfs, rustc}; fn main() { rustc().input("input.rs").run_fail().assert_exit_code(1); - for entry in fs_wrapper::read_dir(cwd()) { + for entry in rfs::read_dir(cwd()) { let entry = entry.unwrap(); let path = entry.path(); diff --git a/tests/run-make/crate-name-priority/rmake.rs b/tests/run-make/crate-name-priority/rmake.rs index b7cb2c997114..c0cc8bdfdbfa 100644 --- a/tests/run-make/crate-name-priority/rmake.rs +++ b/tests/run-make/crate-name-priority/rmake.rs @@ -4,15 +4,15 @@ // and the compiler flags, and checks that the flag is favoured each time. // See https://github.com/rust-lang/rust/pull/15518 -use run_make_support::{bin_name, fs_wrapper, rustc}; +use run_make_support::{bin_name, fs as rfs, rustc}; fn main() { rustc().input("foo.rs").run(); - fs_wrapper::remove_file(bin_name("foo")); + rfs::remove_file(bin_name("foo")); rustc().input("foo.rs").crate_name("bar").run(); - fs_wrapper::remove_file(bin_name("bar")); + rfs::remove_file(bin_name("bar")); rustc().input("foo1.rs").run(); - fs_wrapper::remove_file(bin_name("foo")); + rfs::remove_file(bin_name("foo")); rustc().input("foo1.rs").output(bin_name("bar1")).run(); - fs_wrapper::remove_file(bin_name("bar1")); + rfs::remove_file(bin_name("bar1")); } diff --git a/tests/run-make/doctests-keep-binaries/rmake.rs b/tests/run-make/doctests-keep-binaries/rmake.rs index e48c8a0cef35..35b29f21a5ab 100644 --- a/tests/run-make/doctests-keep-binaries/rmake.rs +++ b/tests/run-make/doctests-keep-binaries/rmake.rs @@ -1,7 +1,7 @@ // Check that valid binaries are persisted by running them, regardless of whether the // --run or --no-run option is used. -use run_make_support::fs_wrapper::{create_dir, remove_dir_all}; +use run_make_support::fs::{create_dir, remove_dir_all}; use run_make_support::{run, rustc, rustdoc}; use std::path::Path; diff --git a/tests/run-make/doctests-runtool/rmake.rs b/tests/run-make/doctests-runtool/rmake.rs index 5208730d336d..979c3ea7d2c1 100644 --- a/tests/run-make/doctests-runtool/rmake.rs +++ b/tests/run-make/doctests-runtool/rmake.rs @@ -1,6 +1,6 @@ // Tests behavior of rustdoc `--runtool`. -use run_make_support::fs_wrapper::{create_dir, remove_dir_all}; +use run_make_support::fs::{create_dir, remove_dir_all}; use run_make_support::{rustc, rustdoc}; use std::path::PathBuf; diff --git a/tests/run-make/dump-mono-stats/rmake.rs b/tests/run-make/dump-mono-stats/rmake.rs index 05ba2e6b8ff2..05a5b559e6dd 100644 --- a/tests/run-make/dump-mono-stats/rmake.rs +++ b/tests/run-make/dump-mono-stats/rmake.rs @@ -4,7 +4,7 @@ // a specific expected string. // See https://github.com/rust-lang/rust/pull/105481 -use run_make_support::{cwd, fs_wrapper, rustc}; +use run_make_support::{cwd, fs as rfs, rustc}; fn main() { rustc() @@ -13,5 +13,5 @@ fn main() { .arg(format!("-Zdump-mono-stats={}", cwd().display())) .arg("-Zdump-mono-stats-format=json") .run(); - assert!(fs_wrapper::read_to_string("foo.mono_items.json").contains(r#""name":"bar""#)); + assert!(rfs::read_to_string("foo.mono_items.json").contains(r#""name":"bar""#)); } diff --git a/tests/run-make/dylib-chain/rmake.rs b/tests/run-make/dylib-chain/rmake.rs index a96cc3508750..63ae2f01ce40 100644 --- a/tests/run-make/dylib-chain/rmake.rs +++ b/tests/run-make/dylib-chain/rmake.rs @@ -8,7 +8,7 @@ //@ ignore-cross-compile // Reason: the compiled binary is executed -use run_make_support::{dynamic_lib_name, fs_wrapper, run, run_fail, rustc}; +use run_make_support::{dynamic_lib_name, fs as rfs, run, run_fail, rustc}; fn main() { rustc().input("m1.rs").arg("-Cprefer-dynamic").run(); @@ -16,8 +16,8 @@ fn main() { rustc().input("m3.rs").arg("-Cprefer-dynamic").run(); rustc().input("m4.rs").run(); run("m4"); - fs_wrapper::remove_file(dynamic_lib_name("m1")); - fs_wrapper::remove_file(dynamic_lib_name("m2")); - fs_wrapper::remove_file(dynamic_lib_name("m3")); + rfs::remove_file(dynamic_lib_name("m1")); + rfs::remove_file(dynamic_lib_name("m2")); + rfs::remove_file(dynamic_lib_name("m3")); run_fail("m4"); } diff --git a/tests/run-make/emit-named-files/rmake.rs b/tests/run-make/emit-named-files/rmake.rs index a02c97fec4cb..0cf743fc7d43 100644 --- a/tests/run-make/emit-named-files/rmake.rs +++ b/tests/run-make/emit-named-files/rmake.rs @@ -1,6 +1,6 @@ use std::path::Path; -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{fs as rfs, rustc}; fn emit_and_check(out_dir: &Path, out_file: &str, format: &str) { let out_file = out_dir.join(out_file); @@ -11,7 +11,7 @@ fn emit_and_check(out_dir: &Path, out_file: &str, format: &str) { fn main() { let out_dir = Path::new("emit"); - fs_wrapper::create_dir(&out_dir); + rfs::create_dir(&out_dir); emit_and_check(&out_dir, "libfoo.s", "asm"); emit_and_check(&out_dir, "libfoo.bc", "llvm-bc"); diff --git a/tests/run-make/emit-path-unhashed/rmake.rs b/tests/run-make/emit-path-unhashed/rmake.rs index ce56c1975886..0d0ad1b91670 100644 --- a/tests/run-make/emit-path-unhashed/rmake.rs +++ b/tests/run-make/emit-path-unhashed/rmake.rs @@ -6,13 +6,13 @@ // adding a new output type (in this test, metadata). // See https://github.com/rust-lang/rust/issues/86044 -use run_make_support::{diff, fs_wrapper, rustc}; +use run_make_support::{diff, fs as rfs, rustc}; fn main() { - fs_wrapper::create_dir("emit"); - fs_wrapper::create_dir("emit/a"); - fs_wrapper::create_dir("emit/b"); - fs_wrapper::create_dir("emit/c"); + rfs::create_dir("emit"); + rfs::create_dir("emit/a"); + rfs::create_dir("emit/b"); + rfs::create_dir("emit/c"); // The default output name. rustc().emit("link").input("foo.rs").run(); // The output is named with the output flag. diff --git a/tests/run-make/extern-flag-pathless/rmake.rs b/tests/run-make/extern-flag-pathless/rmake.rs index 9cf828abcb8b..bdc8b3e2c999 100644 --- a/tests/run-make/extern-flag-pathless/rmake.rs +++ b/tests/run-make/extern-flag-pathless/rmake.rs @@ -8,21 +8,21 @@ //@ ignore-cross-compile // Reason: the compiled binary is executed -use run_make_support::{dynamic_lib_name, fs_wrapper, run, run_fail, rust_lib_name, rustc}; +use run_make_support::{dynamic_lib_name, fs as rfs, run, run_fail, rust_lib_name, rustc}; fn main() { rustc().input("bar.rs").crate_type("rlib").crate_type("dylib").arg("-Cprefer-dynamic").run(); // By default, the rlib has priority over the dylib. rustc().input("foo.rs").arg("--extern").arg("bar").run(); - fs_wrapper::rename(dynamic_lib_name("bar"), "bar.tmp"); + rfs::rename(dynamic_lib_name("bar"), "bar.tmp"); run("foo"); - fs_wrapper::rename("bar.tmp", dynamic_lib_name("bar")); + rfs::rename("bar.tmp", dynamic_lib_name("bar")); rustc().input("foo.rs").extern_("bar", rust_lib_name("bar")).arg("--extern").arg("bar").run(); - fs_wrapper::rename(dynamic_lib_name("bar"), "bar.tmp"); + rfs::rename(dynamic_lib_name("bar"), "bar.tmp"); run("foo"); - fs_wrapper::rename("bar.tmp", dynamic_lib_name("bar")); + rfs::rename("bar.tmp", dynamic_lib_name("bar")); // The first explicit usage of extern overrides the second pathless --extern bar. rustc() @@ -31,13 +31,13 @@ fn main() { .arg("--extern") .arg("bar") .run(); - fs_wrapper::rename(dynamic_lib_name("bar"), "bar.tmp"); + rfs::rename(dynamic_lib_name("bar"), "bar.tmp"); run_fail("foo"); - fs_wrapper::rename("bar.tmp", dynamic_lib_name("bar")); + rfs::rename("bar.tmp", dynamic_lib_name("bar")); // With prefer-dynamic, execution fails as it refuses to use the rlib. rustc().input("foo.rs").arg("--extern").arg("bar").arg("-Cprefer-dynamic").run(); - fs_wrapper::rename(dynamic_lib_name("bar"), "bar.tmp"); + rfs::rename(dynamic_lib_name("bar"), "bar.tmp"); run_fail("foo"); - fs_wrapper::rename("bar.tmp", dynamic_lib_name("bar")); + rfs::rename("bar.tmp", dynamic_lib_name("bar")); } diff --git a/tests/run-make/extra-filename-with-temp-outputs/rmake.rs b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs index c39e397a7cb3..d7b865f81699 100644 --- a/tests/run-make/extra-filename-with-temp-outputs/rmake.rs +++ b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs @@ -7,7 +7,7 @@ // See https://github.com/rust-lang/rust/pull/15686 use run_make_support::{ - bin_name, cwd, fs_wrapper, has_prefix, has_suffix, rustc, shallow_find_files, + bin_name, cwd, fs as rfs, has_prefix, has_suffix, rustc, shallow_find_files, }; fn main() { @@ -16,6 +16,6 @@ fn main() { has_prefix(path, "foobar.foo") && has_suffix(path, "0.rcgu.o") }); let object_file = object_files.get(0).unwrap(); - fs_wrapper::remove_file(object_file); - fs_wrapper::remove_file(bin_name("foobar")); + rfs::remove_file(object_file); + rfs::remove_file(bin_name("foobar")); } diff --git a/tests/run-make/ice-dep-cannot-find-dep/rmake.rs b/tests/run-make/ice-dep-cannot-find-dep/rmake.rs index 33c755bddd7b..b4210eb5f3bc 100644 --- a/tests/run-make/ice-dep-cannot-find-dep/rmake.rs +++ b/tests/run-make/ice-dep-cannot-find-dep/rmake.rs @@ -16,7 +16,7 @@ // If we used `rustc` the additional '-L rmake_out' option would allow rustc to // actually find the crate. -use run_make_support::{bare_rustc, fs_wrapper, rust_lib_name, rustc}; +use run_make_support::{bare_rustc, fs as rfs, rust_lib_name, rustc}; fn main() { rustc().crate_name("a").crate_type("rlib").input("a.rs").arg("--verbose").run(); diff --git a/tests/run-make/inaccessible-temp-dir/rmake.rs b/tests/run-make/inaccessible-temp-dir/rmake.rs index 62b8479c3288..4fbd207975c5 100644 --- a/tests/run-make/inaccessible-temp-dir/rmake.rs +++ b/tests/run-make/inaccessible-temp-dir/rmake.rs @@ -24,11 +24,11 @@ // Reason: `set_readonly` has no effect on directories // and does not prevent modification. -use run_make_support::{fs_wrapper, rustc, test_while_readonly}; +use run_make_support::{fs as rfs, rustc, test_while_readonly}; fn main() { // Create an inaccessible directory. - fs_wrapper::create_dir("inaccessible"); + rfs::create_dir("inaccessible"); test_while_readonly("inaccessible", || { // Run rustc with `-Z temps-dir` set to a directory *inside* the inaccessible one, // so that it can't create `tmp`. diff --git a/tests/run-make/incr-prev-body-beyond-eof/rmake.rs b/tests/run-make/incr-prev-body-beyond-eof/rmake.rs index e6d6ae95aaaf..ae74f120ce39 100644 --- a/tests/run-make/incr-prev-body-beyond-eof/rmake.rs +++ b/tests/run-make/incr-prev-body-beyond-eof/rmake.rs @@ -13,14 +13,14 @@ //@ ignore-nvptx64-nvidia-cuda // FIXME: can't find crate for `std` -use run_make_support::fs_wrapper as fs; +use run_make_support::fs as rfs; use run_make_support::rustc; fn main() { - fs::create_dir("src"); - fs::create_dir("incr"); - fs::copy("a.rs", "src/main.rs"); + rfs::create_dir("src"); + rfs::create_dir("incr"); + rfs::copy("a.rs", "src/main.rs"); rustc().incremental("incr").input("src/main.rs").run(); - fs::copy("b.rs", "src/main.rs"); + rfs::copy("b.rs", "src/main.rs"); rustc().incremental("incr").input("src/main.rs").run(); } diff --git a/tests/run-make/incr-test-moved-file/rmake.rs b/tests/run-make/incr-test-moved-file/rmake.rs index ae142a0d22e8..c4fc3d37526e 100644 --- a/tests/run-make/incr-test-moved-file/rmake.rs +++ b/tests/run-make/incr-test-moved-file/rmake.rs @@ -14,14 +14,14 @@ //@ ignore-nvptx64-nvidia-cuda // FIXME: can't find crate for 'std' -use run_make_support::{fs_wrapper, rust_lib_name, rustc}; +use run_make_support::{fs as rfs, rust_lib_name, rustc}; fn main() { - fs_wrapper::create_dir("incr"); - fs_wrapper::create_dir("src"); - fs_wrapper::create_dir("src/mydir"); - fs_wrapper::copy("main.rs", "src/main.rs"); + rfs::create_dir("incr"); + rfs::create_dir("src"); + rfs::create_dir("src/mydir"); + rfs::copy("main.rs", "src/main.rs"); rustc().input("src/main.rs").incremental("incr").arg("--test").run(); - fs_wrapper::rename("src/main.rs", "src/mydir/main.rs"); + rfs::rename("src/main.rs", "src/mydir/main.rs"); rustc().input("src/mydir/main.rs").incremental("incr").arg("--test").run(); } diff --git a/tests/run-make/incremental-debugger-visualizer/rmake.rs b/tests/run-make/incremental-debugger-visualizer/rmake.rs index 1ef3af873530..da9f9d41ee81 100644 --- a/tests/run-make/incremental-debugger-visualizer/rmake.rs +++ b/tests/run-make/incremental-debugger-visualizer/rmake.rs @@ -2,14 +2,14 @@ // (in this case, foo.py and foo.natvis) are picked up when compiling incrementally. // See https://github.com/rust-lang/rust/pull/111641 -use run_make_support::{fs_wrapper, invalid_utf8_contains, invalid_utf8_not_contains, rustc}; +use run_make_support::{fs as rfs, invalid_utf8_contains, invalid_utf8_not_contains, rustc}; use std::io::Read; fn main() { - fs_wrapper::create_file("foo.py"); - fs_wrapper::write("foo.py", "GDB script v1"); - fs_wrapper::create_file("foo.natvis"); - fs_wrapper::write("foo.natvis", "Natvis v1"); + rfs::create_file("foo.py"); + rfs::write("foo.py", "GDB script v1"); + rfs::create_file("foo.natvis"); + rfs::write("foo.natvis", "Natvis v1"); rustc() .input("foo.rs") .crate_type("rlib") @@ -22,9 +22,9 @@ fn main() { invalid_utf8_contains("libfoo.rmeta", "Natvis v1"); // Change only the GDB script and check that the change has been picked up - fs_wrapper::remove_file("foo.py"); - fs_wrapper::create_file("foo.py"); - fs_wrapper::write("foo.py", "GDB script v2"); + rfs::remove_file("foo.py"); + rfs::create_file("foo.py"); + rfs::write("foo.py", "GDB script v2"); rustc() .input("foo.rs") .crate_type("rlib") @@ -38,9 +38,9 @@ fn main() { invalid_utf8_contains("libfoo.rmeta", "Natvis v1"); // Now change the Natvis version and check that the change has been picked up - fs_wrapper::remove_file("foo.natvis"); - fs_wrapper::create_file("foo.natvis"); - fs_wrapper::write("foo.natvis", "Natvis v2"); + rfs::remove_file("foo.natvis"); + rfs::create_file("foo.natvis"); + rfs::write("foo.natvis", "Natvis v2"); rustc() .input("foo.rs") .crate_type("rlib") diff --git a/tests/run-make/incremental-session-fail/rmake.rs b/tests/run-make/incremental-session-fail/rmake.rs index 0283709f2cf8..22ff1e2a8a4d 100644 --- a/tests/run-make/incremental-session-fail/rmake.rs +++ b/tests/run-make/incremental-session-fail/rmake.rs @@ -4,10 +4,10 @@ // the ensuing compilation failure is not an ICE. // See https://github.com/rust-lang/rust/pull/85698 -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{fs as rfs, rustc}; fn main() { - fs_wrapper::create_file("session"); + rfs::create_file("session"); // rustc should fail to create the session directory here. let out = rustc().input("foo.rs").crate_type("rlib").incremental("session").run_fail(); out.assert_stderr_contains("could not create incremental compilation crate directory"); diff --git a/tests/run-make/inline-always-many-cgu/rmake.rs b/tests/run-make/inline-always-many-cgu/rmake.rs index c55ea69f3b90..3b51bb1cd81a 100644 --- a/tests/run-make/inline-always-many-cgu/rmake.rs +++ b/tests/run-make/inline-always-many-cgu/rmake.rs @@ -1,6 +1,6 @@ -use run_make_support::fs_wrapper::read_to_string; +use run_make_support::fs as rfs; use run_make_support::regex::Regex; -use run_make_support::{read_dir, rustc}; +use run_make_support::rustc; use std::ffi::OsStr; @@ -8,9 +8,9 @@ fn main() { rustc().input("foo.rs").emit("llvm-ir").codegen_units(2).run(); let re = Regex::new(r"\bcall\b").unwrap(); let mut nb_ll = 0; - read_dir(".", |path| { + rfs::read_dir_entries(".", |path| { if path.is_file() && path.extension().is_some_and(|ext| ext == OsStr::new("ll")) { - assert!(!re.is_match(&read_to_string(path))); + assert!(!re.is_match(&rfs::read_to_string(path))); nb_ll += 1; } }); diff --git a/tests/run-make/intrinsic-unreachable/rmake.rs b/tests/run-make/intrinsic-unreachable/rmake.rs index 7e78c8288b82..34f7ab3fbc8a 100644 --- a/tests/run-make/intrinsic-unreachable/rmake.rs +++ b/tests/run-make/intrinsic-unreachable/rmake.rs @@ -8,13 +8,13 @@ //@ ignore-windows // Reason: Because of Windows exception handling, the code is not necessarily any shorter. -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{fs as rfs, rustc}; fn main() { rustc().opt().emit("asm").input("exit-ret.rs").run(); rustc().opt().emit("asm").input("exit-unreachable.rs").run(); assert!( - fs_wrapper::read_to_string("exit-unreachable.s").lines().count() - < fs_wrapper::read_to_string("exit-ret.s").lines().count() + rfs::read_to_string("exit-unreachable.s").lines().count() + < rfs::read_to_string("exit-ret.s").lines().count() ); } diff --git a/tests/run-make/invalid-library/rmake.rs b/tests/run-make/invalid-library/rmake.rs index 9ebab1c8b0f0..3961e2b846bd 100644 --- a/tests/run-make/invalid-library/rmake.rs +++ b/tests/run-make/invalid-library/rmake.rs @@ -4,11 +4,11 @@ // one appearing in stderr in this scenario. // See https://github.com/rust-lang/rust/pull/12645 -use run_make_support::fs_wrapper::create_file; +use run_make_support::fs as rfs; use run_make_support::{llvm_ar, rustc}; fn main() { - create_file("lib.rmeta"); + rfs::create_file("lib.rmeta"); llvm_ar().obj_to_ar().output_input("libfoo-ffffffff-1.0.rlib", "lib.rmeta").run(); rustc().input("foo.rs").run_fail().assert_stderr_contains("found invalid metadata"); } diff --git a/tests/run-make/invalid-so/rmake.rs b/tests/run-make/invalid-so/rmake.rs index 5cfda05334eb..c79e0563bada 100644 --- a/tests/run-make/invalid-so/rmake.rs +++ b/tests/run-make/invalid-so/rmake.rs @@ -4,10 +4,10 @@ // explains that the file exists, but that its metadata is incorrect. // See https://github.com/rust-lang/rust/pull/88368 -use run_make_support::{dynamic_lib_name, fs_wrapper, rustc}; +use run_make_support::{dynamic_lib_name, fs as rfs, rustc}; fn main() { - fs_wrapper::create_file(dynamic_lib_name("foo")); + rfs::create_file(dynamic_lib_name("foo")); rustc() .crate_type("lib") .extern_("foo", dynamic_lib_name("foo")) diff --git a/tests/run-make/invalid-staticlib/rmake.rs b/tests/run-make/invalid-staticlib/rmake.rs index 451292932477..e31dcdec95bd 100644 --- a/tests/run-make/invalid-staticlib/rmake.rs +++ b/tests/run-make/invalid-staticlib/rmake.rs @@ -4,10 +4,10 @@ // an internal compiler error (ICE). // See https://github.com/rust-lang/rust/pull/28673 -use run_make_support::{fs_wrapper, rustc, static_lib_name}; +use run_make_support::{fs as rfs, rustc, static_lib_name}; fn main() { - fs_wrapper::create_file(static_lib_name("foo")); + rfs::create_file(static_lib_name("foo")); rustc() .arg("-") .crate_type("rlib") diff --git a/tests/run-make/issue-107495-archive-permissions/rmake.rs b/tests/run-make/issue-107495-archive-permissions/rmake.rs index ee281fe0a5f0..78d57d57afbe 100644 --- a/tests/run-make/issue-107495-archive-permissions/rmake.rs +++ b/tests/run-make/issue-107495-archive-permissions/rmake.rs @@ -3,7 +3,7 @@ #[cfg(unix)] extern crate libc; -use run_make_support::{aux_build, fs_wrapper}; +use run_make_support::{aux_build, fs as rfs}; #[cfg(unix)] use std::os::unix::fs::PermissionsExt; @@ -20,7 +20,7 @@ fn main() { } fn verify(path: &Path) { - let perm = fs_wrapper::metadata(path).permissions(); + let perm = rfs::metadata(path).permissions(); assert!(!perm.readonly()); diff --git a/tests/run-make/ls-metadata/rmake.rs b/tests/run-make/ls-metadata/rmake.rs index 0e60f2c46787..8a2d79ed3af3 100644 --- a/tests/run-make/ls-metadata/rmake.rs +++ b/tests/run-make/ls-metadata/rmake.rs @@ -6,12 +6,12 @@ //@ ignore-cross-compile -use run_make_support::fs_wrapper; +use run_make_support::fs as rfs; use run_make_support::rustc; fn main() { rustc().input("foo.rs").run(); rustc().arg("-Zls=root").input("foo").run(); - fs_wrapper::create_file("bar"); + rfs::create_file("bar"); rustc().arg("-Zls=root").input("bar").run(); } diff --git a/tests/run-make/lto-readonly-lib/rmake.rs b/tests/run-make/lto-readonly-lib/rmake.rs index 9eb135addd9e..5e06aeb73b60 100644 --- a/tests/run-make/lto-readonly-lib/rmake.rs +++ b/tests/run-make/lto-readonly-lib/rmake.rs @@ -7,7 +7,7 @@ //@ ignore-cross-compile -use run_make_support::fs_wrapper; +use run_make_support::fs as rfs; use run_make_support::{run, rust_lib_name, rustc, test_while_readonly}; fn main() { diff --git a/tests/run-make/many-crates-but-no-match/rmake.rs b/tests/run-make/many-crates-but-no-match/rmake.rs index ea4f166b2bd9..7f8f93346d79 100644 --- a/tests/run-make/many-crates-but-no-match/rmake.rs +++ b/tests/run-make/many-crates-but-no-match/rmake.rs @@ -4,12 +4,12 @@ // what should be done to fix the issue. // See https://github.com/rust-lang/rust/issues/13266 -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{fs as rfs, rustc}; fn main() { - fs_wrapper::create_dir("a1"); - fs_wrapper::create_dir("a2"); - fs_wrapper::create_dir("a3"); + rfs::create_dir("a1"); + rfs::create_dir("a2"); + rfs::create_dir("a3"); rustc().crate_type("rlib").out_dir("a1").input("crateA1.rs").run(); rustc().crate_type("rlib").library_search_path("a1").input("crateB.rs").run(); rustc().crate_type("rlib").out_dir("a2").input("crateA2.rs").run(); diff --git a/tests/run-make/mixing-libs/rmake.rs b/tests/run-make/mixing-libs/rmake.rs index 06ef6ab00f5f..6799a93fbc12 100644 --- a/tests/run-make/mixing-libs/rmake.rs +++ b/tests/run-make/mixing-libs/rmake.rs @@ -6,7 +6,7 @@ //@ ignore-cross-compile -use run_make_support::{dynamic_lib_name, fs_wrapper, rustc}; +use run_make_support::{dynamic_lib_name, fs as rfs, rustc}; fn main() { rustc().input("rlib.rs").crate_type("rlib").crate_type("dylib").run(); @@ -16,6 +16,6 @@ fn main() { // librlib's dynamic version needs to be removed here to prevent prog.rs from fetching // the wrong one. - fs_wrapper::remove_file(dynamic_lib_name("rlib")); + rfs::remove_file(dynamic_lib_name("rlib")); rustc().input("prog.rs").run_fail(); } diff --git a/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs b/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs index c64260299892..2fd602270646 100644 --- a/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs +++ b/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs @@ -17,20 +17,20 @@ //@ ignore-nvptx64-nvidia-cuda // FIXME: can't find crate for 'std' -use run_make_support::{fs_wrapper, rust_lib_name, rustc}; +use run_make_support::{fs as rfs, rust_lib_name, rustc}; fn main() { - fs_wrapper::create_dir("incr"); - fs_wrapper::create_dir("first_src"); - fs_wrapper::create_dir("output"); - fs_wrapper::rename("my_lib.rs", "first_src/my_lib.rs"); - fs_wrapper::rename("main.rs", "first_src/main.rs"); + rfs::create_dir("incr"); + rfs::create_dir("first_src"); + rfs::create_dir("output"); + rfs::rename("my_lib.rs", "first_src/my_lib.rs"); + rfs::rename("main.rs", "first_src/main.rs"); // Build from "first_src" std::env::set_current_dir("first_src").unwrap(); rustc().input("my_lib.rs").incremental("incr").crate_type("lib").run(); rustc().input("main.rs").incremental("incr").extern_("my_lib", rust_lib_name("my_lib")).run(); std::env::set_current_dir("..").unwrap(); - fs_wrapper::rename("first_src", "second_src"); + rfs::rename("first_src", "second_src"); std::env::set_current_dir("second_src").unwrap(); // Build from "second_src" - the output and incremental directory remain identical rustc().input("my_lib.rs").incremental("incr").crate_type("lib").run(); diff --git a/tests/run-make/non-unicode-env/rmake.rs b/tests/run-make/non-unicode-env/rmake.rs index bffd9477f8fe..f23fef88dabc 100644 --- a/tests/run-make/non-unicode-env/rmake.rs +++ b/tests/run-make/non-unicode-env/rmake.rs @@ -1,4 +1,4 @@ -use run_make_support::fs_wrapper; +use run_make_support::fs as rfs; use run_make_support::rustc; fn main() { @@ -7,6 +7,6 @@ fn main() { #[cfg(windows)] let non_unicode: std::ffi::OsString = std::os::windows::ffi::OsStringExt::from_wide(&[0xD800]); let output = rustc().input("non_unicode_env.rs").env("NON_UNICODE_VAR", non_unicode).run_fail(); - let expected = fs_wrapper::read_to_string("non_unicode_env.stderr"); + let expected = rfs::read_to_string("non_unicode_env.stderr"); output.assert_stderr_equals(expected); } diff --git a/tests/run-make/non-unicode-in-incremental-dir/rmake.rs b/tests/run-make/non-unicode-in-incremental-dir/rmake.rs index 895d9e00a2d4..d0d730d17ebb 100644 --- a/tests/run-make/non-unicode-in-incremental-dir/rmake.rs +++ b/tests/run-make/non-unicode-in-incremental-dir/rmake.rs @@ -1,4 +1,4 @@ -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{fs as rfs, rustc}; fn main() { #[cfg(unix)] @@ -17,8 +17,8 @@ fn main() { } let incr_dir = "incr-dir"; rustc().input("foo.rs").incremental(&incr_dir).run(); - for crate_dir in fs_wrapper::read_dir(&incr_dir) { - fs_wrapper::create_dir(crate_dir.unwrap().path().join(&non_unicode)); + for crate_dir in rfs::read_dir(&incr_dir) { + rfs::create_dir(crate_dir.unwrap().path().join(&non_unicode)); } rustc().input("foo.rs").incremental(&incr_dir).run(); } diff --git a/tests/run-make/obey-crate-type-flag/rmake.rs b/tests/run-make/obey-crate-type-flag/rmake.rs index 8aa78cccbb23..198eb6931589 100644 --- a/tests/run-make/obey-crate-type-flag/rmake.rs +++ b/tests/run-make/obey-crate-type-flag/rmake.rs @@ -6,7 +6,7 @@ //@ ignore-cross-compile use run_make_support::{ - cwd, dynamic_lib_name, fs_wrapper, has_extension, rust_lib_name, rustc, shallow_find_files, + cwd, dynamic_lib_name, fs as rfs, has_extension, rust_lib_name, rustc, shallow_find_files, }; use std::path::Path; @@ -15,7 +15,7 @@ fn main() { assert!(Path::new(&dynamic_lib_name("test")).exists()); assert!(Path::new(&rust_lib_name("test")).exists()); - fs_wrapper::remove_file(rust_lib_name("test")); + rfs::remove_file(rust_lib_name("test")); rustc().crate_type("dylib").input("test.rs").run(); assert!(shallow_find_files(cwd(), |path| { has_extension(path, "rlib") }).is_empty()); } diff --git a/tests/run-make/output-filename-conflicts-with-directory/rmake.rs b/tests/run-make/output-filename-conflicts-with-directory/rmake.rs index 4b5c9e8d1187..6df9628a9fb7 100644 --- a/tests/run-make/output-filename-conflicts-with-directory/rmake.rs +++ b/tests/run-make/output-filename-conflicts-with-directory/rmake.rs @@ -4,10 +4,10 @@ // potentially-confusing linker error. // See https://github.com/rust-lang/rust/pull/47203 -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{fs as rfs, rustc}; fn main() { - fs_wrapper::create_dir("foo"); + rfs::create_dir("foo"); rustc().input("foo.rs").output("foo").run_fail().assert_stderr_contains( r#"the generated executable for the input file "foo.rs" conflicts with the existing directory "foo""#, ); diff --git a/tests/run-make/output-filename-overwrites-input/rmake.rs b/tests/run-make/output-filename-overwrites-input/rmake.rs index c6055e818a17..0e9c20b0468f 100644 --- a/tests/run-make/output-filename-overwrites-input/rmake.rs +++ b/tests/run-make/output-filename-overwrites-input/rmake.rs @@ -4,14 +4,14 @@ //@ ignore-cross-compile -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{fs as rfs, rustc}; fn main() { - fs_wrapper::copy("foo.rs", "foo"); + rfs::copy("foo.rs", "foo"); rustc().input("foo").output("foo").run_fail().assert_stderr_contains( r#"the input file "foo" would be overwritten by the generated executable"#, ); - fs_wrapper::copy("bar.rs", "bar.rlib"); + rfs::copy("bar.rs", "bar.rlib"); rustc().input("bar.rlib").output("bar.rlib").run_fail().assert_stderr_contains( r#"the input file "bar.rlib" would be overwritten by the generated executable"#, ); diff --git a/tests/run-make/output-type-permutations/rmake.rs b/tests/run-make/output-type-permutations/rmake.rs index 1d1637a744ec..a4d2601260b4 100644 --- a/tests/run-make/output-type-permutations/rmake.rs +++ b/tests/run-make/output-type-permutations/rmake.rs @@ -5,7 +5,7 @@ // See https://github.com/rust-lang/rust/pull/12020 use run_make_support::{ - bin_name, dynamic_lib_name, filename_not_in_denylist, fs_wrapper, rust_lib_name, rustc, + bin_name, dynamic_lib_name, filename_not_in_denylist, fs as rfs, rust_lib_name, rustc, shallow_find_files, static_lib_name, }; use std::path::PathBuf; @@ -20,10 +20,10 @@ fn assert_expected_output_files(expectations: Expectations, rustc_invocation: im let Expectations { expected_files: must_exist, allowed_files: can_exist, test_dir: dir } = expectations; - fs_wrapper::create_dir(&dir); + rfs::create_dir(&dir); rustc_invocation(); for file in must_exist { - fs_wrapper::remove_file(PathBuf::from(&dir).join(&file)); + rfs::remove_file(PathBuf::from(&dir).join(&file)); } let actual_output_files = shallow_find_files(dir, |path| filename_not_in_denylist(path, &can_exist)); @@ -526,17 +526,14 @@ fn main() { test_dir: "rlib-emits".to_string(), }, || { - fs_wrapper::rename("staticlib-all3/bar.bc", "rlib-emits/foo.bc"); + rfs::rename("staticlib-all3/bar.bc", "rlib-emits/foo.bc"); rustc() .input("foo.rs") .emit("llvm-bc,link") .crate_type("rlib") .out_dir("rlib-emits") .run(); - assert_eq!( - fs_wrapper::read("rlib-emits/foo.bc"), - fs_wrapper::read("rlib-emits/bar.bc") - ); + assert_eq!(rfs::read("rlib-emits/foo.bc"), rfs::read("rlib-emits/bar.bc")); }, ); } diff --git a/tests/run-make/parallel-rustc-no-overwrite/rmake.rs b/tests/run-make/parallel-rustc-no-overwrite/rmake.rs index 3f032cf3762a..9c224ad05b21 100644 --- a/tests/run-make/parallel-rustc-no-overwrite/rmake.rs +++ b/tests/run-make/parallel-rustc-no-overwrite/rmake.rs @@ -5,12 +5,12 @@ // conflicts. This test uses this flag and checks for successful compilation. // See https://github.com/rust-lang/rust/pull/83846 -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{fs as rfs, rustc}; use std::sync::{Arc, Barrier}; use std::thread; fn main() { - fs_wrapper::create_file("lib.rs"); + rfs::create_file("lib.rs"); let barrier = Arc::new(Barrier::new(2)); let handle = { let barrier = Arc::clone(&barrier); diff --git a/tests/run-make/pgo-branch-weights/rmake.rs b/tests/run-make/pgo-branch-weights/rmake.rs index d3cb79c39afa..0915fe0e2a29 100644 --- a/tests/run-make/pgo-branch-weights/rmake.rs +++ b/tests/run-make/pgo-branch-weights/rmake.rs @@ -10,14 +10,14 @@ //@ needs-profiler-support //@ ignore-cross-compile -use run_make_support::{fs_wrapper, llvm_filecheck, llvm_profdata, run_with_args, rustc}; +use run_make_support::{fs as rfs, llvm_filecheck, llvm_profdata, run_with_args, rustc}; use std::path::Path; fn main() { let path_prof_data_dir = Path::new("prof_data_dir"); let path_merged_profdata = path_prof_data_dir.join("merged.profdata"); rustc().input("opaque.rs").run(); - fs_wrapper::create_dir_all(&path_prof_data_dir); + rfs::create_dir_all(&path_prof_data_dir); rustc() .input("interesting.rs") .profile_generate(&path_prof_data_dir) @@ -34,8 +34,5 @@ fn main() { .codegen_units(1) .emit("llvm-ir") .run(); - llvm_filecheck() - .patterns("filecheck-patterns.txt") - .stdin(fs_wrapper::read("interesting.ll")) - .run(); + llvm_filecheck().patterns("filecheck-patterns.txt").stdin(rfs::read("interesting.ll")).run(); } diff --git a/tests/run-make/pgo-use/rmake.rs b/tests/run-make/pgo-use/rmake.rs index 0f76aff80d0c..f53ea79102cb 100644 --- a/tests/run-make/pgo-use/rmake.rs +++ b/tests/run-make/pgo-use/rmake.rs @@ -9,8 +9,8 @@ //@ ignore-cross-compile use run_make_support::{ - cwd, fs_wrapper, has_extension, has_prefix, llvm_filecheck, llvm_profdata, run_with_args, - rustc, shallow_find_files, + cwd, fs as rfs, has_extension, has_prefix, llvm_filecheck, llvm_profdata, run_with_args, rustc, + shallow_find_files, }; fn main() { @@ -47,7 +47,7 @@ fn main() { // line with the function name before the line with the function attributes. // FileCheck only supports checking that something matches on the next line, // but not if something matches on the previous line. - let ir = fs_wrapper::read_to_string("main.ll"); + let ir = rfs::read_to_string("main.ll"); let lines: Vec<_> = ir.lines().rev().collect(); let mut reversed_ir = lines.join("\n"); reversed_ir.push('\n'); diff --git a/tests/run-make/prefer-dylib/rmake.rs b/tests/run-make/prefer-dylib/rmake.rs index 6b3b3ad6d3b8..0fed3e872595 100644 --- a/tests/run-make/prefer-dylib/rmake.rs +++ b/tests/run-make/prefer-dylib/rmake.rs @@ -1,6 +1,6 @@ //@ ignore-cross-compile -use run_make_support::{cwd, dynamic_lib_name, fs_wrapper, read_dir, run, run_fail, rustc}; +use run_make_support::{dynamic_lib_name, fs as rfs, run, run_fail, rustc}; fn main() { rustc().input("bar.rs").crate_type("dylib").crate_type("rlib").arg("-Cprefer-dynamic").run(); @@ -8,7 +8,7 @@ fn main() { run("foo"); - fs_wrapper::remove_file(dynamic_lib_name("bar")); + rfs::remove_file(dynamic_lib_name("bar")); // This time the command should fail. run_fail("foo"); } diff --git a/tests/run-make/prefer-rlib/rmake.rs b/tests/run-make/prefer-rlib/rmake.rs index 96861a264e62..188db7c06028 100644 --- a/tests/run-make/prefer-rlib/rmake.rs +++ b/tests/run-make/prefer-rlib/rmake.rs @@ -3,13 +3,13 @@ //@ ignore-cross-compile -use run_make_support::{dynamic_lib_name, fs_wrapper, path, run, rust_lib_name, rustc}; +use run_make_support::{dynamic_lib_name, fs as rfs, path, run, rust_lib_name, rustc}; fn main() { rustc().input("bar.rs").crate_type("dylib").crate_type("rlib").run(); assert!(path(rust_lib_name("bar")).exists()); rustc().input("foo.rs").run(); - fs_wrapper::remove_file(rust_lib_name("bar")); - fs_wrapper::remove_file(dynamic_lib_name("bar")); + rfs::remove_file(rust_lib_name("bar")); + rfs::remove_file(dynamic_lib_name("bar")); run("foo"); } diff --git a/tests/run-make/pretty-print-with-dep-file/rmake.rs b/tests/run-make/pretty-print-with-dep-file/rmake.rs index 859a9781bb6e..4b3d1c34faea 100644 --- a/tests/run-make/pretty-print-with-dep-file/rmake.rs +++ b/tests/run-make/pretty-print-with-dep-file/rmake.rs @@ -5,13 +5,13 @@ // does not get an unexpected dep-info file. // See https://github.com/rust-lang/rust/issues/112898 -use run_make_support::{fs_wrapper, invalid_utf8_contains, rustc}; +use run_make_support::{fs as rfs, invalid_utf8_contains, rustc}; use std::path::Path; fn main() { rustc().emit("dep-info").arg("-Zunpretty=expanded").input("with-dep.rs").run(); invalid_utf8_contains("with-dep.d", "with-dep.rs"); - fs_wrapper::remove_file("with-dep.d"); + rfs::remove_file("with-dep.d"); rustc().emit("dep-info").arg("-Zunpretty=normal").input("with-dep.rs").run(); assert!(!Path::new("with-dep.d").exists()); } diff --git a/tests/run-make/print-cfg/rmake.rs b/tests/run-make/print-cfg/rmake.rs index d11eda1db2ae..73a03189cb24 100644 --- a/tests/run-make/print-cfg/rmake.rs +++ b/tests/run-make/print-cfg/rmake.rs @@ -10,7 +10,7 @@ use std::ffi::OsString; use std::iter::FromIterator; use std::path::PathBuf; -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{fs as rfs, rustc}; struct PrintCfg { target: &'static str, @@ -96,7 +96,7 @@ fn check(PrintCfg { target, includes, disallow }: PrintCfg) { rustc().target(target).arg(print_arg).run(); - let output = fs_wrapper::read_to_string(&tmp_path); + let output = rfs::read_to_string(&tmp_path); check_(&output, includes, disallow); } diff --git a/tests/run-make/print-to-output/rmake.rs b/tests/run-make/print-to-output/rmake.rs index 66f62a7015ab..ecfd84f81bb3 100644 --- a/tests/run-make/print-to-output/rmake.rs +++ b/tests/run-make/print-to-output/rmake.rs @@ -4,7 +4,7 @@ use std::ffi::OsString; use std::path::PathBuf; -use run_make_support::{fs_wrapper, rustc, target}; +use run_make_support::{fs as rfs, rustc, target}; struct Option<'a> { target: &'a str, @@ -49,7 +49,7 @@ fn check(args: Option) { rustc().target(args.target).arg(print_arg).run(); - fs_wrapper::read_to_string(&tmp_path) + rfs::read_to_string(&tmp_path) }; check_(&stdout, args.includes); diff --git a/tests/run-make/remap-path-prefix/rmake.rs b/tests/run-make/remap-path-prefix/rmake.rs index 62c0368e4b3a..390db93e62d1 100644 --- a/tests/run-make/remap-path-prefix/rmake.rs +++ b/tests/run-make/remap-path-prefix/rmake.rs @@ -4,7 +4,7 @@ // See https://github.com/rust-lang/rust/pull/85344 use run_make_support::bstr::ByteSlice; -use run_make_support::{bstr, fs_wrapper, is_darwin, rustc}; +use run_make_support::{bstr, fs as rfs, is_darwin, rustc}; fn main() { let mut out_simple = rustc(); @@ -60,12 +60,9 @@ fn main() { // helper functions. fn rmeta_contains(expected: &str) { // Normalize to account for path differences in Windows. - if !bstr::BString::from(fs_wrapper::read("liblib.rmeta")) - .replace(b"\\", b"/") - .contains_str(expected) - { + if !bstr::BString::from(rfs::read("liblib.rmeta")).replace(b"\\", b"/").contains_str(expected) { eprintln!("=== FILE CONTENTS (LOSSY) ==="); - eprintln!("{}", String::from_utf8_lossy(&fs_wrapper::read("liblib.rmeta"))); + eprintln!("{}", String::from_utf8_lossy(&rfs::read("liblib.rmeta"))); eprintln!("=== SPECIFIED TEXT ==="); eprintln!("{}", expected); panic!("specified text was not found in file"); @@ -74,12 +71,9 @@ fn rmeta_contains(expected: &str) { fn rmeta_not_contains(expected: &str) { // Normalize to account for path differences in Windows. - if bstr::BString::from(fs_wrapper::read("liblib.rmeta")) - .replace(b"\\", b"/") - .contains_str(expected) - { + if bstr::BString::from(rfs::read("liblib.rmeta")).replace(b"\\", b"/").contains_str(expected) { eprintln!("=== FILE CONTENTS (LOSSY) ==="); - eprintln!("{}", String::from_utf8_lossy(&fs_wrapper::read("liblib.rmeta"))); + eprintln!("{}", String::from_utf8_lossy(&rfs::read("liblib.rmeta"))); eprintln!("=== SPECIFIED TEXT ==="); eprintln!("{}", expected); panic!("specified text was not found in file"); diff --git a/tests/run-make/repr128-dwarf/rmake.rs b/tests/run-make/repr128-dwarf/rmake.rs index a65cf234edff..1c61698ffcd4 100644 --- a/tests/run-make/repr128-dwarf/rmake.rs +++ b/tests/run-make/repr128-dwarf/rmake.rs @@ -3,7 +3,7 @@ use gimli::{AttributeValue, EndianRcSlice, Reader, RunTimeEndian}; use object::{Object, ObjectSection}; -use run_make_support::{fs_wrapper, gimli, object, rustc}; +use run_make_support::{fs as rfs, gimli, object, rustc}; use std::collections::HashMap; use std::path::PathBuf; use std::rc::Rc; @@ -19,7 +19,7 @@ fn main() { .join("DWARF") .join("repr128"); let output = - fs_wrapper::read(if dsym_location.try_exists().unwrap() { dsym_location } else { output }); + rfs::read(if dsym_location.try_exists().unwrap() { dsym_location } else { output }); let obj = object::File::parse(output.as_slice()).unwrap(); let endian = if obj.is_little_endian() { RunTimeEndian::Little } else { RunTimeEndian::Big }; let dwarf = gimli::Dwarf::load(|section| -> Result<_, ()> { diff --git a/tests/run-make/reset-codegen-1/rmake.rs b/tests/run-make/reset-codegen-1/rmake.rs index 19d42b3d6d5e..18cf5513d5c0 100644 --- a/tests/run-make/reset-codegen-1/rmake.rs +++ b/tests/run-make/reset-codegen-1/rmake.rs @@ -7,7 +7,7 @@ //@ ignore-cross-compile -use run_make_support::{bin_name, fs_wrapper, rustc}; +use run_make_support::{bin_name, fs as rfs, rustc}; use std::path::Path; fn compile(output_file: &str, emit: Option<&str>) { diff --git a/tests/run-make/resolve-rename/rmake.rs b/tests/run-make/resolve-rename/rmake.rs index 09bd4165b2a5..cefd608177d7 100644 --- a/tests/run-make/resolve-rename/rmake.rs +++ b/tests/run-make/resolve-rename/rmake.rs @@ -5,12 +5,12 @@ // the renamed library. // See https://github.com/rust-lang/rust/pull/49253 -use run_make_support::fs_wrapper; +use run_make_support::fs as rfs; use run_make_support::rustc; fn main() { rustc().extra_filename("-hash").input("foo.rs").run(); rustc().input("bar.rs").run(); - fs_wrapper::rename("libfoo-hash.rlib", "libfoo-another-hash.rlib"); + rfs::rename("libfoo-hash.rlib", "libfoo-another-hash.rlib"); rustc().input("baz.rs").run(); } diff --git a/tests/run-make/rlib-chain/rmake.rs b/tests/run-make/rlib-chain/rmake.rs index 0947262bf620..875de607a7b1 100644 --- a/tests/run-make/rlib-chain/rmake.rs +++ b/tests/run-make/rlib-chain/rmake.rs @@ -8,7 +8,7 @@ //@ ignore-cross-compile // Reason: the compiled binary is executed -use run_make_support::{fs_wrapper, run, rust_lib_name, rustc}; +use run_make_support::{fs as rfs, run, rust_lib_name, rustc}; fn main() { rustc().input("m1.rs").run(); @@ -16,8 +16,8 @@ fn main() { rustc().input("m3.rs").run(); rustc().input("m4.rs").run(); run("m4"); - fs_wrapper::remove_file(rust_lib_name("m1")); - fs_wrapper::remove_file(rust_lib_name("m2")); - fs_wrapper::remove_file(rust_lib_name("m3")); + rfs::remove_file(rust_lib_name("m1")); + rfs::remove_file(rust_lib_name("m2")); + rfs::remove_file(rust_lib_name("m3")); run("m4"); } diff --git a/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs index 5d67ee2580fb..e76927467064 100644 --- a/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs +++ b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs @@ -1,10 +1,10 @@ -use run_make_support::{fs_wrapper, htmldocck, rustc, rustdoc, source_root}; +use run_make_support::{fs as rfs, htmldocck, rustc, rustdoc, source_root}; use std::path::Path; pub fn scrape(extra_args: &[&str]) { let out_dir = Path::new("rustdoc"); let crate_name = "foobar"; - let deps = fs_wrapper::read_dir("examples") + let deps = rfs::read_dir("examples") .filter_map(|entry| entry.ok().map(|e| e.path())) .filter(|path| path.is_file() && path.extension().is_some_and(|ext| ext == "rs")) .collect::>(); diff --git a/tests/run-make/rustdoc-test-args/rmake.rs b/tests/run-make/rustdoc-test-args/rmake.rs index 80eb768c14c6..57ff529d063d 100644 --- a/tests/run-make/rustdoc-test-args/rmake.rs +++ b/tests/run-make/rustdoc-test-args/rmake.rs @@ -1,10 +1,10 @@ -use run_make_support::{fs_wrapper, rustdoc}; +use run_make_support::{fs as rfs, rustdoc}; use std::iter; use std::path::Path; fn generate_a_lot_of_cfgs(path: &Path) { let content = iter::repeat("--cfg=a\n").take(100_000).collect::(); - fs_wrapper::write(path, content.as_bytes()); + rfs::write(path, content.as_bytes()); } fn main() { diff --git a/tests/run-make/rustdoc-themes/rmake.rs b/tests/run-make/rustdoc-themes/rmake.rs index 4174c0552bea..3a63ebbc20b5 100644 --- a/tests/run-make/rustdoc-themes/rmake.rs +++ b/tests/run-make/rustdoc-themes/rmake.rs @@ -1,15 +1,14 @@ // Test that rustdoc will properly load in a theme file and display it in the theme selector. -use run_make_support::{fs_wrapper, htmldocck, rustdoc, source_root}; +use run_make_support::{fs as rfs, htmldocck, rustdoc, source_root}; use std::path::Path; fn main() { let out_dir = Path::new("rustdoc-themes"); let test_css = "test.css"; - let no_script = fs_wrapper::read_to_string( - source_root().join("src/librustdoc/html/static/css/noscript.css"), - ); + let no_script = + rfs::read_to_string(source_root().join("src/librustdoc/html/static/css/noscript.css")); let mut test_content = String::new(); let mut found_begin_light = false; @@ -24,8 +23,8 @@ fn main() { } } assert!(!test_content.is_empty()); - fs_wrapper::create_dir_all(&out_dir); - fs_wrapper::write(&test_css, test_content); + rfs::create_dir_all(&out_dir); + rfs::write(&test_css, test_content); rustdoc().output(&out_dir).input("foo.rs").arg("--theme").arg(&test_css).run(); htmldocck().arg(out_dir).arg("foo.rs").run(); diff --git a/tests/run-make/rustdoc-verify-output-files/rmake.rs b/tests/run-make/rustdoc-verify-output-files/rmake.rs index 61dd97e09a91..efcc47079bd1 100644 --- a/tests/run-make/rustdoc-verify-output-files/rmake.rs +++ b/tests/run-make/rustdoc-verify-output-files/rmake.rs @@ -1,7 +1,7 @@ -use run_make_support::fs_wrapper::copy; +use run_make_support::fs as rfs; use std::path::{Path, PathBuf}; -use run_make_support::{assert_recursive_eq, copy_dir_all, rustdoc}; +use run_make_support::{assert_recursive_eq, rustdoc}; #[derive(PartialEq)] enum JsonOutput { @@ -26,7 +26,7 @@ fn main() { generate_docs(&out_dir, JsonOutput::No); // Copy first output for to check if it's exactly same after second compilation. - copy_dir_all(&out_dir, &tmp_out_dir); + rfs::copy_dir_all(&out_dir, &tmp_out_dir); // Generate html docs once again on same output. generate_docs(&out_dir, JsonOutput::No); @@ -38,7 +38,7 @@ fn main() { assert!(out_dir.join("foobar.json").is_file()); // Copy first json output to check if it's exactly same after second compilation. - copy(out_dir.join("foobar.json"), tmp_out_dir.join("foobar.json")); + rfs::copy(out_dir.join("foobar.json"), tmp_out_dir.join("foobar.json")); // Generate json doc on the same output. generate_docs(&out_dir, JsonOutput::Yes); diff --git a/tests/run-make/sepcomp-cci-copies/rmake.rs b/tests/run-make/sepcomp-cci-copies/rmake.rs index 612a73977fee..e05db252632c 100644 --- a/tests/run-make/sepcomp-cci-copies/rmake.rs +++ b/tests/run-make/sepcomp-cci-copies/rmake.rs @@ -5,7 +5,7 @@ // See https://github.com/rust-lang/rust/pull/16367 use run_make_support::{ - count_regex_matches_in_files_with_extension, cwd, fs_wrapper, has_extension, regex, rustc, + count_regex_matches_in_files_with_extension, cwd, fs as rfs, has_extension, regex, rustc, shallow_find_files, }; diff --git a/tests/run-make/sepcomp-inlining/rmake.rs b/tests/run-make/sepcomp-inlining/rmake.rs index de7551b9a512..c3e28c4198e7 100644 --- a/tests/run-make/sepcomp-inlining/rmake.rs +++ b/tests/run-make/sepcomp-inlining/rmake.rs @@ -6,7 +6,7 @@ // See https://github.com/rust-lang/rust/pull/16367 use run_make_support::{ - count_regex_matches_in_files_with_extension, cwd, fs_wrapper, has_extension, regex, rustc, + count_regex_matches_in_files_with_extension, cwd, fs as rfs, has_extension, regex, rustc, shallow_find_files, }; diff --git a/tests/run-make/sepcomp-separate/rmake.rs b/tests/run-make/sepcomp-separate/rmake.rs index 6f1d22424b5b..83fcd9490ecc 100644 --- a/tests/run-make/sepcomp-separate/rmake.rs +++ b/tests/run-make/sepcomp-separate/rmake.rs @@ -4,7 +4,7 @@ // See https://github.com/rust-lang/rust/pull/16367 use run_make_support::{ - count_regex_matches_in_files_with_extension, cwd, fs_wrapper, has_extension, regex, rustc, + count_regex_matches_in_files_with_extension, cwd, fs as rfs, has_extension, regex, rustc, shallow_find_files, }; diff --git a/tests/run-make/silly-file-names/rmake.rs b/tests/run-make/silly-file-names/rmake.rs index 9df116146fec..a883597e81c3 100644 --- a/tests/run-make/silly-file-names/rmake.rs +++ b/tests/run-make/silly-file-names/rmake.rs @@ -11,13 +11,13 @@ //@ ignore-windows // Reason: Windows refuses files with < and > in their names -use run_make_support::{diff, fs_wrapper, run, rustc}; +use run_make_support::{diff, fs as rfs, run, rustc}; fn main() { - fs_wrapper::create_file(""); - fs_wrapper::write("trailing-gt>", r#""comes from a file with a name that ends with >""#); + rfs::create_file(""); + rfs::write("trailing-gt>", r#""comes from a file with a name that ends with >""#); rustc().input("silly-file-names.rs").output("silly-file-names").run(); let out = run("silly-file-names").stdout_utf8(); diff().expected_file("silly-file-names.run.stdout").actual_text("actual-stdout", out).run(); diff --git a/tests/run-make/symlinked-extern/rmake.rs b/tests/run-make/symlinked-extern/rmake.rs index 9ed5b76edcbd..cf69216d4317 100644 --- a/tests/run-make/symlinked-extern/rmake.rs +++ b/tests/run-make/symlinked-extern/rmake.rs @@ -11,12 +11,12 @@ //@ ignore-cross-compile //@ needs-symlink -use run_make_support::{create_symlink, cwd, fs_wrapper, rustc}; +use run_make_support::{cwd, fs as rfs, rustc}; fn main() { rustc().input("foo.rs").run(); - fs_wrapper::create_dir_all("other"); - create_symlink("libfoo.rlib", "other"); + rfs::create_dir_all("other"); + rfs::create_symlink("libfoo.rlib", "other"); rustc().input("bar.rs").library_search_path(cwd()).run(); rustc().input("baz.rs").extern_("foo", "other").library_search_path(cwd()).run(); } diff --git a/tests/run-make/symlinked-libraries/rmake.rs b/tests/run-make/symlinked-libraries/rmake.rs index 1d1dce5b5cfe..eb4fc081f2bc 100644 --- a/tests/run-make/symlinked-libraries/rmake.rs +++ b/tests/run-make/symlinked-libraries/rmake.rs @@ -8,11 +8,11 @@ //@ ignore-cross-compile //@ needs-symlink -use run_make_support::{create_symlink, dynamic_lib_name, fs_wrapper, rustc}; +use run_make_support::{dynamic_lib_name, fs as rfs, rustc}; fn main() { rustc().input("foo.rs").arg("-Cprefer-dynamic").run(); - fs_wrapper::create_dir_all("other"); - create_symlink(dynamic_lib_name("foo"), "other"); + rfs::create_dir_all("other"); + rfs::create_symlink(dynamic_lib_name("foo"), "other"); rustc().input("bar.rs").library_search_path("other").run(); } diff --git a/tests/run-make/symlinked-rlib/rmake.rs b/tests/run-make/symlinked-rlib/rmake.rs index 65ebb1914282..52dc9a153b87 100644 --- a/tests/run-make/symlinked-rlib/rmake.rs +++ b/tests/run-make/symlinked-rlib/rmake.rs @@ -8,10 +8,10 @@ //@ ignore-cross-compile //@ needs-symlink -use run_make_support::{create_symlink, cwd, rustc}; +use run_make_support::{cwd, fs as rfs, rustc}; fn main() { rustc().input("foo.rs").crate_type("rlib").output("foo.xxx").run(); - create_symlink("foo.xxx", "libfoo.rlib"); + rfs::create_symlink("foo.xxx", "libfoo.rlib"); rustc().input("bar.rs").library_search_path(cwd()).run(); } diff --git a/tests/run-make/target-specs/rmake.rs b/tests/run-make/target-specs/rmake.rs index d2b5f6508380..dc8bac8ff9d7 100644 --- a/tests/run-make/target-specs/rmake.rs +++ b/tests/run-make/target-specs/rmake.rs @@ -5,11 +5,11 @@ // using them correctly, or fails with the right error message when using them improperly. // See https://github.com/rust-lang/rust/pull/16156 -use run_make_support::{diff, fs_wrapper, rustc}; +use run_make_support::{diff, fs as rfs, rustc}; fn main() { rustc().input("foo.rs").target("my-awesome-platform.json").crate_type("lib").emit("asm").run(); - assert!(!fs_wrapper::read_to_string("foo.s").contains("morestack")); + assert!(!rfs::read_to_string("foo.s").contains("morestack")); rustc() .input("foo.rs") .target("my-invalid-platform.json") @@ -40,8 +40,8 @@ fn main() { .print("target-spec-json") .run() .stdout_utf8(); - fs_wrapper::create_file("test-platform.json"); - fs_wrapper::write("test-platform.json", test_platform.as_bytes()); + rfs::create_file("test-platform.json"); + rfs::write("test-platform.json", test_platform.as_bytes()); let test_platform_2 = rustc() .arg("-Zunstable-options") .target("test-platform.json") diff --git a/tests/run-make/track-path-dep-info/rmake.rs b/tests/run-make/track-path-dep-info/rmake.rs index f108dc660512..84041672984e 100644 --- a/tests/run-make/track-path-dep-info/rmake.rs +++ b/tests/run-make/track-path-dep-info/rmake.rs @@ -4,10 +4,10 @@ // output successfully added the file as a dependency. // See https://github.com/rust-lang/rust/pull/84029 -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{fs as rfs, rustc}; fn main() { rustc().input("macro_def.rs").run(); rustc().env("EXISTING_PROC_MACRO_ENV", "1").emit("dep-info").input("macro_use.rs").run(); - assert!(fs_wrapper::read_to_string("macro_use.d").contains("emojis.txt:")); + assert!(rfs::read_to_string("macro_use.d").contains("emojis.txt:")); } diff --git a/tests/run-make/track-pgo-dep-info/rmake.rs b/tests/run-make/track-pgo-dep-info/rmake.rs index acfe05cf8ea3..f93085ad6460 100644 --- a/tests/run-make/track-pgo-dep-info/rmake.rs +++ b/tests/run-make/track-pgo-dep-info/rmake.rs @@ -8,7 +8,7 @@ // Reason: the binary is executed //@ needs-profiler-support -use run_make_support::{fs_wrapper, llvm_profdata, run, rustc}; +use run_make_support::{fs as rfs, llvm_profdata, run, rustc}; fn main() { // Generate the profile-guided-optimization (PGO) profiles @@ -19,5 +19,5 @@ fn main() { // Use the profiles in compilation rustc().profile_use("merged.profdata").emit("dep-info").input("main.rs").run(); // Check that the profile file is in the dep-info emit file - assert!(fs_wrapper::read_to_string("main.d").contains("merged.profdata")); + assert!(rfs::read_to_string("main.d").contains("merged.profdata")); } diff --git a/tests/run-make/volatile-intrinsics/rmake.rs b/tests/run-make/volatile-intrinsics/rmake.rs index fb9be4bb9ba2..fcadeafff398 100644 --- a/tests/run-make/volatile-intrinsics/rmake.rs +++ b/tests/run-make/volatile-intrinsics/rmake.rs @@ -1,6 +1,6 @@ //@ ignore-cross-compile -use run_make_support::fs_wrapper::read; +use run_make_support::fs as rfs; use run_make_support::{assert_contains, run, rustc}; fn main() { @@ -11,7 +11,7 @@ fn main() { // ... and the loads/stores must not be optimized out. rustc().input("main.rs").emit("llvm-ir").run(); - let raw_llvm_ir = read("main.ll"); + let raw_llvm_ir = rfs::read("main.ll"); let llvm_ir = String::from_utf8_lossy(&raw_llvm_ir); assert_contains(&llvm_ir, "load volatile"); assert_contains(&llvm_ir, "store volatile"); diff --git a/tests/run-make/wasm-custom-section/rmake.rs b/tests/run-make/wasm-custom-section/rmake.rs index e958f5086ac6..d22e4109945e 100644 --- a/tests/run-make/wasm-custom-section/rmake.rs +++ b/tests/run-make/wasm-custom-section/rmake.rs @@ -1,13 +1,13 @@ //@ only-wasm32-wasip1 -use run_make_support::{fs_wrapper, rustc, wasmparser}; +use run_make_support::{fs as rfs, rustc, wasmparser}; use std::collections::HashMap; fn main() { rustc().input("foo.rs").target("wasm32-wasip1").run(); rustc().input("bar.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); - let file = fs_wrapper::read("bar.wasm"); + let file = rfs::read("bar.wasm"); let mut custom = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { diff --git a/tests/run-make/wasm-custom-sections-opt/rmake.rs b/tests/run-make/wasm-custom-sections-opt/rmake.rs index 346cffecc774..db5a5a4849d5 100644 --- a/tests/run-make/wasm-custom-sections-opt/rmake.rs +++ b/tests/run-make/wasm-custom-sections-opt/rmake.rs @@ -1,6 +1,6 @@ //@ only-wasm32-wasip1 -use run_make_support::{fs_wrapper, rustc, wasmparser}; +use run_make_support::{fs as rfs, rustc, wasmparser}; use std::collections::HashMap; use std::path::Path; @@ -12,7 +12,7 @@ fn main() { fn verify(path: &Path) { eprintln!("verify {path:?}"); - let file = fs_wrapper::read(&path); + let file = rfs::read(&path); let mut custom = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { diff --git a/tests/run-make/wasm-export-all-symbols/rmake.rs b/tests/run-make/wasm-export-all-symbols/rmake.rs index 41a2eaaafc31..ba006f55f5b4 100644 --- a/tests/run-make/wasm-export-all-symbols/rmake.rs +++ b/tests/run-make/wasm-export-all-symbols/rmake.rs @@ -1,6 +1,6 @@ //@ only-wasm32-wasip1 -use run_make_support::{fs_wrapper, rustc, wasmparser}; +use run_make_support::{fs as rfs, rustc, wasmparser}; use std::collections::HashMap; use std::path::Path; use wasmparser::ExternalKind::*; @@ -33,7 +33,7 @@ fn test(args: &[&str]) { fn verify_exports(path: &Path, exports: &[(&str, wasmparser::ExternalKind)]) { println!("verify {path:?}"); - let file = fs_wrapper::read(path); + let file = rfs::read(path); let mut wasm_exports = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { let payload = payload.unwrap(); diff --git a/tests/run-make/wasm-import-module/rmake.rs b/tests/run-make/wasm-import-module/rmake.rs index 881242c59a27..5eb49c843489 100644 --- a/tests/run-make/wasm-import-module/rmake.rs +++ b/tests/run-make/wasm-import-module/rmake.rs @@ -1,6 +1,6 @@ //@ only-wasm32-wasip1 -use run_make_support::{fs_wrapper, rustc, wasmparser}; +use run_make_support::{fs as rfs, rustc, wasmparser}; use std::collections::HashMap; use wasmparser::TypeRef::Func; @@ -8,7 +8,7 @@ fn main() { rustc().input("foo.rs").target("wasm32-wasip1").run(); rustc().input("bar.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); - let file = fs_wrapper::read("bar.wasm"); + let file = rfs::read("bar.wasm"); let mut imports = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { diff --git a/tests/run-make/wasm-panic-small/rmake.rs b/tests/run-make/wasm-panic-small/rmake.rs index 891cac4bc9fb..5cc9c3411800 100644 --- a/tests/run-make/wasm-panic-small/rmake.rs +++ b/tests/run-make/wasm-panic-small/rmake.rs @@ -1,7 +1,7 @@ //@ only-wasm32-wasip1 #![deny(warnings)] -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{fs as rfs, rustc}; fn main() { test("a"); @@ -15,7 +15,7 @@ fn test(cfg: &str) { rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").opt().cfg(cfg).run(); - let bytes = fs_wrapper::read("foo.wasm"); + let bytes = rfs::read("foo.wasm"); println!("{}", bytes.len()); assert!(bytes.len() < 40_000); } diff --git a/tests/run-make/wasm-spurious-import/rmake.rs b/tests/run-make/wasm-spurious-import/rmake.rs index 88e4c83c94ca..520b1075dbac 100644 --- a/tests/run-make/wasm-spurious-import/rmake.rs +++ b/tests/run-make/wasm-spurious-import/rmake.rs @@ -1,6 +1,6 @@ //@ only-wasm32-wasip1 -use run_make_support::{fs_wrapper, rustc, wasmparser}; +use run_make_support::{fs as rfs, rustc, wasmparser}; use std::collections::HashMap; fn main() { @@ -13,7 +13,7 @@ fn main() { .arg("-Copt-level=z") .run(); - let file = fs_wrapper::read("main.wasm"); + let file = rfs::read("main.wasm"); let mut imports = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { diff --git a/tests/run-make/wasm-stringify-ints-small/rmake.rs b/tests/run-make/wasm-stringify-ints-small/rmake.rs index 42e415b3a862..26d968755e45 100644 --- a/tests/run-make/wasm-stringify-ints-small/rmake.rs +++ b/tests/run-make/wasm-stringify-ints-small/rmake.rs @@ -1,12 +1,12 @@ //@ only-wasm32-wasip1 #![deny(warnings)] -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{fs as rfs, rustc}; fn main() { rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); - let bytes = fs_wrapper::read("foo.wasm"); + let bytes = rfs::read("foo.wasm"); println!("{}", bytes.len()); assert!(bytes.len() < 50_000); } diff --git a/tests/run-make/wasm-symbols-different-module/rmake.rs b/tests/run-make/wasm-symbols-different-module/rmake.rs index 734f79d834a9..f21dd5886196 100644 --- a/tests/run-make/wasm-symbols-different-module/rmake.rs +++ b/tests/run-make/wasm-symbols-different-module/rmake.rs @@ -1,6 +1,6 @@ //@ only-wasm32-wasip1 -use run_make_support::{fs_wrapper, rustc, wasmparser}; +use run_make_support::{fs as rfs, rustc, wasmparser}; use std::collections::{HashMap, HashSet}; use std::path::Path; @@ -23,7 +23,7 @@ fn test(file: &str, args: &[&str], expected_imports: &[(&str, &[&str])]) { rustc().input(file).target("wasm32-wasip1").args(args).run(); - let file = fs_wrapper::read(Path::new(file).with_extension("wasm")); + let file = rfs::read(Path::new(file).with_extension("wasm")); let mut imports = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { diff --git a/tests/run-make/wasm-symbols-not-exported/rmake.rs b/tests/run-make/wasm-symbols-not-exported/rmake.rs index 4c817a6fd820..e744ac47c503 100644 --- a/tests/run-make/wasm-symbols-not-exported/rmake.rs +++ b/tests/run-make/wasm-symbols-not-exported/rmake.rs @@ -1,6 +1,6 @@ //@ only-wasm32-wasip1 -use run_make_support::{fs_wrapper, rustc, wasmparser}; +use run_make_support::{fs as rfs, rustc, wasmparser}; use std::path::Path; fn main() { @@ -17,7 +17,7 @@ fn main() { fn verify_symbols(path: &Path) { eprintln!("verify {path:?}"); - let file = fs_wrapper::read(&path); + let file = rfs::read(&path); for payload in wasmparser::Parser::new(0).parse_all(&file) { let payload = payload.unwrap(); diff --git a/tests/run-make/wasm-symbols-not-imported/rmake.rs b/tests/run-make/wasm-symbols-not-imported/rmake.rs index 58c9f9c6f45c..b0955e4f458a 100644 --- a/tests/run-make/wasm-symbols-not-imported/rmake.rs +++ b/tests/run-make/wasm-symbols-not-imported/rmake.rs @@ -1,6 +1,6 @@ //@ only-wasm32-wasip1 -use run_make_support::{fs_wrapper, rustc, wasmparser}; +use run_make_support::{fs as rfs, rustc, wasmparser}; use std::path::Path; fn main() { @@ -16,7 +16,7 @@ fn main() { fn verify_symbols(path: &Path) { eprintln!("verify {path:?}"); - let file = fs_wrapper::read(&path); + let file = rfs::read(&path); for payload in wasmparser::Parser::new(0).parse_all(&file) { let payload = payload.unwrap(); diff --git a/tests/run-make/weird-output-filenames/rmake.rs b/tests/run-make/weird-output-filenames/rmake.rs index ed331a0b8d4e..9f59f2961a21 100644 --- a/tests/run-make/weird-output-filenames/rmake.rs +++ b/tests/run-make/weird-output-filenames/rmake.rs @@ -1,4 +1,4 @@ -use run_make_support::fs_wrapper::copy; +use run_make_support::fs as rfs; use run_make_support::regex::Regex; use run_make_support::{cwd, rustc}; @@ -6,12 +6,12 @@ fn main() { let invalid_characters = [".foo.rs", ".foo.bar", "+foo+bar.rs"]; let re = Regex::new(r"invalid character.*in crate name:").unwrap(); for f in invalid_characters { - copy("foo.rs", f); + rfs::copy("foo.rs", f); let stderr = rustc().input(f).run_fail().stderr_utf8(); assert!(re.is_match(&stderr)); } - copy("foo.rs", "-foo.rs"); + rfs::copy("foo.rs", "-foo.rs"); rustc() .input(cwd().join("-foo.rs")) .run_fail() diff --git a/tests/run-make/windows-ws2_32/rmake.rs b/tests/run-make/windows-ws2_32/rmake.rs index fde59452bc55..41e92b702753 100644 --- a/tests/run-make/windows-ws2_32/rmake.rs +++ b/tests/run-make/windows-ws2_32/rmake.rs @@ -3,7 +3,7 @@ // Tests that WS2_32.dll is not unnecessarily linked, see issue #85441 use run_make_support::object::{self, read::Object}; -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{fs as rfs, rustc}; fn main() { rustc().input("empty.rs").run(); @@ -14,7 +14,7 @@ fn main() { } fn links_ws2_32(exe: &str) -> bool { - let binary_data = fs_wrapper::read(exe); + let binary_data = rfs::read(exe); let file = object::File::parse(&*binary_data).unwrap(); for import in file.imports().unwrap() { if import.library().eq_ignore_ascii_case(b"WS2_32.dll") { From 0dfecb3855aabafd14d6156f013b128c12ed7795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Wed, 17 Jul 2024 12:44:25 +0000 Subject: [PATCH 273/734] run_make_support: move some helpers from assertion to path --- .../run-make-support/src/assertion_helpers.rs | 50 +------------------ src/tools/run-make-support/src/lib.rs | 9 ++-- .../run-make-support/src/path_helpers.rs | 47 +++++++++++++++++ 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/tools/run-make-support/src/assertion_helpers.rs b/src/tools/run-make-support/src/assertion_helpers.rs index b57ac475e087..5fb9d0da494c 100644 --- a/src/tools/run-make-support/src/assertion_helpers.rs +++ b/src/tools/run-make-support/src/assertion_helpers.rs @@ -1,57 +1,9 @@ //! Collection of assertions and assertion-related helpers. use std::panic; -use std::path::{Path, PathBuf}; +use std::path::Path; use crate::fs as rfs; -use crate::path_helpers::cwd; - -/// Browse the directory `path` non-recursively and return all files which respect the parameters -/// outlined by `closure`. -#[track_caller] -pub fn shallow_find_files, F: Fn(&PathBuf) -> bool>( - path: P, - filter: F, -) -> Vec { - let mut matching_files = Vec::new(); - for entry in rfs::read_dir(path) { - let entry = entry.expect("failed to read directory entry."); - let path = entry.path(); - - if path.is_file() && filter(&path) { - matching_files.push(path); - } - } - matching_files -} - -/// Returns true if the filename at `path` starts with `prefix`. -pub fn has_prefix>(path: P, prefix: &str) -> bool { - path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().starts_with(prefix)) -} - -/// Returns true if the filename at `path` has the extension `extension`. -pub fn has_extension>(path: P, extension: &str) -> bool { - path.as_ref().extension().is_some_and(|ext| ext == extension) -} - -/// Returns true if the filename at `path` does not contain `expected`. -pub fn not_contains>(path: P, expected: &str) -> bool { - !path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().contains(expected)) -} - -/// Returns true if the filename at `path` is not in `expected`. -pub fn filename_not_in_denylist, V: AsRef<[String]>>(path: P, expected: V) -> bool { - let expected = expected.as_ref(); - path.as_ref() - .file_name() - .is_some_and(|name| !expected.contains(&name.to_str().unwrap().to_owned())) -} - -/// Returns true if the filename at `path` ends with `suffix`. -pub fn has_suffix>(path: P, suffix: &str) -> bool { - path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().ends_with(suffix)) -} /// Gathers all files in the current working directory that have the extension `ext`, and counts /// the number of lines within that contain a match with the regex pattern `re`. diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index ae34ecd8d972..f97e3dd5d8b2 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -61,14 +61,15 @@ pub use artifact_names::{ }; /// Path-related helpers. -pub use path_helpers::{cwd, path, source_root}; +pub use path_helpers::{ + cwd, filename_not_in_denylist, has_extension, has_prefix, has_suffix, not_contains, path, + shallow_find_files, source_root, +}; /// Helpers for scoped test execution where certain properties are attempted to be maintained. pub use scoped_run::{run_in_tmpdir, test_while_readonly}; pub use assertion_helpers::{ assert_contains, assert_equals, assert_not_contains, assert_recursive_eq, - count_regex_matches_in_files_with_extension, filename_not_in_denylist, has_extension, - has_prefix, has_suffix, invalid_utf8_contains, invalid_utf8_not_contains, not_contains, - shallow_find_files, + count_regex_matches_in_files_with_extension, invalid_utf8_contains, invalid_utf8_not_contains, }; diff --git a/src/tools/run-make-support/src/path_helpers.rs b/src/tools/run-make-support/src/path_helpers.rs index b29d8727d2b3..f37ea8dfef8c 100644 --- a/src/tools/run-make-support/src/path_helpers.rs +++ b/src/tools/run-make-support/src/path_helpers.rs @@ -31,3 +31,50 @@ pub fn path>(p: P) -> PathBuf { pub fn source_root() -> PathBuf { env_var("SOURCE_ROOT").into() } + +/// Browse the directory `path` non-recursively and return all files which respect the parameters +/// outlined by `closure`. +#[track_caller] +pub fn shallow_find_files, F: Fn(&PathBuf) -> bool>( + path: P, + filter: F, +) -> Vec { + let mut matching_files = Vec::new(); + for entry in std::fs::read_dir(path).unwrap() { + let entry = entry.expect("failed to read directory entry."); + let path = entry.path(); + + if path.is_file() && filter(&path) { + matching_files.push(path); + } + } + matching_files +} + +/// Returns true if the filename at `path` does not contain `expected`. +pub fn not_contains>(path: P, expected: &str) -> bool { + !path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().contains(expected)) +} + +/// Returns true if the filename at `path` is not in `expected`. +pub fn filename_not_in_denylist, V: AsRef<[String]>>(path: P, expected: V) -> bool { + let expected = expected.as_ref(); + path.as_ref() + .file_name() + .is_some_and(|name| !expected.contains(&name.to_str().unwrap().to_owned())) +} + +/// Returns true if the filename at `path` starts with `prefix`. +pub fn has_prefix>(path: P, prefix: &str) -> bool { + path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().starts_with(prefix)) +} + +/// Returns true if the filename at `path` has the extension `extension`. +pub fn has_extension>(path: P, extension: &str) -> bool { + path.as_ref().extension().is_some_and(|ext| ext == extension) +} + +/// Returns true if the filename at `path` ends with `suffix`. +pub fn has_suffix>(path: P, suffix: &str) -> bool { + path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().ends_with(suffix)) +} From 57a2f76557c3b4ea4ad0c40f1c9dc9c11ca9d289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Wed, 17 Jul 2024 12:52:57 +0000 Subject: [PATCH 274/734] run_make_support: moved some helpers into `string` module --- .../run-make-support/src/assertion_helpers.rs | 46 ----------------- src/tools/run-make-support/src/lib.rs | 4 ++ src/tools/run-make-support/src/string.rs | 50 +++++++++++++++++++ 3 files changed, 54 insertions(+), 46 deletions(-) create mode 100644 src/tools/run-make-support/src/string.rs diff --git a/src/tools/run-make-support/src/assertion_helpers.rs b/src/tools/run-make-support/src/assertion_helpers.rs index 5fb9d0da494c..844c2d477aa8 100644 --- a/src/tools/run-make-support/src/assertion_helpers.rs +++ b/src/tools/run-make-support/src/assertion_helpers.rs @@ -5,52 +5,6 @@ use std::path::Path; use crate::fs as rfs; -/// Gathers all files in the current working directory that have the extension `ext`, and counts -/// the number of lines within that contain a match with the regex pattern `re`. -pub fn count_regex_matches_in_files_with_extension(re: ®ex::Regex, ext: &str) -> usize { - let fetched_files = shallow_find_files(cwd(), |path| has_extension(path, ext)); - - let mut count = 0; - for file in fetched_files { - let content = rfs::read_to_string(file); - count += content.lines().filter(|line| re.is_match(&line)).count(); - } - - count -} - -/// Read the contents of a file that cannot simply be read by -/// [`read_to_string`][crate::fs::read_to_string], due to invalid UTF-8 data, then assert -/// that it contains `expected`. -#[track_caller] -pub fn invalid_utf8_contains, S: AsRef>(path: P, expected: S) { - let buffer = rfs::read(path.as_ref()); - let expected = expected.as_ref(); - if !String::from_utf8_lossy(&buffer).contains(expected) { - eprintln!("=== FILE CONTENTS (LOSSY) ==="); - eprintln!("{}", String::from_utf8_lossy(&buffer)); - eprintln!("=== SPECIFIED TEXT ==="); - eprintln!("{}", expected); - panic!("specified text was not found in file"); - } -} - -/// Read the contents of a file that cannot simply be read by -/// [`read_to_string`][crate::fs::read_to_string], due to invalid UTF-8 data, then assert -/// that it does not contain `expected`. -#[track_caller] -pub fn invalid_utf8_not_contains, S: AsRef>(path: P, expected: S) { - let buffer = rfs::read(path.as_ref()); - let expected = expected.as_ref(); - if String::from_utf8_lossy(&buffer).contains(expected) { - eprintln!("=== FILE CONTENTS (LOSSY) ==="); - eprintln!("{}", String::from_utf8_lossy(&buffer)); - eprintln!("=== SPECIFIED TEXT ==="); - eprintln!("{}", expected); - panic!("specified text was unexpectedly found in file"); - } -} - /// Assert that `actual` is equal to `expected`. #[track_caller] pub fn assert_equals, E: AsRef>(actual: A, expected: E) { diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index f97e3dd5d8b2..3dbc2d201ffa 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -16,6 +16,7 @@ pub mod fs; pub mod path_helpers; pub mod run; pub mod scoped_run; +pub mod string; pub mod targets; // Re-exports of third-party library crates. @@ -71,5 +72,8 @@ pub use scoped_run::{run_in_tmpdir, test_while_readonly}; pub use assertion_helpers::{ assert_contains, assert_equals, assert_not_contains, assert_recursive_eq, +}; + +pub use string::{ count_regex_matches_in_files_with_extension, invalid_utf8_contains, invalid_utf8_not_contains, }; diff --git a/src/tools/run-make-support/src/string.rs b/src/tools/run-make-support/src/string.rs new file mode 100644 index 000000000000..f0b1e2334d8b --- /dev/null +++ b/src/tools/run-make-support/src/string.rs @@ -0,0 +1,50 @@ +use std::path::Path; + +use crate::fs as rfs; +use crate::path_helpers::{cwd, has_extension, shallow_find_files}; + +/// Gathers all files in the current working directory that have the extension `ext`, and counts +/// the number of lines within that contain a match with the regex pattern `re`. +pub fn count_regex_matches_in_files_with_extension(re: ®ex::Regex, ext: &str) -> usize { + let fetched_files = shallow_find_files(cwd(), |path| has_extension(path, ext)); + + let mut count = 0; + for file in fetched_files { + let content = rfs::read_to_string(file); + count += content.lines().filter(|line| re.is_match(&line)).count(); + } + + count +} + +/// Read the contents of a file that cannot simply be read by +/// [`read_to_string`][crate::fs::read_to_string], due to invalid UTF-8 data, then assert +/// that it contains `expected`. +#[track_caller] +pub fn invalid_utf8_contains, S: AsRef>(path: P, expected: S) { + let buffer = rfs::read(path.as_ref()); + let expected = expected.as_ref(); + if !String::from_utf8_lossy(&buffer).contains(expected) { + eprintln!("=== FILE CONTENTS (LOSSY) ==="); + eprintln!("{}", String::from_utf8_lossy(&buffer)); + eprintln!("=== SPECIFIED TEXT ==="); + eprintln!("{}", expected); + panic!("specified text was not found in file"); + } +} + +/// Read the contents of a file that cannot simply be read by +/// [`read_to_string`][crate::fs::read_to_string], due to invalid UTF-8 data, then assert +/// that it does not contain `expected`. +#[track_caller] +pub fn invalid_utf8_not_contains, S: AsRef>(path: P, expected: S) { + let buffer = rfs::read(path.as_ref()); + let expected = expected.as_ref(); + if String::from_utf8_lossy(&buffer).contains(expected) { + eprintln!("=== FILE CONTENTS (LOSSY) ==="); + eprintln!("{}", String::from_utf8_lossy(&buffer)); + eprintln!("=== SPECIFIED TEXT ==="); + eprintln!("{}", expected); + panic!("specified text was unexpectedly found in file"); + } +} From 30bdc4a30994beb338f9ab6589fd992082b3f0af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Wed, 17 Jul 2024 13:01:54 +0000 Subject: [PATCH 275/734] run_make_support: rename `assert_recursive_eq` to `assert_dirs_are_equal` --- src/tools/run-make-support/src/assertion_helpers.rs | 4 ++-- src/tools/run-make-support/src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/run-make-support/src/assertion_helpers.rs b/src/tools/run-make-support/src/assertion_helpers.rs index 844c2d477aa8..07992afc4b96 100644 --- a/src/tools/run-make-support/src/assertion_helpers.rs +++ b/src/tools/run-make-support/src/assertion_helpers.rs @@ -48,12 +48,12 @@ pub fn assert_not_contains, N: AsRef>(haystack: H, needle: N) } /// Assert that all files in `dir1` exist and have the same content in `dir2` -pub fn assert_recursive_eq(dir1: impl AsRef, dir2: impl AsRef) { +pub fn assert_dirs_are_equal(dir1: impl AsRef, dir2: impl AsRef) { let dir2 = dir2.as_ref(); rfs::read_dir_entries(dir1, |entry_path| { let entry_name = entry_path.file_name().unwrap(); if entry_path.is_dir() { - assert_recursive_eq(&entry_path, &dir2.join(entry_name)); + assert_dirs_are_equal(&entry_path, &dir2.join(entry_name)); } else { let path2 = dir2.join(entry_name); let file1 = rfs::read(&entry_path); diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 3dbc2d201ffa..1a5e6d092ec4 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -71,7 +71,7 @@ pub use path_helpers::{ pub use scoped_run::{run_in_tmpdir, test_while_readonly}; pub use assertion_helpers::{ - assert_contains, assert_equals, assert_not_contains, assert_recursive_eq, + assert_contains, assert_dirs_are_equal, assert_equals, assert_not_contains, }; pub use string::{ From a00b860bfcf552d0c09e56edd0bcb377b6b532b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Wed, 17 Jul 2024 13:02:34 +0000 Subject: [PATCH 276/734] tests: update rustdoc test for renamed `assert_dirs_are_equal` --- tests/run-make/rustdoc-verify-output-files/rmake.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-make/rustdoc-verify-output-files/rmake.rs b/tests/run-make/rustdoc-verify-output-files/rmake.rs index efcc47079bd1..940503bf85fb 100644 --- a/tests/run-make/rustdoc-verify-output-files/rmake.rs +++ b/tests/run-make/rustdoc-verify-output-files/rmake.rs @@ -1,7 +1,7 @@ use run_make_support::fs as rfs; use std::path::{Path, PathBuf}; -use run_make_support::{assert_recursive_eq, rustdoc}; +use run_make_support::{assert_dirs_are_equal, rustdoc}; #[derive(PartialEq)] enum JsonOutput { @@ -45,5 +45,5 @@ fn main() { // Check if all docs(including both json and html formats) are still the same after multiple // compilations. - assert_recursive_eq(&out_dir, &tmp_out_dir); + assert_dirs_are_equal(&out_dir, &tmp_out_dir); } From 1f1bf4c71b73351193fbcb0deff298b17884c9cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Wed, 17 Jul 2024 13:31:27 +0000 Subject: [PATCH 277/734] run_make_support: use `fs` internally, but `rfs` to tests --- .../run-make-support/src/assertion_helpers.rs | 8 ++++---- src/tools/run-make-support/src/diff/mod.rs | 16 +++++++++------- src/tools/run-make-support/src/lib.rs | 9 ++++++++- src/tools/run-make-support/src/scoped_run.rs | 12 ++++++------ src/tools/run-make-support/src/string.rs | 8 ++++---- 5 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/tools/run-make-support/src/assertion_helpers.rs b/src/tools/run-make-support/src/assertion_helpers.rs index 07992afc4b96..4b5b349431db 100644 --- a/src/tools/run-make-support/src/assertion_helpers.rs +++ b/src/tools/run-make-support/src/assertion_helpers.rs @@ -3,7 +3,7 @@ use std::panic; use std::path::Path; -use crate::fs as rfs; +use crate::fs; /// Assert that `actual` is equal to `expected`. #[track_caller] @@ -50,14 +50,14 @@ pub fn assert_not_contains, N: AsRef>(haystack: H, needle: N) /// Assert that all files in `dir1` exist and have the same content in `dir2` pub fn assert_dirs_are_equal(dir1: impl AsRef, dir2: impl AsRef) { let dir2 = dir2.as_ref(); - rfs::read_dir_entries(dir1, |entry_path| { + fs::read_dir_entries(dir1, |entry_path| { let entry_name = entry_path.file_name().unwrap(); if entry_path.is_dir() { assert_dirs_are_equal(&entry_path, &dir2.join(entry_name)); } else { let path2 = dir2.join(entry_name); - let file1 = rfs::read(&entry_path); - let file2 = rfs::read(&path2); + let file1 = fs::read(&entry_path); + let file2 = fs::read(&path2); // We don't use `assert_eq!` because they are `Vec`, so not great for display. // Why not using String? Because there might be minified files or even potentially diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs index 9f3548891192..ac6623316065 100644 --- a/src/tools/run-make-support/src/diff/mod.rs +++ b/src/tools/run-make-support/src/diff/mod.rs @@ -1,10 +1,12 @@ -use regex::Regex; -use similar::TextDiff; use std::path::{Path, PathBuf}; -use crate::fs as rfs; +use regex::Regex; +use similar::TextDiff; + use build_helper::drop_bomb::DropBomb; +use crate::fs; + #[cfg(test)] mod tests; @@ -43,7 +45,7 @@ impl Diff { /// Specify the expected output for the diff from a file. pub fn expected_file>(&mut self, path: P) -> &mut Self { let path = path.as_ref(); - let content = rfs::read_to_string(path); + let content = fs::read_to_string(path); let name = path.to_string_lossy().to_string(); self.expected_file = Some(path.into()); @@ -62,7 +64,7 @@ impl Diff { /// Specify the actual output for the diff from a file. pub fn actual_file>(&mut self, path: P) -> &mut Self { let path = path.as_ref(); - let content = rfs::read_to_string(path); + let content = fs::read_to_string(path); let name = path.to_string_lossy().to_string(); self.actual = Some(content); @@ -116,7 +118,7 @@ impl Diff { if let Some(ref expected_file) = self.expected_file { if std::env::var("RUSTC_BLESS_TEST").is_ok() { println!("Blessing `{}`", expected_file.display()); - rfs::write(expected_file, actual); + fs::write(expected_file, actual); return; } } @@ -138,7 +140,7 @@ impl Diff { if let Some(ref expected_file) = self.expected_file { if std::env::var("RUSTC_BLESS_TEST").is_ok() { println!("Blessing `{}`", expected_file.display()); - rfs::write(expected_file, actual); + fs::write(expected_file, actual); return; } } diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 1a5e6d092ec4..b15705e89658 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -12,13 +12,20 @@ pub mod assertion_helpers; pub mod diff; pub mod env; pub mod external_deps; -pub mod fs; pub mod path_helpers; pub mod run; pub mod scoped_run; pub mod string; pub mod targets; +mod fs; + +/// [`std::fs`] wrappers and assorted filesystem-related helpers. Public to tests as `rfs` to not be +/// confused with [`std::fs`]. +pub mod rfs { + pub use crate::fs::*; +} + // Re-exports of third-party library crates. pub use bstr; pub use gimli; diff --git a/src/tools/run-make-support/src/scoped_run.rs b/src/tools/run-make-support/src/scoped_run.rs index 63837e98904a..074a83922c5b 100644 --- a/src/tools/run-make-support/src/scoped_run.rs +++ b/src/tools/run-make-support/src/scoped_run.rs @@ -2,7 +2,7 @@ use std::path::Path; -use crate::fs as rfs; +use crate::fs; use crate::path_helpers::cwd; use crate::targets::is_windows; @@ -34,16 +34,16 @@ where ); panic!("`test_while_readonly` on directory detected while on Windows."); } - let metadata = rfs::metadata(&path); + let metadata = fs::metadata(&path); let original_perms = metadata.permissions(); let mut new_perms = original_perms.clone(); new_perms.set_readonly(true); - rfs::set_permissions(&path, new_perms); + fs::set_permissions(&path, new_perms); let success = std::panic::catch_unwind(closure); - rfs::set_permissions(&path, original_perms); + fs::set_permissions(&path, original_perms); success.unwrap(); } @@ -60,10 +60,10 @@ where pub fn run_in_tmpdir(callback: F) { let original_dir = cwd(); let tmpdir = original_dir.join("../temporary-directory"); - rfs::copy_dir_all(".", &tmpdir); + fs::copy_dir_all(".", &tmpdir); std::env::set_current_dir(&tmpdir).unwrap(); callback(); std::env::set_current_dir(original_dir).unwrap(); - rfs::remove_dir_all(tmpdir); + fs::remove_dir_all(tmpdir); } diff --git a/src/tools/run-make-support/src/string.rs b/src/tools/run-make-support/src/string.rs index f0b1e2334d8b..a79004b8ec6b 100644 --- a/src/tools/run-make-support/src/string.rs +++ b/src/tools/run-make-support/src/string.rs @@ -1,6 +1,6 @@ use std::path::Path; -use crate::fs as rfs; +use crate::fs; use crate::path_helpers::{cwd, has_extension, shallow_find_files}; /// Gathers all files in the current working directory that have the extension `ext`, and counts @@ -10,7 +10,7 @@ pub fn count_regex_matches_in_files_with_extension(re: ®ex::Regex, ext: &str) let mut count = 0; for file in fetched_files { - let content = rfs::read_to_string(file); + let content = fs::read_to_string(file); count += content.lines().filter(|line| re.is_match(&line)).count(); } @@ -22,7 +22,7 @@ pub fn count_regex_matches_in_files_with_extension(re: ®ex::Regex, ext: &str) /// that it contains `expected`. #[track_caller] pub fn invalid_utf8_contains, S: AsRef>(path: P, expected: S) { - let buffer = rfs::read(path.as_ref()); + let buffer = fs::read(path.as_ref()); let expected = expected.as_ref(); if !String::from_utf8_lossy(&buffer).contains(expected) { eprintln!("=== FILE CONTENTS (LOSSY) ==="); @@ -38,7 +38,7 @@ pub fn invalid_utf8_contains, S: AsRef>(path: P, expected: S /// that it does not contain `expected`. #[track_caller] pub fn invalid_utf8_not_contains, S: AsRef>(path: P, expected: S) { - let buffer = rfs::read(path.as_ref()); + let buffer = fs::read(path.as_ref()); let expected = expected.as_ref(); if String::from_utf8_lossy(&buffer).contains(expected) { eprintln!("=== FILE CONTENTS (LOSSY) ==="); From d69cc1ccbf9d25225add138a4b0f6ee424d0d59a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Wed, 17 Jul 2024 13:31:38 +0000 Subject: [PATCH 278/734] tests: update for `rfs` rename --- tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs | 2 +- tests/run-make/c-link-to-rust-dylib/rmake.rs | 2 +- tests/run-make/c-link-to-rust-staticlib/rmake.rs | 2 +- tests/run-make/cdylib/rmake.rs | 2 +- tests/run-make/comment-section/rmake.rs | 2 +- tests/run-make/compiler-builtins/rmake.rs | 2 +- tests/run-make/compiler-lookup-paths/rmake.rs | 2 +- tests/run-make/const-prop-lint/rmake.rs | 2 +- tests/run-make/crate-name-priority/rmake.rs | 2 +- tests/run-make/doctests-keep-binaries/rmake.rs | 2 +- tests/run-make/doctests-runtool/rmake.rs | 2 +- tests/run-make/dump-mono-stats/rmake.rs | 2 +- tests/run-make/dylib-chain/rmake.rs | 2 +- tests/run-make/emit-named-files/rmake.rs | 2 +- tests/run-make/emit-path-unhashed/rmake.rs | 2 +- tests/run-make/extern-flag-pathless/rmake.rs | 2 +- tests/run-make/extra-filename-with-temp-outputs/rmake.rs | 4 +--- tests/run-make/ice-dep-cannot-find-dep/rmake.rs | 2 +- tests/run-make/inaccessible-temp-dir/rmake.rs | 2 +- tests/run-make/incr-prev-body-beyond-eof/rmake.rs | 2 +- tests/run-make/incr-test-moved-file/rmake.rs | 2 +- tests/run-make/incremental-debugger-visualizer/rmake.rs | 2 +- tests/run-make/incremental-session-fail/rmake.rs | 2 +- tests/run-make/inline-always-many-cgu/rmake.rs | 2 +- tests/run-make/intrinsic-unreachable/rmake.rs | 2 +- tests/run-make/invalid-library/rmake.rs | 2 +- tests/run-make/invalid-so/rmake.rs | 2 +- tests/run-make/invalid-staticlib/rmake.rs | 2 +- tests/run-make/issue-107495-archive-permissions/rmake.rs | 2 +- tests/run-make/ls-metadata/rmake.rs | 2 +- tests/run-make/lto-readonly-lib/rmake.rs | 2 +- tests/run-make/many-crates-but-no-match/rmake.rs | 2 +- tests/run-make/mixing-libs/rmake.rs | 2 +- tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs | 2 +- tests/run-make/non-unicode-env/rmake.rs | 2 +- tests/run-make/non-unicode-in-incremental-dir/rmake.rs | 2 +- tests/run-make/obey-crate-type-flag/rmake.rs | 2 +- .../output-filename-conflicts-with-directory/rmake.rs | 2 +- tests/run-make/output-filename-overwrites-input/rmake.rs | 2 +- tests/run-make/output-type-permutations/rmake.rs | 2 +- tests/run-make/parallel-rustc-no-overwrite/rmake.rs | 2 +- tests/run-make/pgo-branch-weights/rmake.rs | 2 +- tests/run-make/pgo-use/rmake.rs | 2 +- tests/run-make/prefer-dylib/rmake.rs | 2 +- tests/run-make/prefer-rlib/rmake.rs | 2 +- tests/run-make/pretty-print-with-dep-file/rmake.rs | 2 +- tests/run-make/print-cfg/rmake.rs | 2 +- tests/run-make/print-to-output/rmake.rs | 2 +- tests/run-make/remap-path-prefix/rmake.rs | 2 +- tests/run-make/repr128-dwarf/rmake.rs | 2 +- tests/run-make/reset-codegen-1/rmake.rs | 2 +- tests/run-make/resolve-rename/rmake.rs | 2 +- tests/run-make/rlib-chain/rmake.rs | 2 +- tests/run-make/rustdoc-scrape-examples-remap/scrape.rs | 2 +- tests/run-make/rustdoc-test-args/rmake.rs | 2 +- tests/run-make/rustdoc-themes/rmake.rs | 2 +- tests/run-make/rustdoc-verify-output-files/rmake.rs | 2 +- tests/run-make/sepcomp-cci-copies/rmake.rs | 2 +- tests/run-make/sepcomp-inlining/rmake.rs | 2 +- tests/run-make/sepcomp-separate/rmake.rs | 2 +- tests/run-make/silly-file-names/rmake.rs | 2 +- tests/run-make/symlinked-extern/rmake.rs | 2 +- tests/run-make/symlinked-libraries/rmake.rs | 2 +- tests/run-make/symlinked-rlib/rmake.rs | 2 +- tests/run-make/target-specs/rmake.rs | 2 +- tests/run-make/track-path-dep-info/rmake.rs | 2 +- tests/run-make/track-pgo-dep-info/rmake.rs | 2 +- tests/run-make/volatile-intrinsics/rmake.rs | 2 +- tests/run-make/wasm-custom-section/rmake.rs | 2 +- tests/run-make/wasm-custom-sections-opt/rmake.rs | 2 +- tests/run-make/wasm-export-all-symbols/rmake.rs | 2 +- tests/run-make/wasm-import-module/rmake.rs | 2 +- tests/run-make/wasm-panic-small/rmake.rs | 2 +- tests/run-make/wasm-spurious-import/rmake.rs | 2 +- tests/run-make/wasm-stringify-ints-small/rmake.rs | 2 +- tests/run-make/wasm-symbols-different-module/rmake.rs | 2 +- tests/run-make/wasm-symbols-not-exported/rmake.rs | 2 +- tests/run-make/wasm-symbols-not-imported/rmake.rs | 2 +- tests/run-make/weird-output-filenames/rmake.rs | 2 +- tests/run-make/windows-ws2_32/rmake.rs | 2 +- 80 files changed, 80 insertions(+), 82 deletions(-) diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs index 5dd05f151df4..fec4a4bb90b3 100644 --- a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs +++ b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs @@ -5,7 +5,7 @@ use std::path::PathBuf; -use run_make_support::{aux_build, fs as rfs, rustc, source_root}; +use run_make_support::{aux_build, rfs, rustc, source_root}; fn main() { aux_build().input("stable.rs").emit("metadata").run(); diff --git a/tests/run-make/c-link-to-rust-dylib/rmake.rs b/tests/run-make/c-link-to-rust-dylib/rmake.rs index e4441ac0c3be..ab9aa445402b 100644 --- a/tests/run-make/c-link-to-rust-dylib/rmake.rs +++ b/tests/run-make/c-link-to-rust-dylib/rmake.rs @@ -3,7 +3,7 @@ //@ ignore-cross-compile -use run_make_support::{cc, cwd, dynamic_lib_extension, fs as rfs, is_msvc, run, run_fail, rustc}; +use run_make_support::{cc, cwd, dynamic_lib_extension, is_msvc, rfs, run, run_fail, rustc}; fn main() { rustc().input("foo.rs").run(); diff --git a/tests/run-make/c-link-to-rust-staticlib/rmake.rs b/tests/run-make/c-link-to-rust-staticlib/rmake.rs index 8c845f8b6f2d..ee35350da66a 100644 --- a/tests/run-make/c-link-to-rust-staticlib/rmake.rs +++ b/tests/run-make/c-link-to-rust-staticlib/rmake.rs @@ -3,7 +3,7 @@ //@ ignore-cross-compile -use run_make_support::fs::remove_file; +use run_make_support::rfs::remove_file; use run_make_support::{cc, extra_c_flags, run, rustc, static_lib_name}; use std::fs; diff --git a/tests/run-make/cdylib/rmake.rs b/tests/run-make/cdylib/rmake.rs index b6f2a9be0b22..21b83d1b1a91 100644 --- a/tests/run-make/cdylib/rmake.rs +++ b/tests/run-make/cdylib/rmake.rs @@ -10,7 +10,7 @@ //@ ignore-cross-compile -use run_make_support::{cc, cwd, dynamic_lib_name, fs as rfs, is_msvc, run, rustc}; +use run_make_support::{cc, cwd, dynamic_lib_name, is_msvc, rfs, run, rustc}; fn main() { rustc().input("bar.rs").run(); diff --git a/tests/run-make/comment-section/rmake.rs b/tests/run-make/comment-section/rmake.rs index f6978ab259dd..a16adea71626 100644 --- a/tests/run-make/comment-section/rmake.rs +++ b/tests/run-make/comment-section/rmake.rs @@ -9,8 +9,8 @@ use std::path::PathBuf; -use run_make_support::fs as rfs; use run_make_support::llvm_readobj; +use run_make_support::rfs; use run_make_support::rustc; use run_make_support::{cwd, env_var, run_in_tmpdir}; diff --git a/tests/run-make/compiler-builtins/rmake.rs b/tests/run-make/compiler-builtins/rmake.rs index b9dacdd0b905..43d1d69b245f 100644 --- a/tests/run-make/compiler-builtins/rmake.rs +++ b/tests/run-make/compiler-builtins/rmake.rs @@ -14,12 +14,12 @@ #![deny(warnings)] -use run_make_support::fs::{read, read_dir}; use run_make_support::object::read::archive::ArchiveFile; use run_make_support::object::read::Object; use run_make_support::object::ObjectSection; use run_make_support::object::ObjectSymbol; use run_make_support::object::RelocationTarget; +use run_make_support::rfs::{read, read_dir}; use run_make_support::{cmd, env_var, object}; use std::collections::HashSet; use std::path::PathBuf; diff --git a/tests/run-make/compiler-lookup-paths/rmake.rs b/tests/run-make/compiler-lookup-paths/rmake.rs index cfb7ef90ce43..3ffa6e0592f0 100644 --- a/tests/run-make/compiler-lookup-paths/rmake.rs +++ b/tests/run-make/compiler-lookup-paths/rmake.rs @@ -9,7 +9,7 @@ //@ ignore-wasm64 // Reason: a C compiler is required for build_native_static_lib -use run_make_support::{build_native_static_lib, fs as rfs, rustc, static_lib_name}; +use run_make_support::{build_native_static_lib, rfs, rustc, static_lib_name}; fn main() { build_native_static_lib("native"); diff --git a/tests/run-make/const-prop-lint/rmake.rs b/tests/run-make/const-prop-lint/rmake.rs index 25d9ccad4177..17e4b0c77f35 100644 --- a/tests/run-make/const-prop-lint/rmake.rs +++ b/tests/run-make/const-prop-lint/rmake.rs @@ -1,6 +1,6 @@ // Tests that const prop lints interrupting codegen don't leave `.o` files around. -use run_make_support::{cwd, fs as rfs, rustc}; +use run_make_support::{cwd, rfs, rustc}; fn main() { rustc().input("input.rs").run_fail().assert_exit_code(1); diff --git a/tests/run-make/crate-name-priority/rmake.rs b/tests/run-make/crate-name-priority/rmake.rs index c0cc8bdfdbfa..5bdb49b33cea 100644 --- a/tests/run-make/crate-name-priority/rmake.rs +++ b/tests/run-make/crate-name-priority/rmake.rs @@ -4,7 +4,7 @@ // and the compiler flags, and checks that the flag is favoured each time. // See https://github.com/rust-lang/rust/pull/15518 -use run_make_support::{bin_name, fs as rfs, rustc}; +use run_make_support::{bin_name, rfs, rustc}; fn main() { rustc().input("foo.rs").run(); diff --git a/tests/run-make/doctests-keep-binaries/rmake.rs b/tests/run-make/doctests-keep-binaries/rmake.rs index 35b29f21a5ab..6bff5c0c8d04 100644 --- a/tests/run-make/doctests-keep-binaries/rmake.rs +++ b/tests/run-make/doctests-keep-binaries/rmake.rs @@ -1,7 +1,7 @@ // Check that valid binaries are persisted by running them, regardless of whether the // --run or --no-run option is used. -use run_make_support::fs::{create_dir, remove_dir_all}; +use run_make_support::rfs::{create_dir, remove_dir_all}; use run_make_support::{run, rustc, rustdoc}; use std::path::Path; diff --git a/tests/run-make/doctests-runtool/rmake.rs b/tests/run-make/doctests-runtool/rmake.rs index 979c3ea7d2c1..5d829b9e88bc 100644 --- a/tests/run-make/doctests-runtool/rmake.rs +++ b/tests/run-make/doctests-runtool/rmake.rs @@ -1,6 +1,6 @@ // Tests behavior of rustdoc `--runtool`. -use run_make_support::fs::{create_dir, remove_dir_all}; +use run_make_support::rfs::{create_dir, remove_dir_all}; use run_make_support::{rustc, rustdoc}; use std::path::PathBuf; diff --git a/tests/run-make/dump-mono-stats/rmake.rs b/tests/run-make/dump-mono-stats/rmake.rs index 05a5b559e6dd..f4142e0a31c3 100644 --- a/tests/run-make/dump-mono-stats/rmake.rs +++ b/tests/run-make/dump-mono-stats/rmake.rs @@ -4,7 +4,7 @@ // a specific expected string. // See https://github.com/rust-lang/rust/pull/105481 -use run_make_support::{cwd, fs as rfs, rustc}; +use run_make_support::{cwd, rfs, rustc}; fn main() { rustc() diff --git a/tests/run-make/dylib-chain/rmake.rs b/tests/run-make/dylib-chain/rmake.rs index 63ae2f01ce40..54d53d470920 100644 --- a/tests/run-make/dylib-chain/rmake.rs +++ b/tests/run-make/dylib-chain/rmake.rs @@ -8,7 +8,7 @@ //@ ignore-cross-compile // Reason: the compiled binary is executed -use run_make_support::{dynamic_lib_name, fs as rfs, run, run_fail, rustc}; +use run_make_support::{dynamic_lib_name, rfs, run, run_fail, rustc}; fn main() { rustc().input("m1.rs").arg("-Cprefer-dynamic").run(); diff --git a/tests/run-make/emit-named-files/rmake.rs b/tests/run-make/emit-named-files/rmake.rs index 0cf743fc7d43..1570e1adc256 100644 --- a/tests/run-make/emit-named-files/rmake.rs +++ b/tests/run-make/emit-named-files/rmake.rs @@ -1,6 +1,6 @@ use std::path::Path; -use run_make_support::{fs as rfs, rustc}; +use run_make_support::{rfs, rustc}; fn emit_and_check(out_dir: &Path, out_file: &str, format: &str) { let out_file = out_dir.join(out_file); diff --git a/tests/run-make/emit-path-unhashed/rmake.rs b/tests/run-make/emit-path-unhashed/rmake.rs index 0d0ad1b91670..a97153e37dd9 100644 --- a/tests/run-make/emit-path-unhashed/rmake.rs +++ b/tests/run-make/emit-path-unhashed/rmake.rs @@ -6,7 +6,7 @@ // adding a new output type (in this test, metadata). // See https://github.com/rust-lang/rust/issues/86044 -use run_make_support::{diff, fs as rfs, rustc}; +use run_make_support::{diff, rfs, rustc}; fn main() { rfs::create_dir("emit"); diff --git a/tests/run-make/extern-flag-pathless/rmake.rs b/tests/run-make/extern-flag-pathless/rmake.rs index bdc8b3e2c999..ec380feae462 100644 --- a/tests/run-make/extern-flag-pathless/rmake.rs +++ b/tests/run-make/extern-flag-pathless/rmake.rs @@ -8,7 +8,7 @@ //@ ignore-cross-compile // Reason: the compiled binary is executed -use run_make_support::{dynamic_lib_name, fs as rfs, run, run_fail, rust_lib_name, rustc}; +use run_make_support::{dynamic_lib_name, rfs, run, run_fail, rust_lib_name, rustc}; fn main() { rustc().input("bar.rs").crate_type("rlib").crate_type("dylib").arg("-Cprefer-dynamic").run(); diff --git a/tests/run-make/extra-filename-with-temp-outputs/rmake.rs b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs index d7b865f81699..0910045bb857 100644 --- a/tests/run-make/extra-filename-with-temp-outputs/rmake.rs +++ b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs @@ -6,9 +6,7 @@ // are named as expected. // See https://github.com/rust-lang/rust/pull/15686 -use run_make_support::{ - bin_name, cwd, fs as rfs, has_prefix, has_suffix, rustc, shallow_find_files, -}; +use run_make_support::{bin_name, cwd, has_prefix, has_suffix, rfs, rustc, shallow_find_files}; fn main() { rustc().extra_filename("bar").input("foo.rs").arg("-Csave-temps").run(); diff --git a/tests/run-make/ice-dep-cannot-find-dep/rmake.rs b/tests/run-make/ice-dep-cannot-find-dep/rmake.rs index b4210eb5f3bc..8ba3a0366b00 100644 --- a/tests/run-make/ice-dep-cannot-find-dep/rmake.rs +++ b/tests/run-make/ice-dep-cannot-find-dep/rmake.rs @@ -16,7 +16,7 @@ // If we used `rustc` the additional '-L rmake_out' option would allow rustc to // actually find the crate. -use run_make_support::{bare_rustc, fs as rfs, rust_lib_name, rustc}; +use run_make_support::{bare_rustc, rfs, rust_lib_name, rustc}; fn main() { rustc().crate_name("a").crate_type("rlib").input("a.rs").arg("--verbose").run(); diff --git a/tests/run-make/inaccessible-temp-dir/rmake.rs b/tests/run-make/inaccessible-temp-dir/rmake.rs index 4fbd207975c5..b6624f37f962 100644 --- a/tests/run-make/inaccessible-temp-dir/rmake.rs +++ b/tests/run-make/inaccessible-temp-dir/rmake.rs @@ -24,7 +24,7 @@ // Reason: `set_readonly` has no effect on directories // and does not prevent modification. -use run_make_support::{fs as rfs, rustc, test_while_readonly}; +use run_make_support::{rfs, rustc, test_while_readonly}; fn main() { // Create an inaccessible directory. diff --git a/tests/run-make/incr-prev-body-beyond-eof/rmake.rs b/tests/run-make/incr-prev-body-beyond-eof/rmake.rs index ae74f120ce39..14e75671df8a 100644 --- a/tests/run-make/incr-prev-body-beyond-eof/rmake.rs +++ b/tests/run-make/incr-prev-body-beyond-eof/rmake.rs @@ -13,7 +13,7 @@ //@ ignore-nvptx64-nvidia-cuda // FIXME: can't find crate for `std` -use run_make_support::fs as rfs; +use run_make_support::rfs; use run_make_support::rustc; fn main() { diff --git a/tests/run-make/incr-test-moved-file/rmake.rs b/tests/run-make/incr-test-moved-file/rmake.rs index c4fc3d37526e..f314e110a8c3 100644 --- a/tests/run-make/incr-test-moved-file/rmake.rs +++ b/tests/run-make/incr-test-moved-file/rmake.rs @@ -14,7 +14,7 @@ //@ ignore-nvptx64-nvidia-cuda // FIXME: can't find crate for 'std' -use run_make_support::{fs as rfs, rust_lib_name, rustc}; +use run_make_support::{rfs, rust_lib_name, rustc}; fn main() { rfs::create_dir("incr"); diff --git a/tests/run-make/incremental-debugger-visualizer/rmake.rs b/tests/run-make/incremental-debugger-visualizer/rmake.rs index da9f9d41ee81..985816ff5d70 100644 --- a/tests/run-make/incremental-debugger-visualizer/rmake.rs +++ b/tests/run-make/incremental-debugger-visualizer/rmake.rs @@ -2,7 +2,7 @@ // (in this case, foo.py and foo.natvis) are picked up when compiling incrementally. // See https://github.com/rust-lang/rust/pull/111641 -use run_make_support::{fs as rfs, invalid_utf8_contains, invalid_utf8_not_contains, rustc}; +use run_make_support::{invalid_utf8_contains, invalid_utf8_not_contains, rfs, rustc}; use std::io::Read; fn main() { diff --git a/tests/run-make/incremental-session-fail/rmake.rs b/tests/run-make/incremental-session-fail/rmake.rs index 22ff1e2a8a4d..c6927c8a9f16 100644 --- a/tests/run-make/incremental-session-fail/rmake.rs +++ b/tests/run-make/incremental-session-fail/rmake.rs @@ -4,7 +4,7 @@ // the ensuing compilation failure is not an ICE. // See https://github.com/rust-lang/rust/pull/85698 -use run_make_support::{fs as rfs, rustc}; +use run_make_support::{rfs, rustc}; fn main() { rfs::create_file("session"); diff --git a/tests/run-make/inline-always-many-cgu/rmake.rs b/tests/run-make/inline-always-many-cgu/rmake.rs index 3b51bb1cd81a..5a6929c855b2 100644 --- a/tests/run-make/inline-always-many-cgu/rmake.rs +++ b/tests/run-make/inline-always-many-cgu/rmake.rs @@ -1,5 +1,5 @@ -use run_make_support::fs as rfs; use run_make_support::regex::Regex; +use run_make_support::rfs; use run_make_support::rustc; use std::ffi::OsStr; diff --git a/tests/run-make/intrinsic-unreachable/rmake.rs b/tests/run-make/intrinsic-unreachable/rmake.rs index 34f7ab3fbc8a..bb189fbdcb5d 100644 --- a/tests/run-make/intrinsic-unreachable/rmake.rs +++ b/tests/run-make/intrinsic-unreachable/rmake.rs @@ -8,7 +8,7 @@ //@ ignore-windows // Reason: Because of Windows exception handling, the code is not necessarily any shorter. -use run_make_support::{fs as rfs, rustc}; +use run_make_support::{rfs, rustc}; fn main() { rustc().opt().emit("asm").input("exit-ret.rs").run(); diff --git a/tests/run-make/invalid-library/rmake.rs b/tests/run-make/invalid-library/rmake.rs index 3961e2b846bd..42afb74a59ef 100644 --- a/tests/run-make/invalid-library/rmake.rs +++ b/tests/run-make/invalid-library/rmake.rs @@ -4,7 +4,7 @@ // one appearing in stderr in this scenario. // See https://github.com/rust-lang/rust/pull/12645 -use run_make_support::fs as rfs; +use run_make_support::rfs; use run_make_support::{llvm_ar, rustc}; fn main() { diff --git a/tests/run-make/invalid-so/rmake.rs b/tests/run-make/invalid-so/rmake.rs index c79e0563bada..754c53a49b92 100644 --- a/tests/run-make/invalid-so/rmake.rs +++ b/tests/run-make/invalid-so/rmake.rs @@ -4,7 +4,7 @@ // explains that the file exists, but that its metadata is incorrect. // See https://github.com/rust-lang/rust/pull/88368 -use run_make_support::{dynamic_lib_name, fs as rfs, rustc}; +use run_make_support::{dynamic_lib_name, rfs, rustc}; fn main() { rfs::create_file(dynamic_lib_name("foo")); diff --git a/tests/run-make/invalid-staticlib/rmake.rs b/tests/run-make/invalid-staticlib/rmake.rs index e31dcdec95bd..ba9e07dd07b8 100644 --- a/tests/run-make/invalid-staticlib/rmake.rs +++ b/tests/run-make/invalid-staticlib/rmake.rs @@ -4,7 +4,7 @@ // an internal compiler error (ICE). // See https://github.com/rust-lang/rust/pull/28673 -use run_make_support::{fs as rfs, rustc, static_lib_name}; +use run_make_support::{rfs, rustc, static_lib_name}; fn main() { rfs::create_file(static_lib_name("foo")); diff --git a/tests/run-make/issue-107495-archive-permissions/rmake.rs b/tests/run-make/issue-107495-archive-permissions/rmake.rs index 78d57d57afbe..f47b8d7190f2 100644 --- a/tests/run-make/issue-107495-archive-permissions/rmake.rs +++ b/tests/run-make/issue-107495-archive-permissions/rmake.rs @@ -3,7 +3,7 @@ #[cfg(unix)] extern crate libc; -use run_make_support::{aux_build, fs as rfs}; +use run_make_support::{aux_build, rfs}; #[cfg(unix)] use std::os::unix::fs::PermissionsExt; diff --git a/tests/run-make/ls-metadata/rmake.rs b/tests/run-make/ls-metadata/rmake.rs index 8a2d79ed3af3..45299a48c110 100644 --- a/tests/run-make/ls-metadata/rmake.rs +++ b/tests/run-make/ls-metadata/rmake.rs @@ -6,7 +6,7 @@ //@ ignore-cross-compile -use run_make_support::fs as rfs; +use run_make_support::rfs; use run_make_support::rustc; fn main() { diff --git a/tests/run-make/lto-readonly-lib/rmake.rs b/tests/run-make/lto-readonly-lib/rmake.rs index 5e06aeb73b60..d0ba3fb37a20 100644 --- a/tests/run-make/lto-readonly-lib/rmake.rs +++ b/tests/run-make/lto-readonly-lib/rmake.rs @@ -7,7 +7,7 @@ //@ ignore-cross-compile -use run_make_support::fs as rfs; +use run_make_support::rfs; use run_make_support::{run, rust_lib_name, rustc, test_while_readonly}; fn main() { diff --git a/tests/run-make/many-crates-but-no-match/rmake.rs b/tests/run-make/many-crates-but-no-match/rmake.rs index 7f8f93346d79..938ffce6a036 100644 --- a/tests/run-make/many-crates-but-no-match/rmake.rs +++ b/tests/run-make/many-crates-but-no-match/rmake.rs @@ -4,7 +4,7 @@ // what should be done to fix the issue. // See https://github.com/rust-lang/rust/issues/13266 -use run_make_support::{fs as rfs, rustc}; +use run_make_support::{rfs, rustc}; fn main() { rfs::create_dir("a1"); diff --git a/tests/run-make/mixing-libs/rmake.rs b/tests/run-make/mixing-libs/rmake.rs index 6799a93fbc12..89fbf5589e3b 100644 --- a/tests/run-make/mixing-libs/rmake.rs +++ b/tests/run-make/mixing-libs/rmake.rs @@ -6,7 +6,7 @@ //@ ignore-cross-compile -use run_make_support::{dynamic_lib_name, fs as rfs, rustc}; +use run_make_support::{dynamic_lib_name, rfs, rustc}; fn main() { rustc().input("rlib.rs").crate_type("rlib").crate_type("dylib").run(); diff --git a/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs b/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs index 2fd602270646..f63146e692ac 100644 --- a/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs +++ b/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs @@ -17,7 +17,7 @@ //@ ignore-nvptx64-nvidia-cuda // FIXME: can't find crate for 'std' -use run_make_support::{fs as rfs, rust_lib_name, rustc}; +use run_make_support::{rfs, rust_lib_name, rustc}; fn main() { rfs::create_dir("incr"); diff --git a/tests/run-make/non-unicode-env/rmake.rs b/tests/run-make/non-unicode-env/rmake.rs index f23fef88dabc..0042e4d1e173 100644 --- a/tests/run-make/non-unicode-env/rmake.rs +++ b/tests/run-make/non-unicode-env/rmake.rs @@ -1,4 +1,4 @@ -use run_make_support::fs as rfs; +use run_make_support::rfs; use run_make_support::rustc; fn main() { diff --git a/tests/run-make/non-unicode-in-incremental-dir/rmake.rs b/tests/run-make/non-unicode-in-incremental-dir/rmake.rs index d0d730d17ebb..ef316f110363 100644 --- a/tests/run-make/non-unicode-in-incremental-dir/rmake.rs +++ b/tests/run-make/non-unicode-in-incremental-dir/rmake.rs @@ -1,4 +1,4 @@ -use run_make_support::{fs as rfs, rustc}; +use run_make_support::{rfs, rustc}; fn main() { #[cfg(unix)] diff --git a/tests/run-make/obey-crate-type-flag/rmake.rs b/tests/run-make/obey-crate-type-flag/rmake.rs index 198eb6931589..8d6eb237982e 100644 --- a/tests/run-make/obey-crate-type-flag/rmake.rs +++ b/tests/run-make/obey-crate-type-flag/rmake.rs @@ -6,7 +6,7 @@ //@ ignore-cross-compile use run_make_support::{ - cwd, dynamic_lib_name, fs as rfs, has_extension, rust_lib_name, rustc, shallow_find_files, + cwd, dynamic_lib_name, has_extension, rfs, rust_lib_name, rustc, shallow_find_files, }; use std::path::Path; diff --git a/tests/run-make/output-filename-conflicts-with-directory/rmake.rs b/tests/run-make/output-filename-conflicts-with-directory/rmake.rs index 6df9628a9fb7..e49b5005fa06 100644 --- a/tests/run-make/output-filename-conflicts-with-directory/rmake.rs +++ b/tests/run-make/output-filename-conflicts-with-directory/rmake.rs @@ -4,7 +4,7 @@ // potentially-confusing linker error. // See https://github.com/rust-lang/rust/pull/47203 -use run_make_support::{fs as rfs, rustc}; +use run_make_support::{rfs, rustc}; fn main() { rfs::create_dir("foo"); diff --git a/tests/run-make/output-filename-overwrites-input/rmake.rs b/tests/run-make/output-filename-overwrites-input/rmake.rs index 0e9c20b0468f..1fa12259fafa 100644 --- a/tests/run-make/output-filename-overwrites-input/rmake.rs +++ b/tests/run-make/output-filename-overwrites-input/rmake.rs @@ -4,7 +4,7 @@ //@ ignore-cross-compile -use run_make_support::{fs as rfs, rustc}; +use run_make_support::{rfs, rustc}; fn main() { rfs::copy("foo.rs", "foo"); diff --git a/tests/run-make/output-type-permutations/rmake.rs b/tests/run-make/output-type-permutations/rmake.rs index a4d2601260b4..c51b2153945f 100644 --- a/tests/run-make/output-type-permutations/rmake.rs +++ b/tests/run-make/output-type-permutations/rmake.rs @@ -5,7 +5,7 @@ // See https://github.com/rust-lang/rust/pull/12020 use run_make_support::{ - bin_name, dynamic_lib_name, filename_not_in_denylist, fs as rfs, rust_lib_name, rustc, + bin_name, dynamic_lib_name, filename_not_in_denylist, rfs, rust_lib_name, rustc, shallow_find_files, static_lib_name, }; use std::path::PathBuf; diff --git a/tests/run-make/parallel-rustc-no-overwrite/rmake.rs b/tests/run-make/parallel-rustc-no-overwrite/rmake.rs index 9c224ad05b21..3f412bfefc8d 100644 --- a/tests/run-make/parallel-rustc-no-overwrite/rmake.rs +++ b/tests/run-make/parallel-rustc-no-overwrite/rmake.rs @@ -5,7 +5,7 @@ // conflicts. This test uses this flag and checks for successful compilation. // See https://github.com/rust-lang/rust/pull/83846 -use run_make_support::{fs as rfs, rustc}; +use run_make_support::{rfs, rustc}; use std::sync::{Arc, Barrier}; use std::thread; diff --git a/tests/run-make/pgo-branch-weights/rmake.rs b/tests/run-make/pgo-branch-weights/rmake.rs index 0915fe0e2a29..588c5c6dc31c 100644 --- a/tests/run-make/pgo-branch-weights/rmake.rs +++ b/tests/run-make/pgo-branch-weights/rmake.rs @@ -10,7 +10,7 @@ //@ needs-profiler-support //@ ignore-cross-compile -use run_make_support::{fs as rfs, llvm_filecheck, llvm_profdata, run_with_args, rustc}; +use run_make_support::{llvm_filecheck, llvm_profdata, rfs, run_with_args, rustc}; use std::path::Path; fn main() { diff --git a/tests/run-make/pgo-use/rmake.rs b/tests/run-make/pgo-use/rmake.rs index f53ea79102cb..cad49372266e 100644 --- a/tests/run-make/pgo-use/rmake.rs +++ b/tests/run-make/pgo-use/rmake.rs @@ -9,7 +9,7 @@ //@ ignore-cross-compile use run_make_support::{ - cwd, fs as rfs, has_extension, has_prefix, llvm_filecheck, llvm_profdata, run_with_args, rustc, + cwd, has_extension, has_prefix, llvm_filecheck, llvm_profdata, rfs, run_with_args, rustc, shallow_find_files, }; diff --git a/tests/run-make/prefer-dylib/rmake.rs b/tests/run-make/prefer-dylib/rmake.rs index 0fed3e872595..264d184a6c70 100644 --- a/tests/run-make/prefer-dylib/rmake.rs +++ b/tests/run-make/prefer-dylib/rmake.rs @@ -1,6 +1,6 @@ //@ ignore-cross-compile -use run_make_support::{dynamic_lib_name, fs as rfs, run, run_fail, rustc}; +use run_make_support::{dynamic_lib_name, rfs, run, run_fail, rustc}; fn main() { rustc().input("bar.rs").crate_type("dylib").crate_type("rlib").arg("-Cprefer-dynamic").run(); diff --git a/tests/run-make/prefer-rlib/rmake.rs b/tests/run-make/prefer-rlib/rmake.rs index 188db7c06028..6d38282c2e39 100644 --- a/tests/run-make/prefer-rlib/rmake.rs +++ b/tests/run-make/prefer-rlib/rmake.rs @@ -3,7 +3,7 @@ //@ ignore-cross-compile -use run_make_support::{dynamic_lib_name, fs as rfs, path, run, rust_lib_name, rustc}; +use run_make_support::{dynamic_lib_name, path, rfs, run, rust_lib_name, rustc}; fn main() { rustc().input("bar.rs").crate_type("dylib").crate_type("rlib").run(); diff --git a/tests/run-make/pretty-print-with-dep-file/rmake.rs b/tests/run-make/pretty-print-with-dep-file/rmake.rs index 4b3d1c34faea..d7a29ff7d19b 100644 --- a/tests/run-make/pretty-print-with-dep-file/rmake.rs +++ b/tests/run-make/pretty-print-with-dep-file/rmake.rs @@ -5,7 +5,7 @@ // does not get an unexpected dep-info file. // See https://github.com/rust-lang/rust/issues/112898 -use run_make_support::{fs as rfs, invalid_utf8_contains, rustc}; +use run_make_support::{invalid_utf8_contains, rfs, rustc}; use std::path::Path; fn main() { diff --git a/tests/run-make/print-cfg/rmake.rs b/tests/run-make/print-cfg/rmake.rs index 73a03189cb24..d83e8a36f2c0 100644 --- a/tests/run-make/print-cfg/rmake.rs +++ b/tests/run-make/print-cfg/rmake.rs @@ -10,7 +10,7 @@ use std::ffi::OsString; use std::iter::FromIterator; use std::path::PathBuf; -use run_make_support::{fs as rfs, rustc}; +use run_make_support::{rfs, rustc}; struct PrintCfg { target: &'static str, diff --git a/tests/run-make/print-to-output/rmake.rs b/tests/run-make/print-to-output/rmake.rs index ecfd84f81bb3..d0cba725b367 100644 --- a/tests/run-make/print-to-output/rmake.rs +++ b/tests/run-make/print-to-output/rmake.rs @@ -4,7 +4,7 @@ use std::ffi::OsString; use std::path::PathBuf; -use run_make_support::{fs as rfs, rustc, target}; +use run_make_support::{rfs, rustc, target}; struct Option<'a> { target: &'a str, diff --git a/tests/run-make/remap-path-prefix/rmake.rs b/tests/run-make/remap-path-prefix/rmake.rs index 390db93e62d1..aeb30e72d5bf 100644 --- a/tests/run-make/remap-path-prefix/rmake.rs +++ b/tests/run-make/remap-path-prefix/rmake.rs @@ -4,7 +4,7 @@ // See https://github.com/rust-lang/rust/pull/85344 use run_make_support::bstr::ByteSlice; -use run_make_support::{bstr, fs as rfs, is_darwin, rustc}; +use run_make_support::{bstr, is_darwin, rfs, rustc}; fn main() { let mut out_simple = rustc(); diff --git a/tests/run-make/repr128-dwarf/rmake.rs b/tests/run-make/repr128-dwarf/rmake.rs index 1c61698ffcd4..824ca6e18760 100644 --- a/tests/run-make/repr128-dwarf/rmake.rs +++ b/tests/run-make/repr128-dwarf/rmake.rs @@ -3,7 +3,7 @@ use gimli::{AttributeValue, EndianRcSlice, Reader, RunTimeEndian}; use object::{Object, ObjectSection}; -use run_make_support::{fs as rfs, gimli, object, rustc}; +use run_make_support::{gimli, object, rfs, rustc}; use std::collections::HashMap; use std::path::PathBuf; use std::rc::Rc; diff --git a/tests/run-make/reset-codegen-1/rmake.rs b/tests/run-make/reset-codegen-1/rmake.rs index 18cf5513d5c0..cc6bb7d5e39c 100644 --- a/tests/run-make/reset-codegen-1/rmake.rs +++ b/tests/run-make/reset-codegen-1/rmake.rs @@ -7,7 +7,7 @@ //@ ignore-cross-compile -use run_make_support::{bin_name, fs as rfs, rustc}; +use run_make_support::{bin_name, rfs, rustc}; use std::path::Path; fn compile(output_file: &str, emit: Option<&str>) { diff --git a/tests/run-make/resolve-rename/rmake.rs b/tests/run-make/resolve-rename/rmake.rs index cefd608177d7..16ee7b028856 100644 --- a/tests/run-make/resolve-rename/rmake.rs +++ b/tests/run-make/resolve-rename/rmake.rs @@ -5,7 +5,7 @@ // the renamed library. // See https://github.com/rust-lang/rust/pull/49253 -use run_make_support::fs as rfs; +use run_make_support::rfs; use run_make_support::rustc; fn main() { diff --git a/tests/run-make/rlib-chain/rmake.rs b/tests/run-make/rlib-chain/rmake.rs index 875de607a7b1..306a472f4737 100644 --- a/tests/run-make/rlib-chain/rmake.rs +++ b/tests/run-make/rlib-chain/rmake.rs @@ -8,7 +8,7 @@ //@ ignore-cross-compile // Reason: the compiled binary is executed -use run_make_support::{fs as rfs, run, rust_lib_name, rustc}; +use run_make_support::{rfs, run, rust_lib_name, rustc}; fn main() { rustc().input("m1.rs").run(); diff --git a/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs index e76927467064..3feee78f2e15 100644 --- a/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs +++ b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs @@ -1,4 +1,4 @@ -use run_make_support::{fs as rfs, htmldocck, rustc, rustdoc, source_root}; +use run_make_support::{htmldocck, rfs, rustc, rustdoc, source_root}; use std::path::Path; pub fn scrape(extra_args: &[&str]) { diff --git a/tests/run-make/rustdoc-test-args/rmake.rs b/tests/run-make/rustdoc-test-args/rmake.rs index 57ff529d063d..69dea83de4fe 100644 --- a/tests/run-make/rustdoc-test-args/rmake.rs +++ b/tests/run-make/rustdoc-test-args/rmake.rs @@ -1,4 +1,4 @@ -use run_make_support::{fs as rfs, rustdoc}; +use run_make_support::{rfs, rustdoc}; use std::iter; use std::path::Path; diff --git a/tests/run-make/rustdoc-themes/rmake.rs b/tests/run-make/rustdoc-themes/rmake.rs index 3a63ebbc20b5..981db358f29d 100644 --- a/tests/run-make/rustdoc-themes/rmake.rs +++ b/tests/run-make/rustdoc-themes/rmake.rs @@ -1,6 +1,6 @@ // Test that rustdoc will properly load in a theme file and display it in the theme selector. -use run_make_support::{fs as rfs, htmldocck, rustdoc, source_root}; +use run_make_support::{htmldocck, rfs, rustdoc, source_root}; use std::path::Path; fn main() { diff --git a/tests/run-make/rustdoc-verify-output-files/rmake.rs b/tests/run-make/rustdoc-verify-output-files/rmake.rs index 940503bf85fb..d1ff2e330f53 100644 --- a/tests/run-make/rustdoc-verify-output-files/rmake.rs +++ b/tests/run-make/rustdoc-verify-output-files/rmake.rs @@ -1,4 +1,4 @@ -use run_make_support::fs as rfs; +use run_make_support::rfs; use std::path::{Path, PathBuf}; use run_make_support::{assert_dirs_are_equal, rustdoc}; diff --git a/tests/run-make/sepcomp-cci-copies/rmake.rs b/tests/run-make/sepcomp-cci-copies/rmake.rs index e05db252632c..e244f5465807 100644 --- a/tests/run-make/sepcomp-cci-copies/rmake.rs +++ b/tests/run-make/sepcomp-cci-copies/rmake.rs @@ -5,7 +5,7 @@ // See https://github.com/rust-lang/rust/pull/16367 use run_make_support::{ - count_regex_matches_in_files_with_extension, cwd, fs as rfs, has_extension, regex, rustc, + count_regex_matches_in_files_with_extension, cwd, has_extension, regex, rfs, rustc, shallow_find_files, }; diff --git a/tests/run-make/sepcomp-inlining/rmake.rs b/tests/run-make/sepcomp-inlining/rmake.rs index c3e28c4198e7..b7a6bed05b84 100644 --- a/tests/run-make/sepcomp-inlining/rmake.rs +++ b/tests/run-make/sepcomp-inlining/rmake.rs @@ -6,7 +6,7 @@ // See https://github.com/rust-lang/rust/pull/16367 use run_make_support::{ - count_regex_matches_in_files_with_extension, cwd, fs as rfs, has_extension, regex, rustc, + count_regex_matches_in_files_with_extension, cwd, has_extension, regex, rfs, rustc, shallow_find_files, }; diff --git a/tests/run-make/sepcomp-separate/rmake.rs b/tests/run-make/sepcomp-separate/rmake.rs index 83fcd9490ecc..90017572c4c1 100644 --- a/tests/run-make/sepcomp-separate/rmake.rs +++ b/tests/run-make/sepcomp-separate/rmake.rs @@ -4,7 +4,7 @@ // See https://github.com/rust-lang/rust/pull/16367 use run_make_support::{ - count_regex_matches_in_files_with_extension, cwd, fs as rfs, has_extension, regex, rustc, + count_regex_matches_in_files_with_extension, cwd, has_extension, regex, rfs, rustc, shallow_find_files, }; diff --git a/tests/run-make/silly-file-names/rmake.rs b/tests/run-make/silly-file-names/rmake.rs index a883597e81c3..2acf2be86480 100644 --- a/tests/run-make/silly-file-names/rmake.rs +++ b/tests/run-make/silly-file-names/rmake.rs @@ -11,7 +11,7 @@ //@ ignore-windows // Reason: Windows refuses files with < and > in their names -use run_make_support::{diff, fs as rfs, run, rustc}; +use run_make_support::{diff, rfs, run, rustc}; fn main() { rfs::create_file(" Date: Wed, 17 Jul 2024 15:41:16 +0200 Subject: [PATCH 279/734] add test for repr(transparent) enum --- .../cmse-nonsecure-call/via-registers.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs index 72b405ef2820..43768dd72f70 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs @@ -10,7 +10,12 @@ pub trait Copy {} impl Copy for u32 {} #[repr(transparent)] -pub struct ReprTransparentU64(u64); +pub struct ReprTransparentStructU64(u64); + +#[repr(transparent)] +pub enum ReprTransparentEnumU64 { + A(u64), +} #[repr(C)] pub struct U32Compound(u16, u16); @@ -23,7 +28,7 @@ pub fn params( f3: extern "C-cmse-nonsecure-call" fn(u64, u64), f4: extern "C-cmse-nonsecure-call" fn(u128), f5: extern "C-cmse-nonsecure-call" fn(f64, f32, f32), - f6: extern "C-cmse-nonsecure-call" fn(ReprTransparentU64, U32Compound), + f6: extern "C-cmse-nonsecure-call" fn(ReprTransparentStructU64, U32Compound), f7: extern "C-cmse-nonsecure-call" fn([u32; 4]), ) { f1(); @@ -31,7 +36,7 @@ pub fn params( f3(1, 2); f4(1); f5(1.0, 2.0, 3.0); - f6(ReprTransparentU64(1), U32Compound(2, 3)); + f6(ReprTransparentStructU64(1), U32Compound(2, 3)); f7([0xDEADBEEF; 4]); } @@ -42,8 +47,9 @@ pub fn returns( f3: extern "C-cmse-nonsecure-call" fn() -> i64, f4: extern "C-cmse-nonsecure-call" fn() -> f64, f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 4], - f6: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentU64, - f7: extern "C-cmse-nonsecure-call" fn() -> U32Compound, + f6: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentStructU64, + f7: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentEnumU64, + f8: extern "C-cmse-nonsecure-call" fn() -> U32Compound, ) { f1(); f2(); @@ -52,4 +58,5 @@ pub fn returns( f5(); f6(); f7(); + f8(); } From a6510507e784d37f52558a6ceaa8cf92d345a4e2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 16 Jul 2024 00:03:37 -0400 Subject: [PATCH 280/734] lift_to_tcx -> lift_to_interner --- compiler/rustc_macros/src/lift.rs | 2 +- compiler/rustc_middle/src/macros.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 8 ++++---- compiler/rustc_middle/src/ty/generic_args.rs | 2 +- compiler/rustc_middle/src/ty/structural_impls.rs | 4 ++-- compiler/rustc_type_ir/src/binder.rs | 6 +++--- compiler/rustc_type_ir/src/lift.rs | 2 +- compiler/rustc_type_ir/src/predicate.rs | 4 ++-- compiler/rustc_type_ir_macros/src/lib.rs | 4 ++-- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_macros/src/lift.rs b/compiler/rustc_macros/src/lift.rs index d41ceb29816c..627f4088d5f5 100644 --- a/compiler/rustc_macros/src/lift.rs +++ b/compiler/rustc_macros/src/lift.rs @@ -45,7 +45,7 @@ pub fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStre quote! { type Lifted = #lifted; - fn lift_to_tcx(self, __tcx: ::rustc_middle::ty::TyCtxt<'__lifted>) -> Option<#lifted> { + fn lift_to_interner(self, __tcx: ::rustc_middle::ty::TyCtxt<'__lifted>) -> Option<#lifted> { Some(match self { #body }) } }, diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index fcea1ea81a7c..d385be007d33 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -59,7 +59,7 @@ macro_rules! TrivialLiftImpls { $( impl<'tcx> $crate::ty::Lift<$crate::ty::TyCtxt<'tcx>> for $ty { type Lifted = Self; - fn lift_to_tcx(self, _: $crate::ty::TyCtxt<'tcx>) -> Option { + fn lift_to_interner(self, _: $crate::ty::TyCtxt<'tcx>) -> Option { Some(self) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 25070e6b042c..fd41668ae44c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1484,7 +1484,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn lift>>(self, value: T) -> Option { - value.lift_to_tcx(self) + value.lift_to_interner(self) } /// Creates a type context. To use the context call `fn enter` which @@ -2087,7 +2087,7 @@ macro_rules! nop_lift { ($set:ident; $ty:ty => $lifted:ty) => { impl<'a, 'tcx> Lift> for $ty { type Lifted = $lifted; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option { // Assert that the set has the right type. // Given an argument that has an interned type, the return type has the type of // the corresponding interner set. This won't actually return anything, we're @@ -2122,7 +2122,7 @@ macro_rules! nop_list_lift { ($set:ident; $ty:ty => $lifted:ty) => { impl<'a, 'tcx> Lift> for &'a List<$ty> { type Lifted = &'tcx List<$lifted>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option { // Assert that the set has the right type. if false { let _x: &InternedSet<'tcx, List<$lifted>> = &tcx.interners.$set; @@ -2160,7 +2160,7 @@ macro_rules! nop_slice_lift { ($ty:ty => $lifted:ty) => { impl<'a, 'tcx> Lift> for &'a [$ty] { type Lifted = &'tcx [$lifted]; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option { if self.is_empty() { return Some(&[]); } diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 5ac3168196ad..10919623de72 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -308,7 +308,7 @@ impl<'tcx> GenericArg<'tcx> { impl<'a, 'tcx> Lift> for GenericArg<'a> { type Lifted = GenericArg<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option { match self.unpack() { GenericArgKind::Lifetime(lt) => tcx.lift(lt).map(|lt| lt.into()), GenericArgKind::Type(ty) => tcx.lift(ty).map(|ty| ty.into()), diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 00ea87690c1a..7cdc0e32953d 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -283,7 +283,7 @@ TrivialTypeTraversalAndLiftImpls! { impl<'tcx, T: Lift>> Lift> for Option { type Lifted = Option; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option { Some(match self { Some(x) => Some(tcx.lift(x)?), None => None, @@ -293,7 +293,7 @@ impl<'tcx, T: Lift>> Lift> for Option { impl<'a, 'tcx> Lift> for Term<'a> { type Lifted = ty::Term<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option { match self.unpack() { TermKind::Ty(ty) => tcx.lift(ty).map(Into::into), TermKind::Const(c) => tcx.lift(c).map(Into::into), diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 2531219baecc..9f2af470d1cd 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -49,10 +49,10 @@ where { type Lifted = Binder; - fn lift_to_tcx(self, tcx: U) -> Option { + fn lift_to_interner(self, tcx: U) -> Option { Some(Binder { - value: self.value.lift_to_tcx(tcx)?, - bound_vars: self.bound_vars.lift_to_tcx(tcx)?, + value: self.value.lift_to_interner(tcx)?, + bound_vars: self.bound_vars.lift_to_interner(tcx)?, }) } } diff --git a/compiler/rustc_type_ir/src/lift.rs b/compiler/rustc_type_ir/src/lift.rs index 839da10db5e5..abad155c9ae0 100644 --- a/compiler/rustc_type_ir/src/lift.rs +++ b/compiler/rustc_type_ir/src/lift.rs @@ -17,5 +17,5 @@ /// e.g., `()` or `u8`, was interned in a different context. pub trait Lift: std::fmt::Debug { type Lifted: std::fmt::Debug; - fn lift_to_tcx(self, tcx: I) -> Option; + fn lift_to_interner(self, tcx: I) -> Option; } diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index e5bcbc67f946..acf8817c6ac1 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -34,8 +34,8 @@ where { type Lifted = OutlivesPredicate; - fn lift_to_tcx(self, tcx: U) -> Option { - Some(OutlivesPredicate(self.0.lift_to_tcx(tcx)?, self.1.lift_to_tcx(tcx)?)) + fn lift_to_interner(self, tcx: U) -> Option { + Some(OutlivesPredicate(self.0.lift_to_interner(tcx)?, self.1.lift_to_interner(tcx)?)) } } diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs index 000bcf2d3b27..f5b90424afbc 100644 --- a/compiler/rustc_type_ir_macros/src/lib.rs +++ b/compiler/rustc_type_ir_macros/src/lib.rs @@ -71,7 +71,7 @@ fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { wc.push(parse_quote! { #ty: ::rustc_type_ir::lift::Lift }); let bind = &bindings[index]; quote! { - #bind.lift_to_tcx(interner)? + #bind.lift_to_interner(interner)? } }) }); @@ -89,7 +89,7 @@ fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { quote! { type Lifted = #lifted_ty; - fn lift_to_tcx( + fn lift_to_interner( self, interner: J, ) -> Option { From 8d90f442ca3b71b1bbda426e5d82ef528c71f8ff Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 16 Jul 2024 00:06:30 -0400 Subject: [PATCH 281/734] tcx -> cx in rustc_type_ir --- compiler/rustc_type_ir/src/binder.rs | 36 ++++---- compiler/rustc_type_ir/src/canonical.rs | 12 +-- compiler/rustc_type_ir/src/effects.rs | 20 ++--- compiler/rustc_type_ir/src/elaborate.rs | 8 +- compiler/rustc_type_ir/src/fast_reject.rs | 6 +- compiler/rustc_type_ir/src/fold.rs | 22 ++--- compiler/rustc_type_ir/src/inherent.rs | 2 +- compiler/rustc_type_ir/src/lift.rs | 2 +- compiler/rustc_type_ir/src/opaque_ty.rs | 10 +-- compiler/rustc_type_ir/src/outlives.rs | 14 +-- compiler/rustc_type_ir/src/predicate.rs | 38 ++++---- compiler/rustc_type_ir/src/relate.rs | 89 +++++++++---------- compiler/rustc_type_ir/src/solve/mod.rs | 8 +- compiler/rustc_type_ir/src/ty_kind/closure.rs | 34 +++---- 14 files changed, 149 insertions(+), 152 deletions(-) diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 9f2af470d1cd..17b35a2807a2 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -49,10 +49,10 @@ where { type Lifted = Binder; - fn lift_to_interner(self, tcx: U) -> Option { + fn lift_to_interner(self, cx: U) -> Option { Some(Binder { - value: self.value.lift_to_interner(tcx)?, - bound_vars: self.bound_vars.lift_to_interner(tcx)?, + value: self.value.lift_to_interner(cx)?, + bound_vars: self.bound_vars.lift_to_interner(cx)?, }) } } @@ -439,11 +439,11 @@ impl EarlyBinder where Iter::Item: TypeFoldable, { - pub fn iter_instantiated(self, tcx: I, args: A) -> IterInstantiated + pub fn iter_instantiated(self, cx: I, args: A) -> IterInstantiated where A: SliceLike, { - IterInstantiated { it: self.value.into_iter(), tcx, args } + IterInstantiated { it: self.value.into_iter(), cx, args } } /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity), @@ -455,7 +455,7 @@ where pub struct IterInstantiated { it: Iter::IntoIter, - tcx: I, + cx: I, args: A, } @@ -469,7 +469,7 @@ where fn next(&mut self) -> Option { Some( EarlyBinder { value: self.it.next()?, _tcx: PhantomData } - .instantiate(self.tcx, self.args), + .instantiate(self.cx, self.args), ) } @@ -487,7 +487,7 @@ where fn next_back(&mut self) -> Option { Some( EarlyBinder { value: self.it.next_back()?, _tcx: PhantomData } - .instantiate(self.tcx, self.args), + .instantiate(self.cx, self.args), ) } } @@ -507,10 +507,10 @@ where { pub fn iter_instantiated_copied( self, - tcx: I, + cx: I, args: &'s [I::GenericArg], ) -> IterInstantiatedCopied<'s, I, Iter> { - IterInstantiatedCopied { it: self.value.into_iter(), tcx, args } + IterInstantiatedCopied { it: self.value.into_iter(), cx, args } } /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity), @@ -522,7 +522,7 @@ where pub struct IterInstantiatedCopied<'a, I: Interner, Iter: IntoIterator> { it: Iter::IntoIter, - tcx: I, + cx: I, args: &'a [I::GenericArg], } @@ -535,7 +535,7 @@ where fn next(&mut self) -> Option { self.it.next().map(|value| { - EarlyBinder { value: *value, _tcx: PhantomData }.instantiate(self.tcx, self.args) + EarlyBinder { value: *value, _tcx: PhantomData }.instantiate(self.cx, self.args) }) } @@ -552,7 +552,7 @@ where { fn next_back(&mut self) -> Option { self.it.next_back().map(|value| { - EarlyBinder { value: *value, _tcx: PhantomData }.instantiate(self.tcx, self.args) + EarlyBinder { value: *value, _tcx: PhantomData }.instantiate(self.cx, self.args) }) } } @@ -589,11 +589,11 @@ impl Iterator for EarlyBinderIter { } impl> ty::EarlyBinder { - pub fn instantiate(self, tcx: I, args: A) -> T + pub fn instantiate(self, cx: I, args: A) -> T where A: SliceLike, { - let mut folder = ArgFolder { tcx, args: args.as_slice(), binders_passed: 0 }; + let mut folder = ArgFolder { cx, args: args.as_slice(), binders_passed: 0 }; self.value.fold_with(&mut folder) } @@ -619,7 +619,7 @@ impl> ty::EarlyBinder { // The actual instantiation engine itself is a type folder. struct ArgFolder<'a, I: Interner> { - tcx: I, + cx: I, args: &'a [I::GenericArg], /// Number of region binders we have passed through while doing the instantiation @@ -629,7 +629,7 @@ struct ArgFolder<'a, I: Interner> { impl<'a, I: Interner> TypeFolder for ArgFolder<'a, I> { #[inline] fn cx(&self) -> I { - self.tcx + self.cx } fn fold_binder>(&mut self, t: ty::Binder) -> ty::Binder { @@ -858,6 +858,6 @@ impl<'a, I: Interner> ArgFolder<'a, I> { if self.binders_passed == 0 || !region.has_escaping_bound_vars() { return region; } - ty::fold::shift_region(self.tcx, region, self.binders_passed) + ty::fold::shift_region(self.cx, region, self.binders_passed) } } diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 7b114f565f29..a9252711b2b6 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -330,25 +330,25 @@ impl CanonicalVarValues { // Given a list of canonical variables, construct a set of values which are // the identity response. - pub fn make_identity(tcx: I, infos: I::CanonicalVars) -> CanonicalVarValues { + pub fn make_identity(cx: I, infos: I::CanonicalVars) -> CanonicalVarValues { CanonicalVarValues { - var_values: tcx.mk_args_from_iter(infos.iter().enumerate().map( + var_values: cx.mk_args_from_iter(infos.iter().enumerate().map( |(i, info)| -> I::GenericArg { match info.kind { CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => { - Ty::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i)) + Ty::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) .into() } CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => { - Region::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i)) + Region::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) .into() } CanonicalVarKind::Effect => { - Const::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i)) + Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) .into() } CanonicalVarKind::Const(_) | CanonicalVarKind::PlaceholderConst(_) => { - Const::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i)) + Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) .into() } } diff --git a/compiler/rustc_type_ir/src/effects.rs b/compiler/rustc_type_ir/src/effects.rs index f7942f2f982f..d1c3c8e52235 100644 --- a/compiler/rustc_type_ir/src/effects.rs +++ b/compiler/rustc_type_ir/src/effects.rs @@ -10,38 +10,38 @@ pub enum EffectKind { } impl EffectKind { - pub fn try_from_def_id(tcx: I, def_id: I::DefId) -> Option { - if tcx.is_lang_item(def_id, EffectsMaybe) { + pub fn try_from_def_id(cx: I, def_id: I::DefId) -> Option { + if cx.is_lang_item(def_id, EffectsMaybe) { Some(EffectKind::Maybe) - } else if tcx.is_lang_item(def_id, EffectsRuntime) { + } else if cx.is_lang_item(def_id, EffectsRuntime) { Some(EffectKind::Runtime) - } else if tcx.is_lang_item(def_id, EffectsNoRuntime) { + } else if cx.is_lang_item(def_id, EffectsNoRuntime) { Some(EffectKind::NoRuntime) } else { None } } - pub fn to_def_id(self, tcx: I) -> I::DefId { + pub fn to_def_id(self, cx: I) -> I::DefId { let lang_item = match self { EffectKind::Maybe => EffectsMaybe, EffectKind::NoRuntime => EffectsNoRuntime, EffectKind::Runtime => EffectsRuntime, }; - tcx.require_lang_item(lang_item) + cx.require_lang_item(lang_item) } - pub fn try_from_ty(tcx: I, ty: I::Ty) -> Option { + pub fn try_from_ty(cx: I, ty: I::Ty) -> Option { if let crate::Adt(def, _) = ty.kind() { - Self::try_from_def_id(tcx, def.def_id()) + Self::try_from_def_id(cx, def.def_id()) } else { None } } - pub fn to_ty(self, tcx: I) -> I::Ty { - I::Ty::new_adt(tcx, tcx.adt_def(self.to_def_id(tcx)), Default::default()) + pub fn to_ty(self, cx: I) -> I::Ty { + I::Ty::new_adt(cx, cx.adt_def(self.to_def_id(cx)), Default::default()) } /// Returns an intersection between two effect kinds. If one effect kind diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 0def7d12f742..7dd2f3de3f82 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -258,17 +258,17 @@ pub fn supertrait_def_ids( } pub fn supertraits( - tcx: I, + cx: I, trait_ref: ty::Binder>, ) -> FilterToTraits> { - elaborate(tcx, [trait_ref.upcast(tcx)]).filter_only_self().filter_to_traits() + elaborate(cx, [trait_ref.upcast(cx)]).filter_only_self().filter_to_traits() } pub fn transitive_bounds( - tcx: I, + cx: I, trait_refs: impl Iterator>>, ) -> FilterToTraits> { - elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx))) + elaborate(cx, trait_refs.map(|trait_ref| trait_ref.upcast(cx))) .filter_only_self() .filter_to_traits() } diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs index 0810fa5c5583..456accd1a1b7 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -105,7 +105,7 @@ pub enum TreatParams { /// /// ¹ meaning that if the outermost layers are different, then the whole types are also different. pub fn simplify_type( - tcx: I, + cx: I, ty: I::Ty, treat_params: TreatParams, ) -> Option> { @@ -119,10 +119,10 @@ pub fn simplify_type( ty::Str => Some(SimplifiedType::Str), ty::Array(..) => Some(SimplifiedType::Array), ty::Slice(..) => Some(SimplifiedType::Slice), - ty::Pat(ty, ..) => simplify_type(tcx, ty, treat_params), + ty::Pat(ty, ..) => simplify_type(cx, ty, treat_params), ty::RawPtr(_, mutbl) => Some(SimplifiedType::Ptr(mutbl)), ty::Dynamic(trait_info, ..) => match trait_info.principal_def_id() { - Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => { + Some(principal_def_id) if !cx.trait_is_auto(principal_def_id) => { Some(SimplifiedType::Trait(principal_def_id)) } _ => Some(SimplifiedType::MarkerTraitObject), diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index 09ee12d1cc39..a4d8dafb246e 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -345,20 +345,20 @@ impl, Ix: Idx> TypeFoldable for IndexVec { - tcx: I, + cx: I, current_index: ty::DebruijnIndex, amount: u32, } impl Shifter { - pub fn new(tcx: I, amount: u32) -> Self { - Shifter { tcx, current_index: ty::INNERMOST, amount } + pub fn new(cx: I, amount: u32) -> Self { + Shifter { cx, current_index: ty::INNERMOST, amount } } } impl TypeFolder for Shifter { fn cx(&self) -> I { - self.tcx + self.cx } fn fold_binder>(&mut self, t: ty::Binder) -> ty::Binder { @@ -372,7 +372,7 @@ impl TypeFolder for Shifter { match r.kind() { ty::ReBound(debruijn, br) if debruijn >= self.current_index => { let debruijn = debruijn.shifted_in(self.amount); - Region::new_bound(self.tcx, debruijn, br) + Region::new_bound(self.cx, debruijn, br) } _ => r, } @@ -382,7 +382,7 @@ impl TypeFolder for Shifter { match ty.kind() { ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { let debruijn = debruijn.shifted_in(self.amount); - Ty::new_bound(self.tcx, debruijn, bound_ty) + Ty::new_bound(self.cx, debruijn, bound_ty) } _ if ty.has_vars_bound_at_or_above(self.current_index) => ty.super_fold_with(self), @@ -394,7 +394,7 @@ impl TypeFolder for Shifter { match ct.kind() { ty::ConstKind::Bound(debruijn, bound_ct) if debruijn >= self.current_index => { let debruijn = debruijn.shifted_in(self.amount); - Const::new_bound(self.tcx, debruijn, bound_ct) + Const::new_bound(self.cx, debruijn, bound_ct) } _ => ct.super_fold_with(self), } @@ -405,16 +405,16 @@ impl TypeFolder for Shifter { } } -pub fn shift_region(tcx: I, region: I::Region, amount: u32) -> I::Region { +pub fn shift_region(cx: I, region: I::Region, amount: u32) -> I::Region { match region.kind() { ty::ReBound(debruijn, br) if amount > 0 => { - Region::new_bound(tcx, debruijn.shifted_in(amount), br) + Region::new_bound(cx, debruijn.shifted_in(amount), br) } _ => region, } } -pub fn shift_vars(tcx: I, value: T, amount: u32) -> T +pub fn shift_vars(cx: I, value: T, amount: u32) -> T where T: TypeFoldable, { @@ -424,5 +424,5 @@ where return value; } - value.fold_with(&mut Shifter::new(tcx, amount)) + value.fold_with(&mut Shifter::new(cx, amount)) } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index f05d626b4703..63ad36efc852 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -475,7 +475,7 @@ pub trait Clause>: /// poly-trait-ref to supertraits that must hold if that /// poly-trait-ref holds. This is slightly different from a normal /// instantiation in terms of what happens with bound regions. - fn instantiate_supertrait(self, tcx: I, trait_ref: ty::Binder>) -> Self; + fn instantiate_supertrait(self, cx: I, trait_ref: ty::Binder>) -> Self; } /// Common capabilities of placeholder kinds diff --git a/compiler/rustc_type_ir/src/lift.rs b/compiler/rustc_type_ir/src/lift.rs index abad155c9ae0..e5a099d1f504 100644 --- a/compiler/rustc_type_ir/src/lift.rs +++ b/compiler/rustc_type_ir/src/lift.rs @@ -17,5 +17,5 @@ /// e.g., `()` or `u8`, was interned in a different context. pub trait Lift: std::fmt::Debug { type Lifted: std::fmt::Debug; - fn lift_to_interner(self, tcx: I) -> Option; + fn lift_to_interner(self, cx: I) -> Option; } diff --git a/compiler/rustc_type_ir/src/opaque_ty.rs b/compiler/rustc_type_ir/src/opaque_ty.rs index d8ed4770e2dc..e5d18fcb3d1e 100644 --- a/compiler/rustc_type_ir/src/opaque_ty.rs +++ b/compiler/rustc_type_ir/src/opaque_ty.rs @@ -22,8 +22,8 @@ pub struct OpaqueTypeKey { } impl OpaqueTypeKey { - pub fn iter_captured_args(self, tcx: I) -> impl Iterator { - let variances = tcx.variances_of(self.def_id.into()); + pub fn iter_captured_args(self, cx: I) -> impl Iterator { + let variances = cx.variances_of(self.def_id.into()); std::iter::zip(self.args.iter(), variances.iter()).enumerate().filter_map( |(i, (arg, v))| match (arg.kind(), v) { (_, ty::Invariant) => Some((i, arg)), @@ -35,18 +35,18 @@ impl OpaqueTypeKey { pub fn fold_captured_lifetime_args( self, - tcx: I, + cx: I, mut f: impl FnMut(I::Region) -> I::Region, ) -> Self { let Self { def_id, args } = self; - let variances = tcx.variances_of(def_id.into()); + let variances = cx.variances_of(def_id.into()); let args = std::iter::zip(args.iter(), variances.iter()).map(|(arg, v)| match (arg.kind(), v) { (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => arg, (ty::GenericArgKind::Lifetime(lt), _) => f(lt).into(), _ => arg, }); - let args = tcx.mk_args_from_iter(args); + let args = cx.mk_args_from_iter(args); Self { def_id, args } } } diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs index 10b6f3355d92..eb84f3dd5873 100644 --- a/compiler/rustc_type_ir/src/outlives.rs +++ b/compiler/rustc_type_ir/src/outlives.rs @@ -54,15 +54,15 @@ pub enum Component { /// Push onto `out` all the things that must outlive `'a` for the condition /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. pub fn push_outlives_components( - tcx: I, + cx: I, ty: I::Ty, out: &mut SmallVec<[Component; 4]>, ) { - ty.visit_with(&mut OutlivesCollector { tcx, out, visited: Default::default() }); + ty.visit_with(&mut OutlivesCollector { cx, out, visited: Default::default() }); } struct OutlivesCollector<'a, I: Interner> { - tcx: I, + cx: I, out: &'a mut SmallVec<[Component; 4]>, visited: SsoHashSet, } @@ -147,7 +147,7 @@ impl TypeVisitor for OutlivesCollector<'_, I> { // OutlivesProjectionComponents. Continue walking // through and constrain Pi. let mut subcomponents = smallvec![]; - compute_alias_components_recursive(self.tcx, ty, &mut subcomponents); + compute_alias_components_recursive(self.cx, ty, &mut subcomponents); self.out.push(Component::EscapingAlias(subcomponents.into_iter().collect())); } } @@ -206,7 +206,7 @@ impl TypeVisitor for OutlivesCollector<'_, I> { /// This should not be used to get the components of `parent` itself. /// Use [push_outlives_components] instead. pub fn compute_alias_components_recursive( - tcx: I, + cx: I, alias_ty: I::Ty, out: &mut SmallVec<[Component; 4]>, ) { @@ -215,9 +215,9 @@ pub fn compute_alias_components_recursive( }; let opt_variances = - if kind == ty::Opaque { Some(tcx.variances_of(alias_ty.def_id)) } else { None }; + if kind == ty::Opaque { Some(cx.variances_of(alias_ty.def_id)) } else { None }; - let mut visitor = OutlivesCollector { tcx, out, visited: Default::default() }; + let mut visitor = OutlivesCollector { cx, out, visited: Default::default() }; for (index, child) in alias_ty.args.iter().enumerate() { if opt_variances.and_then(|variances| variances.get(index)) == Some(ty::Bivariant) { diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index acf8817c6ac1..e03f521c5b10 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -34,8 +34,8 @@ where { type Lifted = OutlivesPredicate; - fn lift_to_interner(self, tcx: U) -> Option { - Some(OutlivesPredicate(self.0.lift_to_interner(tcx)?, self.1.lift_to_interner(tcx)?)) + fn lift_to_interner(self, cx: U) -> Option { + Some(OutlivesPredicate(self.0.lift_to_interner(cx)?, self.1.lift_to_interner(cx)?)) } } @@ -267,25 +267,23 @@ impl ty::Binder> { /// Given an existential predicate like `?Self: PartialEq` (e.g., derived from `dyn PartialEq`), /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self` /// has been replaced with `self_ty` (e.g., `self_ty: PartialEq`, in our example). - pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> I::Clause { + pub fn with_self_ty(&self, cx: I, self_ty: I::Ty) -> I::Clause { match self.skip_binder() { - ExistentialPredicate::Trait(tr) => { - self.rebind(tr).with_self_ty(tcx, self_ty).upcast(tcx) - } + ExistentialPredicate::Trait(tr) => self.rebind(tr).with_self_ty(cx, self_ty).upcast(cx), ExistentialPredicate::Projection(p) => { - self.rebind(p.with_self_ty(tcx, self_ty)).upcast(tcx) + self.rebind(p.with_self_ty(cx, self_ty)).upcast(cx) } ExistentialPredicate::AutoTrait(did) => { - let generics = tcx.generics_of(did); + let generics = cx.generics_of(did); let trait_ref = if generics.count() == 1 { - ty::TraitRef::new(tcx, did, [self_ty]) + ty::TraitRef::new(cx, did, [self_ty]) } else { // If this is an ill-formed auto trait, then synthesize // new error args for the missing generics. - let err_args = GenericArgs::extend_with_error(tcx, did, &[self_ty.into()]); - ty::TraitRef::new_from_args(tcx, did, err_args) + let err_args = GenericArgs::extend_with_error(cx, did, &[self_ty.into()]); + ty::TraitRef::new_from_args(cx, did, err_args) }; - self.rebind(trait_ref).upcast(tcx) + self.rebind(trait_ref).upcast(cx) } } } @@ -345,8 +343,8 @@ impl ty::Binder> { /// we convert the principal trait-ref into a normal trait-ref, /// you must give *some* self type. A common choice is `mk_err()` /// or some placeholder type. - pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> ty::Binder> { - self.map_bound(|trait_ref| trait_ref.with_self_ty(tcx, self_ty)) + pub fn with_self_ty(&self, cx: I, self_ty: I::Ty) -> ty::Binder> { + self.map_bound(|trait_ref| trait_ref.with_self_ty(cx, self_ty)) } } @@ -406,8 +404,8 @@ impl ExistentialProjection { } impl ty::Binder> { - pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> ty::Binder> { - self.map_bound(|p| p.with_self_ty(tcx, self_ty)) + pub fn with_self_ty(&self, cx: I, self_ty: I::Ty) -> ty::Binder> { + self.map_bound(|p| p.with_self_ty(cx, self_ty)) } pub fn item_def_id(&self) -> I::DefId { @@ -669,21 +667,21 @@ impl ProjectionPredicate { impl ty::Binder> { /// Returns the `DefId` of the trait of the associated item being projected. #[inline] - pub fn trait_def_id(&self, tcx: I) -> I::DefId { - self.skip_binder().projection_term.trait_def_id(tcx) + pub fn trait_def_id(&self, cx: I) -> I::DefId { + self.skip_binder().projection_term.trait_def_id(cx) } /// Get the trait ref required for this projection to be well formed. /// Note that for generic associated types the predicates of the associated /// type also need to be checked. #[inline] - pub fn required_poly_trait_ref(&self, tcx: I) -> ty::Binder> { + pub fn required_poly_trait_ref(&self, cx: I) -> ty::Binder> { // Note: unlike with `TraitRef::to_poly_trait_ref()`, // `self.0.trait_ref` is permitted to have escaping regions. // This is because here `self` has a `Binder` and so does our // return value, so we are preserving the number of binding // levels. - self.map_bound(|predicate| predicate.projection_term.trait_ref(tcx)) + self.map_bound(|predicate| predicate.projection_term.trait_ref(cx)) } pub fn term(&self) -> ty::Binder { diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 0439e7f857fe..a8f48d14af5c 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -56,7 +56,7 @@ impl VarianceDiagInfo { } pub trait TypeRelation: Sized { - fn tcx(&self) -> I; + fn cx(&self) -> I; /// Returns a static string we can use for printouts. fn tag(&self) -> &'static str; @@ -80,8 +80,8 @@ pub trait TypeRelation: Sized { item_def_id, a_arg, b_arg ); - let tcx = self.tcx(); - let opt_variances = tcx.variances_of(item_def_id); + let cx = self.cx(); + let opt_variances = cx.variances_of(item_def_id); relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, true) } @@ -128,7 +128,7 @@ pub fn relate_args_invariantly>( a_arg: I::GenericArgs, b_arg: I::GenericArgs, ) -> RelateResult { - relation.tcx().mk_args_from_iter(iter::zip(a_arg.iter(), b_arg.iter()).map(|(a, b)| { + relation.cx().mk_args_from_iter(iter::zip(a_arg.iter(), b_arg.iter()).map(|(a, b)| { relation.relate_with_variance(ty::Invariant, VarianceDiagInfo::default(), a, b) })) } @@ -141,14 +141,13 @@ pub fn relate_args_with_variances>( b_arg: I::GenericArgs, fetch_ty_for_diag: bool, ) -> RelateResult { - let tcx = relation.tcx(); + let cx = relation.cx(); let mut cached_ty = None; let params = iter::zip(a_arg.iter(), b_arg.iter()).enumerate().map(|(i, (a, b))| { let variance = variances.get(i).unwrap(); let variance_info = if variance == ty::Invariant && fetch_ty_for_diag { - let ty = - *cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).instantiate(tcx, a_arg)); + let ty = *cached_ty.get_or_insert_with(|| cx.type_of(ty_def_id).instantiate(cx, a_arg)); VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() } } else { VarianceDiagInfo::default() @@ -156,7 +155,7 @@ pub fn relate_args_with_variances>( relation.relate_with_variance(variance, variance_info, a, b) }); - tcx.mk_args_from_iter(params) + cx.mk_args_from_iter(params) } impl Relate for ty::FnSig { @@ -165,7 +164,7 @@ impl Relate for ty::FnSig { a: ty::FnSig, b: ty::FnSig, ) -> RelateResult> { - let tcx = relation.tcx(); + let cx = relation.cx(); if a.c_variadic != b.c_variadic { return Err(TypeError::VariadicMismatch({ @@ -210,7 +209,7 @@ impl Relate for ty::FnSig { r => r, }); Ok(ty::FnSig { - inputs_and_output: tcx.mk_type_list_from_iter(inputs_and_output)?, + inputs_and_output: cx.mk_type_list_from_iter(inputs_and_output)?, c_variadic: a.c_variadic, safety, abi, @@ -245,11 +244,11 @@ impl Relate for ty::AliasTy { ExpectedFound::new(true, a, b) })) } else { - let args = match a.kind(relation.tcx()) { + let args = match a.kind(relation.cx()) { ty::Opaque => relate_args_with_variances( relation, a.def_id, - relation.tcx().variances_of(a.def_id), + relation.cx().variances_of(a.def_id), a.args, b.args, false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle @@ -258,7 +257,7 @@ impl Relate for ty::AliasTy { relate_args_invariantly(relation, a.args, b.args)? } }; - Ok(ty::AliasTy::new_from_args(relation.tcx(), a.def_id, args)) + Ok(ty::AliasTy::new_from_args(relation.cx(), a.def_id, args)) } } } @@ -276,11 +275,11 @@ impl Relate for ty::AliasTerm { ExpectedFound::new(true, a, b) })) } else { - let args = match a.kind(relation.tcx()) { + let args = match a.kind(relation.cx()) { ty::AliasTermKind::OpaqueTy => relate_args_with_variances( relation, a.def_id, - relation.tcx().variances_of(a.def_id), + relation.cx().variances_of(a.def_id), a.args, b.args, false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle @@ -293,7 +292,7 @@ impl Relate for ty::AliasTerm { relate_args_invariantly(relation, a.args, b.args)? } }; - Ok(ty::AliasTerm::new_from_args(relation.tcx(), a.def_id, args)) + Ok(ty::AliasTerm::new_from_args(relation.cx(), a.def_id, args)) } } } @@ -343,7 +342,7 @@ impl Relate for ty::TraitRef { })) } else { let args = relate_args_invariantly(relation, a.args, b.args)?; - Ok(ty::TraitRef::new_from_args(relation.tcx(), a.def_id, args)) + Ok(ty::TraitRef::new_from_args(relation.cx(), a.def_id, args)) } } } @@ -377,7 +376,7 @@ pub fn structurally_relate_tys>( a: I::Ty, b: I::Ty, ) -> RelateResult { - let tcx = relation.tcx(); + let cx = relation.cx(); match (a.kind(), b.kind()) { (ty::Infer(_), _) | (_, ty::Infer(_)) => { // The caller should handle these cases! @@ -388,7 +387,7 @@ pub fn structurally_relate_tys>( panic!("bound types encountered in structurally_relate_tys") } - (ty::Error(guar), _) | (_, ty::Error(guar)) => Ok(Ty::new_error(tcx, guar)), + (ty::Error(guar), _) | (_, ty::Error(guar)) => Ok(Ty::new_error(cx, guar)), (ty::Never, _) | (ty::Char, _) @@ -412,16 +411,16 @@ pub fn structurally_relate_tys>( (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args)) if a_def == b_def => { let args = relation.relate_item_args(a_def.def_id(), a_args, b_args)?; - Ok(Ty::new_adt(tcx, a_def, args)) + Ok(Ty::new_adt(cx, a_def, args)) } - (ty::Foreign(a_id), ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(tcx, a_id)), + (ty::Foreign(a_id), ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(cx, a_id)), (ty::Dynamic(a_obj, a_region, a_repr), ty::Dynamic(b_obj, b_region, b_repr)) if a_repr == b_repr => { Ok(Ty::new_dynamic( - tcx, + cx, relation.relate(a_obj, b_obj)?, relation.relate(a_region, b_region)?, a_repr, @@ -433,7 +432,7 @@ pub fn structurally_relate_tys>( // the (anonymous) type of the same coroutine expression. So // all of their regions should be equated. let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_coroutine(tcx, a_id, args)) + Ok(Ty::new_coroutine(cx, a_id, args)) } (ty::CoroutineWitness(a_id, a_args), ty::CoroutineWitness(b_id, b_args)) @@ -443,7 +442,7 @@ pub fn structurally_relate_tys>( // the (anonymous) type of the same coroutine expression. So // all of their regions should be equated. let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_coroutine_witness(tcx, a_id, args)) + Ok(Ty::new_coroutine_witness(cx, a_id, args)) } (ty::Closure(a_id, a_args), ty::Closure(b_id, b_args)) if a_id == b_id => { @@ -451,14 +450,14 @@ pub fn structurally_relate_tys>( // the (anonymous) type of the same closure expression. So // all of their regions should be equated. let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_closure(tcx, a_id, args)) + Ok(Ty::new_closure(cx, a_id, args)) } (ty::CoroutineClosure(a_id, a_args), ty::CoroutineClosure(b_id, b_args)) if a_id == b_id => { let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_coroutine_closure(tcx, a_id, args)) + Ok(Ty::new_coroutine_closure(cx, a_id, args)) } (ty::RawPtr(a_ty, a_mutbl), ty::RawPtr(b_ty, b_mutbl)) => { @@ -475,7 +474,7 @@ pub fn structurally_relate_tys>( let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?; - Ok(Ty::new_ptr(tcx, ty, a_mutbl)) + Ok(Ty::new_ptr(cx, ty, a_mutbl)) } (ty::Ref(a_r, a_ty, a_mutbl), ty::Ref(b_r, b_ty, b_mutbl)) => { @@ -493,18 +492,18 @@ pub fn structurally_relate_tys>( let r = relation.relate(a_r, b_r)?; let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?; - Ok(Ty::new_ref(tcx, r, ty, a_mutbl)) + Ok(Ty::new_ref(cx, r, ty, a_mutbl)) } (ty::Array(a_t, sz_a), ty::Array(b_t, sz_b)) => { let t = relation.relate(a_t, b_t)?; match relation.relate(sz_a, sz_b) { - Ok(sz) => Ok(Ty::new_array_with_const_len(tcx, t, sz)), + Ok(sz) => Ok(Ty::new_array_with_const_len(cx, t, sz)), Err(err) => { // Check whether the lengths are both concrete/known values, // but are unequal, for better diagnostics. - let sz_a = sz_a.try_to_target_usize(tcx); - let sz_b = sz_b.try_to_target_usize(tcx); + let sz_a = sz_a.try_to_target_usize(cx); + let sz_b = sz_b.try_to_target_usize(cx); match (sz_a, sz_b) { (Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => Err( @@ -518,13 +517,13 @@ pub fn structurally_relate_tys>( (ty::Slice(a_t), ty::Slice(b_t)) => { let t = relation.relate(a_t, b_t)?; - Ok(Ty::new_slice(tcx, t)) + Ok(Ty::new_slice(cx, t)) } (ty::Tuple(as_), ty::Tuple(bs)) => { if as_.len() == bs.len() { Ok(Ty::new_tup_from_iter( - tcx, + cx, iter::zip(as_.iter(), bs.iter()).map(|(a, b)| relation.relate(a, b)), )?) } else if !(as_.is_empty() || bs.is_empty()) { @@ -536,25 +535,25 @@ pub fn structurally_relate_tys>( (ty::FnDef(a_def_id, a_args), ty::FnDef(b_def_id, b_args)) if a_def_id == b_def_id => { let args = relation.relate_item_args(a_def_id, a_args, b_args)?; - Ok(Ty::new_fn_def(tcx, a_def_id, args)) + Ok(Ty::new_fn_def(cx, a_def_id, args)) } (ty::FnPtr(a_fty), ty::FnPtr(b_fty)) => { let fty = relation.relate(a_fty, b_fty)?; - Ok(Ty::new_fn_ptr(tcx, fty)) + Ok(Ty::new_fn_ptr(cx, fty)) } // Alias tend to mostly already be handled downstream due to normalization. (ty::Alias(a_kind, a_data), ty::Alias(b_kind, b_data)) => { let alias_ty = relation.relate(a_data, b_data)?; assert_eq!(a_kind, b_kind); - Ok(Ty::new_alias(tcx, a_kind, alias_ty)) + Ok(Ty::new_alias(cx, a_kind, alias_ty)) } (ty::Pat(a_ty, a_pat), ty::Pat(b_ty, b_pat)) => { let ty = relation.relate(a_ty, b_ty)?; let pat = relation.relate(a_pat, b_pat)?; - Ok(Ty::new_pat(tcx, ty, pat)) + Ok(Ty::new_pat(cx, ty, pat)) } _ => Err(TypeError::Sorts(ExpectedFound::new(true, a, b))), @@ -573,11 +572,11 @@ pub fn structurally_relate_consts>( mut b: I::Const, ) -> RelateResult { debug!("{}.structurally_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); - let tcx = relation.tcx(); + let cx = relation.cx(); - if tcx.features().generic_const_exprs() { - a = tcx.expand_abstract_consts(a); - b = tcx.expand_abstract_consts(b); + if cx.features().generic_const_exprs() { + a = cx.expand_abstract_consts(a); + b = cx.expand_abstract_consts(b); } debug!("{}.structurally_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b); @@ -607,8 +606,8 @@ pub fn structurally_relate_consts>( // be stabilized. (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def => { if cfg!(debug_assertions) { - let a_ty = tcx.type_of(au.def).instantiate(tcx, au.args); - let b_ty = tcx.type_of(bu.def).instantiate(tcx, bu.args); + let a_ty = cx.type_of(au.def).instantiate(cx, au.args); + let b_ty = cx.type_of(bu.def).instantiate(cx, bu.args); assert_eq!(a_ty, b_ty); } @@ -618,11 +617,11 @@ pub fn structurally_relate_consts>( au.args, bu.args, )?; - return Ok(Const::new_unevaluated(tcx, ty::UnevaluatedConst { def: au.def, args })); + return Ok(Const::new_unevaluated(cx, ty::UnevaluatedConst { def: au.def, args })); } (ty::ConstKind::Expr(ae), ty::ConstKind::Expr(be)) => { let expr = relation.relate(ae, be)?; - return Ok(Const::new_expr(tcx, expr)); + return Ok(Const::new_expr(cx, expr)); } _ => false, }; diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 7934f996f0bd..2449ac47db6f 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -106,13 +106,13 @@ pub struct Goal { } impl Goal { - pub fn new(tcx: I, param_env: I::ParamEnv, predicate: impl Upcast) -> Goal { - Goal { param_env, predicate: predicate.upcast(tcx) } + pub fn new(cx: I, param_env: I::ParamEnv, predicate: impl Upcast) -> Goal { + Goal { param_env, predicate: predicate.upcast(cx) } } /// Updates the goal to one with a different `predicate` but the same `param_env`. - pub fn with(self, tcx: I, predicate: impl Upcast) -> Goal { - Goal { param_env: self.param_env, predicate: predicate.upcast(tcx) } + pub fn with(self, cx: I, predicate: impl Upcast) -> Goal { + Goal { param_env: self.param_env, predicate: predicate.upcast(cx) } } } diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs index 24a7c0c67e90..6c5bbbfd59ba 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -136,9 +136,9 @@ pub struct ClosureArgsParts { impl ClosureArgs { /// Construct `ClosureArgs` from `ClosureArgsParts`, containing `Args` /// for the closure parent, alongside additional closure-specific components. - pub fn new(tcx: I, parts: ClosureArgsParts) -> ClosureArgs { + pub fn new(cx: I, parts: ClosureArgsParts) -> ClosureArgs { ClosureArgs { - args: tcx.mk_args_from_iter(parts.parent_args.iter().chain([ + args: cx.mk_args_from_iter(parts.parent_args.iter().chain([ parts.closure_kind_ty.into(), parts.closure_sig_as_fn_ptr_ty.into(), parts.tupled_upvars_ty.into(), @@ -258,9 +258,9 @@ pub struct CoroutineClosureArgsParts { } impl CoroutineClosureArgs { - pub fn new(tcx: I, parts: CoroutineClosureArgsParts) -> CoroutineClosureArgs { + pub fn new(cx: I, parts: CoroutineClosureArgsParts) -> CoroutineClosureArgs { CoroutineClosureArgs { - args: tcx.mk_args_from_iter(parts.parent_args.iter().chain([ + args: cx.mk_args_from_iter(parts.parent_args.iter().chain([ parts.closure_kind_ty.into(), parts.signature_parts_ty.into(), parts.tupled_upvars_ty.into(), @@ -409,14 +409,14 @@ impl CoroutineClosureSignature { /// When the kind and upvars are known, use the other helper functions. pub fn to_coroutine( self, - tcx: I, + cx: I, parent_args: I::GenericArgsSlice, coroutine_kind_ty: I::Ty, coroutine_def_id: I::DefId, tupled_upvars_ty: I::Ty, ) -> I::Ty { let coroutine_args = ty::CoroutineArgs::new( - tcx, + cx, ty::CoroutineArgsParts { parent_args, kind_ty: coroutine_kind_ty, @@ -428,7 +428,7 @@ impl CoroutineClosureSignature { }, ); - Ty::new_coroutine(tcx, coroutine_def_id, coroutine_args.args) + Ty::new_coroutine(cx, coroutine_def_id, coroutine_args.args) } /// Given known upvars and a [`ClosureKind`](ty::ClosureKind), compute the coroutine @@ -438,7 +438,7 @@ impl CoroutineClosureSignature { /// that the `ClosureKind` is actually supported by the coroutine-closure. pub fn to_coroutine_given_kind_and_upvars( self, - tcx: I, + cx: I, parent_args: I::GenericArgsSlice, coroutine_def_id: I::DefId, goal_kind: ty::ClosureKind, @@ -447,7 +447,7 @@ impl CoroutineClosureSignature { coroutine_captures_by_ref_ty: I::Ty, ) -> I::Ty { let tupled_upvars_ty = Self::tupled_upvars_by_closure_kind( - tcx, + cx, goal_kind, self.tupled_inputs_ty, closure_tupled_upvars_ty, @@ -456,9 +456,9 @@ impl CoroutineClosureSignature { ); self.to_coroutine( - tcx, + cx, parent_args, - Ty::from_coroutine_closure_kind(tcx, goal_kind), + Ty::from_coroutine_closure_kind(cx, goal_kind), coroutine_def_id, tupled_upvars_ty, ) @@ -474,7 +474,7 @@ impl CoroutineClosureSignature { /// lifetimes are related to the lifetime of the borrow on the closure made for /// the call. This allows borrowck to enforce the self-borrows correctly. pub fn tupled_upvars_by_closure_kind( - tcx: I, + cx: I, kind: ty::ClosureKind, tupled_inputs_ty: I::Ty, closure_tupled_upvars_ty: I::Ty, @@ -488,12 +488,12 @@ impl CoroutineClosureSignature { }; let coroutine_captures_by_ref_ty = sig.output().skip_binder().fold_with(&mut FoldEscapingRegions { - interner: tcx, + interner: cx, region: env_region, debruijn: ty::INNERMOST, }); Ty::new_tup_from_iter( - tcx, + cx, tupled_inputs_ty .tuple_fields() .iter() @@ -501,7 +501,7 @@ impl CoroutineClosureSignature { ) } ty::ClosureKind::FnOnce => Ty::new_tup_from_iter( - tcx, + cx, tupled_inputs_ty .tuple_fields() .iter() @@ -615,9 +615,9 @@ pub struct CoroutineArgsParts { impl CoroutineArgs { /// Construct `CoroutineArgs` from `CoroutineArgsParts`, containing `Args` /// for the coroutine parent, alongside additional coroutine-specific components. - pub fn new(tcx: I, parts: CoroutineArgsParts) -> CoroutineArgs { + pub fn new(cx: I, parts: CoroutineArgsParts) -> CoroutineArgs { CoroutineArgs { - args: tcx.mk_args_from_iter(parts.parent_args.iter().chain([ + args: cx.mk_args_from_iter(parts.parent_args.iter().chain([ parts.kind_ty.into(), parts.resume_ty.into(), parts.yield_ty.into(), From 0b5ce54bc2bd6dae4ab27fd712ee2c999491f364 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 16 Jul 2024 00:14:44 -0400 Subject: [PATCH 282/734] Fix relations --- compiler/rustc_borrowck/src/type_check/relate_tys.rs | 8 ++++---- .../rustc_infer/src/error_reporting/infer/mod.rs | 2 +- .../src/infer/outlives/test_type_match.rs | 2 +- compiler/rustc_infer/src/infer/relate/generalize.rs | 12 ++++++------ compiler/rustc_infer/src/infer/relate/glb.rs | 4 ++-- compiler/rustc_infer/src/infer/relate/lub.rs | 4 ++-- .../rustc_infer/src/infer/relate/type_relating.rs | 10 +++++----- compiler/rustc_middle/src/ty/relate.rs | 4 ++-- .../src/traits/select/_match.rs | 4 ++-- 9 files changed, 25 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 02b9c2d48b11..ea4a94e57b3b 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -309,7 +309,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { } impl<'bccx, 'tcx> TypeRelation> for NllTypeRelating<'_, 'bccx, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.type_checker.infcx.tcx } @@ -370,7 +370,7 @@ impl<'bccx, 'tcx> TypeRelation> for NllTypeRelating<'_, 'bccx, 'tcx // shouldn't ever fail. Instead, it unconditionally emits an // alias-relate goal. assert!(!self.type_checker.infcx.next_trait_solver()); - self.tcx().dcx().span_delayed_bug( + self.cx().dcx().span_delayed_bug( self.span(), "failure to relate an opaque to itself should result in an error later on", ); @@ -540,7 +540,7 @@ impl<'bccx, 'tcx> PredicateEmittingRelation> for NllTypeRelating &mut self, obligations: impl IntoIterator, ty::Predicate<'tcx>>>, ) { - let tcx = self.tcx(); + let tcx = self.cx(); let param_env = self.param_env(); self.register_goals( obligations.into_iter().map(|to_pred| Goal::new(tcx, param_env, to_pred)), @@ -559,7 +559,7 @@ impl<'bccx, 'tcx> PredicateEmittingRelation> for NllTypeRelating .into_iter() .map(|goal| { Obligation::new( - self.tcx(), + self.cx(), ObligationCause::dummy_with_span(self.span()), goal.param_env, goal.predicate, diff --git a/compiler/rustc_infer/src/error_reporting/infer/mod.rs b/compiler/rustc_infer/src/error_reporting/infer/mod.rs index ddd5818203cf..a4af721cf754 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/mod.rs @@ -1930,7 +1930,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'tcx>); impl<'tcx> TypeRelation> for SameTypeModuloInfer<'_, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.0.tcx } diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index 978b92fd8980..d60d9113d91b 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -137,7 +137,7 @@ impl<'tcx> TypeRelation> for MatchAgainstHigherRankedOutlives<'tcx> "MatchAgainstHigherRankedOutlives" } - fn tcx(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index fe3b8d60fb91..ace439545b84 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -372,7 +372,7 @@ impl<'tcx> Generalizer<'_, 'tcx> { let is_nested_alias = mem::replace(&mut self.in_alias, true); let result = match self.relate(alias, alias) { - Ok(alias) => Ok(alias.to_ty(self.tcx())), + Ok(alias) => Ok(alias.to_ty(self.cx())), Err(e) => { if is_nested_alias { return Err(e); @@ -397,7 +397,7 @@ impl<'tcx> Generalizer<'_, 'tcx> { } impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -417,7 +417,7 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { // (e.g., #41849). relate::relate_args_invariantly(self, a_arg, b_arg) } else { - let tcx = self.tcx(); + let tcx = self.cx(); let opt_variances = tcx.variances_of(item_def_id); relate::relate_args_with_variances( self, @@ -525,7 +525,7 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { } debug!("replacing original vid={:?} with new={:?}", vid, new_var_id); - Ok(Ty::new_var(self.tcx(), new_var_id)) + Ok(Ty::new_var(self.cx(), new_var_id)) } } } @@ -654,7 +654,7 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { { variable_table.union(vid, new_var_id); } - Ok(ty::Const::new_var(self.tcx(), new_var_id)) + Ok(ty::Const::new_var(self.cx(), new_var_id)) } } } @@ -672,7 +672,7 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { args, args, )?; - Ok(ty::Const::new_unevaluated(self.tcx(), ty::UnevaluatedConst { def, args })) + Ok(ty::Const::new_unevaluated(self.cx(), ty::UnevaluatedConst { def, args })) } ty::ConstKind::Placeholder(placeholder) => { if self.for_universe.can_name(placeholder.universe) { diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs index 5bb8a113e173..819a47fcf93f 100644 --- a/compiler/rustc_infer/src/infer/relate/glb.rs +++ b/compiler/rustc_infer/src/infer/relate/glb.rs @@ -27,7 +27,7 @@ impl<'tcx> TypeRelation> for Glb<'_, '_, 'tcx> { "Glb" } - fn tcx(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.fields.tcx() } @@ -61,7 +61,7 @@ impl<'tcx> TypeRelation> for Glb<'_, '_, 'tcx> { let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8 Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions( - self.tcx(), + self.cx(), origin, a, b, diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs index 94c1464817f7..56d325c5dc1f 100644 --- a/compiler/rustc_infer/src/infer/relate/lub.rs +++ b/compiler/rustc_infer/src/infer/relate/lub.rs @@ -27,7 +27,7 @@ impl<'tcx> TypeRelation> for Lub<'_, '_, 'tcx> { "Lub" } - fn tcx(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.fields.tcx() } @@ -61,7 +61,7 @@ impl<'tcx> TypeRelation> for Lub<'_, '_, 'tcx> { let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8 Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions( - self.tcx(), + self.cx(), origin, a, b, diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index e206f530519b..97bd858defbc 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -32,7 +32,7 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { "TypeRelating" } - fn tcx(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.fields.infcx.tcx } @@ -48,7 +48,7 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { // (e.g., #41849). relate_args_invariantly(self, a_arg, b_arg) } else { - let tcx = self.tcx(); + let tcx = self.cx(); let opt_variances = tcx.variances_of(item_def_id); relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, false) } @@ -88,7 +88,7 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { // can't make progress on `A <: B` if both A and B are // type variables, so record an obligation. self.fields.goals.push(Goal::new( - self.tcx(), + self.cx(), self.fields.param_env, ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: true, @@ -101,7 +101,7 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { // can't make progress on `B <: A` if both A and B are // type variables, so record an obligation. self.fields.goals.push(Goal::new( - self.tcx(), + self.cx(), self.fields.param_env, ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: false, @@ -134,7 +134,7 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { (&ty::Error(e), _) | (_, &ty::Error(e)) => { infcx.set_tainted_by_errors(e); - return Ok(Ty::new_error(self.tcx(), e)); + return Ok(Ty::new_error(self.cx(), e)); } ( diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index ebf0d7ed737f..61c03922ac05 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -69,7 +69,7 @@ impl<'tcx> Relate> for ty::Pattern<'tcx> { if inc_a != inc_b { todo!() } - Ok(relation.tcx().mk_pat(ty::PatternKind::Range { start, end, include_end: inc_a })) + Ok(relation.cx().mk_pat(ty::PatternKind::Range { start, end, include_end: inc_a })) } } } @@ -81,7 +81,7 @@ impl<'tcx> Relate> for &'tcx ty::List RelateResult<'tcx, Self> { - let tcx = relation.tcx(); + let tcx = relation.cx(); // FIXME: this is wasteful, but want to do a perf run to see how slow it is. // We need to perform this deduplication as we sometimes generate duplicate projections diff --git a/compiler/rustc_trait_selection/src/traits/select/_match.rs b/compiler/rustc_trait_selection/src/traits/select/_match.rs index 50d8e96aaf91..8676f30a53b6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/_match.rs +++ b/compiler/rustc_trait_selection/src/traits/select/_match.rs @@ -36,7 +36,7 @@ impl<'tcx> TypeRelation> for MatchAgainstFreshVars<'tcx> { "MatchAgainstFreshVars" } - fn tcx(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -77,7 +77,7 @@ impl<'tcx> TypeRelation> for MatchAgainstFreshVars<'tcx> { Err(TypeError::Sorts(ExpectedFound::new(true, a, b))) } - (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.tcx(), guar)), + (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.cx(), guar)), _ => structurally_relate_tys(self, a, b), } From 1d40d4c4f496ce26d2cbf268b2f415e1f3bd5616 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 12 Jul 2024 16:18:51 -0400 Subject: [PATCH 283/734] Fix precise capturing suggestion for hidden type when APITs are involved --- compiler/rustc_infer/messages.ftl | 5 + .../src/error_reporting/infer/region.rs | 102 +++++++++++++++--- compiler/rustc_infer/src/errors/mod.rs | 22 ++++ .../hidden-type-suggestion.rs | 12 +++ .../hidden-type-suggestion.stderr | 44 +++++++- 5 files changed, 169 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index 7a5e71599203..c279195a7e99 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -225,6 +225,8 @@ infer_outlives_content = lifetime of reference outlives lifetime of borrowed con infer_precise_capturing_existing = add `{$new_lifetime}` to the `use<...>` bound to explicitly capture it infer_precise_capturing_new = add a `use<...>` bound to explicitly capture `{$new_lifetime}` +infer_precise_capturing_new_but_apit = add a `use<...>` bound to explicitly capture `{$new_lifetime}` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate + infer_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here... infer_prlf_defined_without_sub = the lifetime defined here... infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 for more information) @@ -387,6 +389,9 @@ infer_type_annotations_needed = {$source_kind -> .label = type must be known at this point infer_types_declared_different = these two types are declared with different lifetimes... + +infer_warn_removing_apit_params = you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable + infer_where_copy_predicates = copy the `where` clause predicates from the trait infer_where_remove = remove the `where` clause diff --git a/compiler/rustc_infer/src/error_reporting/infer/region.rs b/compiler/rustc_infer/src/error_reporting/infer/region.rs index 093d2d3d743d..5d41bb5d2710 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/region.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/region.rs @@ -1269,9 +1269,13 @@ fn suggest_precise_capturing<'tcx>( captured_lifetime: ty::Region<'tcx>, diag: &mut Diag<'_>, ) { - let hir::OpaqueTy { bounds, .. } = + let hir::OpaqueTy { bounds, origin, .. } = tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); + let hir::OpaqueTyOrigin::FnReturn(fn_def_id) = *origin else { + return; + }; + let new_lifetime = Symbol::intern(&captured_lifetime.to_string()); if let Some((args, span)) = bounds.iter().find_map(|bound| match bound { @@ -1306,6 +1310,7 @@ fn suggest_precise_capturing<'tcx>( let variances = tcx.variances_of(opaque_def_id); let mut generics = tcx.generics_of(opaque_def_id); + let mut synthetics = vec![]; loop { for param in &generics.own_params { if variances[param.index as usize] == ty::Bivariant { @@ -1317,9 +1322,7 @@ fn suggest_precise_capturing<'tcx>( captured_lifetimes.insert(param.name); } ty::GenericParamDefKind::Type { synthetic: true, .. } => { - // FIXME: We can't provide a good suggestion for - // `use<...>` if we have an APIT. Bail for now. - return; + synthetics.push((tcx.def_span(param.def_id), param.name)); } ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } => { @@ -1340,17 +1343,86 @@ fn suggest_precise_capturing<'tcx>( return; } - let concatenated_bounds = captured_lifetimes - .into_iter() - .chain(captured_non_lifetimes) - .map(|sym| sym.to_string()) - .collect::>() - .join(", "); + if synthetics.is_empty() { + let concatenated_bounds = captured_lifetimes + .into_iter() + .chain(captured_non_lifetimes) + .map(|sym| sym.to_string()) + .collect::>() + .join(", "); - diag.subdiagnostic(errors::AddPreciseCapturing::New { - span: tcx.def_span(opaque_def_id).shrink_to_hi(), - new_lifetime, - concatenated_bounds, - }); + diag.subdiagnostic(errors::AddPreciseCapturing::New { + span: tcx.def_span(opaque_def_id).shrink_to_hi(), + new_lifetime, + concatenated_bounds, + }); + } else { + let mut next_fresh_param = || { + ["T", "U", "V", "W", "X", "Y", "A", "B", "C"] + .into_iter() + .map(Symbol::intern) + .chain((0..).map(|i| Symbol::intern(&format!("T{i}")))) + .find(|s| captured_non_lifetimes.insert(*s)) + .unwrap() + }; + + let mut new_params = String::new(); + let mut suggs = vec![]; + let mut apit_spans = vec![]; + + for (i, (span, name)) in synthetics.into_iter().enumerate() { + apit_spans.push(span); + + let fresh_param = next_fresh_param(); + + // Suggest renaming. + suggs.push((span, fresh_param.to_string())); + + // Super jank. Turn `impl Trait` into `T: Trait`. + // + // This currently involves stripping the `impl` from the name of + // the parameter, since APITs are always named after how they are + // rendered in the AST. This sucks! But to recreate the bound list + // from the APIT itself would be miserable, so we're stuck with + // this for now! + if i > 0 { + new_params += ", "; + } + let name_as_bounds = name.as_str().trim_start_matches("impl").trim_start(); + new_params += fresh_param.as_str(); + new_params += ": "; + new_params += name_as_bounds; + } + + let Some(generics) = tcx.hir().get_generics(fn_def_id) else { + // This shouldn't happen, but don't ICE. + return; + }; + + // Add generics or concatenate to the end of the list. + suggs.push(if let Some(params_span) = generics.span_for_param_suggestion() { + (params_span, format!(", {new_params}")) + } else { + (generics.span, format!("<{new_params}>")) + }); + + let concatenated_bounds = captured_lifetimes + .into_iter() + .chain(captured_non_lifetimes) + .map(|sym| sym.to_string()) + .collect::>() + .join(", "); + + suggs.push(( + tcx.def_span(opaque_def_id).shrink_to_hi(), + format!(" + use<{concatenated_bounds}>"), + )); + + diag.subdiagnostic(errors::AddPreciseCapturingAndParams { + suggs, + new_lifetime, + apit_spans, + }); + } } } diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index f849a1a73224..2ce712e0bff5 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1609,3 +1609,25 @@ pub enum AddPreciseCapturing { post: &'static str, }, } + +pub struct AddPreciseCapturingAndParams { + pub suggs: Vec<(Span, String)>, + pub new_lifetime: Symbol, + pub apit_spans: Vec, +} + +impl Subdiagnostic for AddPreciseCapturingAndParams { + fn add_to_diag_with>( + self, + diag: &mut Diag<'_, G>, + _f: &F, + ) { + diag.arg("new_lifetime", self.new_lifetime); + diag.multipart_suggestion_verbose( + fluent::infer_precise_capturing_new_but_apit, + self.suggs, + Applicability::MaybeIncorrect, + ); + diag.span_note(self.apit_spans, fluent::infer_warn_removing_apit_params); + } +} diff --git a/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs index e0b115b0ce41..b50780643f1c 100644 --- a/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs +++ b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs @@ -27,4 +27,16 @@ fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<' //~^ ERROR hidden type for } +fn no_params_yet(_: impl Sized, y: &()) -> impl Sized { +//~^ HELP add a `use<...>` bound + y +//~^ ERROR hidden type for +} + +fn yes_params_yet<'a, T>(_: impl Sized, y: &'a ()) -> impl Sized { +//~^ HELP add a `use<...>` bound + y +//~^ ERROR hidden type for +} + fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr index 391f16d012e4..1007a835894e 100644 --- a/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr +++ b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr @@ -62,6 +62,48 @@ help: add a `use<...>` bound to explicitly capture `'a` LL | fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<'captured> + use<'captured, 'a, Captured> { | ++++++++++++++++++++++++++++++ -error: aborting due to 4 previous errors +error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds + --> $DIR/hidden-type-suggestion.rs:32:5 + | +LL | fn no_params_yet(_: impl Sized, y: &()) -> impl Sized { + | --- ---------- opaque type defined here + | | + | hidden type `&()` captures the anonymous lifetime defined here +LL | +LL | y + | ^ + | +note: you could use a `use<...>` bound to explicitly capture `'_`, but argument-position `impl Trait`s are not nameable + --> $DIR/hidden-type-suggestion.rs:30:21 + | +LL | fn no_params_yet(_: impl Sized, y: &()) -> impl Sized { + | ^^^^^^^^^^ +help: add a `use<...>` bound to explicitly capture `'_` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate + | +LL | fn no_params_yet(_: T, y: &()) -> impl Sized + use<'_, T> { + | ++++++++++ ~ ++++++++++++ + +error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds + --> $DIR/hidden-type-suggestion.rs:38:5 + | +LL | fn yes_params_yet<'a, T>(_: impl Sized, y: &'a ()) -> impl Sized { + | -- ---------- opaque type defined here + | | + | hidden type `&'a ()` captures the lifetime `'a` as defined here +LL | +LL | y + | ^ + | +note: you could use a `use<...>` bound to explicitly capture `'a`, but argument-position `impl Trait`s are not nameable + --> $DIR/hidden-type-suggestion.rs:36:29 + | +LL | fn yes_params_yet<'a, T>(_: impl Sized, y: &'a ()) -> impl Sized { + | ^^^^^^^^^^ +help: add a `use<...>` bound to explicitly capture `'a` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate + | +LL | fn yes_params_yet<'a, T, U: Sized>(_: U, y: &'a ()) -> impl Sized + use<'a, T, U> { + | ++++++++++ ~ +++++++++++++++ + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0700`. From da2054f389fbf631b0082dd3cdaf8724f9e93f56 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 12 Jul 2024 13:07:16 -0400 Subject: [PATCH 284/734] Add cross-crate precise capturing support to rustdoc --- compiler/rustc_hir_analysis/src/collect.rs | 21 ++++++++++++ .../src/rmeta/decoder/cstore_impl.rs | 10 ++++++ compiler/rustc_metadata/src/rmeta/encoder.rs | 10 ++++++ compiler/rustc_metadata/src/rmeta/mod.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 8 +++++ src/librustdoc/clean/mod.rs | 34 +++++++++---------- tests/rustdoc/auxiliary/precise-capturing.rs | 7 ++++ tests/rustdoc/impl-trait-precise-capturing.rs | 13 +++++++ 8 files changed, 87 insertions(+), 17 deletions(-) create mode 100644 tests/rustdoc/auxiliary/precise-capturing.rs diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index e0aad2991632..8318e1f8955c 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -84,6 +84,7 @@ pub fn provide(providers: &mut Providers) { coroutine_kind, coroutine_for_closure, is_type_alias_impl_trait, + rendered_precise_capturing_args, ..*providers }; } @@ -1880,3 +1881,23 @@ fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool _ => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id), } } + +fn rendered_precise_capturing_args<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> Option<&'tcx [Symbol]> { + if let Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) = + tcx.opt_rpitit_info(def_id.to_def_id()) + { + return tcx.rendered_precise_capturing_args(opaque_def_id); + } + + tcx.hir_node_by_def_id(def_id).expect_item().expect_opaque_ty().bounds.iter().find_map( + |bound| match bound { + hir::GenericBound::Use(args, ..) => { + Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| arg.name()))) + } + _ => None, + }, + ) +} diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 6b240f0f0b3d..bbd9ab5704fd 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -72,6 +72,15 @@ impl<'a, 'tcx, T: Copy + Decodable>> ProcessQueryValue<' } } +impl<'a, 'tcx, T: Copy + Decodable>> + ProcessQueryValue<'tcx, Option<&'tcx [T]>> for Option> +{ + #[inline(always)] + fn process_decoded(self, tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> Option<&'tcx [T]> { + if let Some(iter) = self { Some(&*tcx.arena.alloc_from_iter(iter)) } else { None } + } +} + impl ProcessQueryValue<'_, Option> for Option { #[inline(always)] fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> Option { @@ -249,6 +258,7 @@ provide! { tcx, def_id, other, cdata, .process_decoded(tcx, || panic!("{def_id:?} does not have coerce_unsized_info"))) } mir_const_qualif => { table } rendered_const => { table } + rendered_precise_capturing_args => { table } asyncness => { table_direct } fn_arg_names => { table } coroutine_kind => { table_direct } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 209316ca20fd..8596a0645e4a 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1496,6 +1496,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tables .is_type_alias_impl_trait .set(def_id.index, self.tcx.is_type_alias_impl_trait(def_id)); + self.encode_precise_capturing_args(def_id); } if tcx.impl_method_has_trait_impl_trait_tys(def_id) && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id) @@ -1635,6 +1636,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tables.assumed_wf_types_for_rpitit[def_id] <- self.tcx.assumed_wf_types_for_rpitit(def_id) ); + self.encode_precise_capturing_args(def_id); } } if item.is_effects_desugaring { @@ -1642,6 +1644,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } + fn encode_precise_capturing_args(&mut self, def_id: DefId) { + let Some(precise_capturing_args) = self.tcx.rendered_precise_capturing_args(def_id) else { + return; + }; + + record_array!(self.tables.rendered_precise_capturing_args[def_id] <- precise_capturing_args); + } + fn encode_mir(&mut self) { if self.is_proc_macro { return; diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 2a44b3423ae2..e565c8c1ea1c 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -442,6 +442,7 @@ define_tables! { coerce_unsized_info: Table>, mir_const_qualif: Table>, rendered_const: Table>, + rendered_precise_capturing_args: Table>, asyncness: Table, fn_arg_names: Table>, coroutine_kind: Table, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 817c7157b682..c7ea1d433836 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1261,6 +1261,7 @@ rustc_queries! { desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) } separate_provide_extern } + /// Gets the rendered value of the specified constant or associated constant. /// Used by rustdoc. query rendered_const(def_id: DefId) -> &'tcx String { @@ -1268,6 +1269,13 @@ rustc_queries! { desc { |tcx| "rendering constant initializer of `{}`", tcx.def_path_str(def_id) } separate_provide_extern } + + /// Gets the rendered precise capturing args for an opaque for use in rustdoc. + query rendered_precise_capturing_args(def_id: DefId) -> Option<&'tcx [Symbol]> { + desc { |tcx| "rendering precise capturing args for `{}`", tcx.def_path_str(def_id) } + separate_provide_extern + } + query impl_parent(def_id: DefId) -> Option { desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) } separate_provide_extern diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a0e28d2f55c7..4dd065f56808 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -461,13 +461,7 @@ fn clean_projection<'tcx>( def_id: Option, ) -> Type { if cx.tcx.is_impl_trait_in_trait(ty.skip_binder().def_id) { - let bounds = cx - .tcx - .explicit_item_bounds(ty.skip_binder().def_id) - .iter_instantiated_copied(cx.tcx, ty.skip_binder().args) - .map(|(pred, _)| pred) - .collect::>(); - return clean_middle_opaque_bounds(cx, bounds); + return clean_middle_opaque_bounds(cx, ty.skip_binder().def_id, ty.skip_binder().args); } let trait_ = clean_trait_ref_with_constraints( @@ -2243,13 +2237,7 @@ pub(crate) fn clean_middle_ty<'tcx>( *cx.current_type_aliases.entry(def_id).or_insert(0) += 1; // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the bounds associated with the def_id. - let bounds = cx - .tcx - .explicit_item_bounds(def_id) - .iter_instantiated_copied(cx.tcx, args) - .map(|(bound, _)| bound) - .collect::>(); - let ty = clean_middle_opaque_bounds(cx, bounds); + let ty = clean_middle_opaque_bounds(cx, def_id, args); if let Some(count) = cx.current_type_aliases.get_mut(&def_id) { *count -= 1; if *count == 0 { @@ -2272,12 +2260,20 @@ pub(crate) fn clean_middle_ty<'tcx>( fn clean_middle_opaque_bounds<'tcx>( cx: &mut DocContext<'tcx>, - bounds: Vec>, + impl_trait_def_id: DefId, + args: ty::GenericArgsRef<'tcx>, ) -> Type { let mut has_sized = false; + + let bounds: Vec<_> = cx + .tcx + .explicit_item_bounds(impl_trait_def_id) + .iter_instantiated_copied(cx.tcx, args) + .collect(); + let mut bounds = bounds .iter() - .filter_map(|bound| { + .filter_map(|(bound, _)| { let bound_predicate = bound.kind(); let trait_ref = match bound_predicate.skip_binder() { ty::ClauseKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref), @@ -2296,7 +2292,7 @@ fn clean_middle_opaque_bounds<'tcx>( let bindings: ThinVec<_> = bounds .iter() - .filter_map(|bound| { + .filter_map(|(bound, _)| { if let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder() { if proj.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder() { Some(AssocItemConstraint { @@ -2336,6 +2332,10 @@ fn clean_middle_opaque_bounds<'tcx>( bounds.insert(0, GenericBound::sized(cx)); } + if let Some(args) = cx.tcx.rendered_precise_capturing_args(impl_trait_def_id) { + bounds.push(GenericBound::Use(args.to_vec())); + } + ImplTrait(bounds) } diff --git a/tests/rustdoc/auxiliary/precise-capturing.rs b/tests/rustdoc/auxiliary/precise-capturing.rs new file mode 100644 index 000000000000..531d4dfdccc6 --- /dev/null +++ b/tests/rustdoc/auxiliary/precise-capturing.rs @@ -0,0 +1,7 @@ +#![feature(precise_capturing)] + +pub fn cross_crate_empty() -> impl Sized + use<> {} + +pub fn cross_crate_missing() -> impl Sized {} + +pub fn cross_crate_args<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {} diff --git a/tests/rustdoc/impl-trait-precise-capturing.rs b/tests/rustdoc/impl-trait-precise-capturing.rs index d1987a555c15..a964a1f8518f 100644 --- a/tests/rustdoc/impl-trait-precise-capturing.rs +++ b/tests/rustdoc/impl-trait-precise-capturing.rs @@ -1,6 +1,10 @@ +//@ aux-build:precise-capturing.rs + #![crate_name = "foo"] #![feature(precise_capturing)] +extern crate precise_capturing; + //@ has foo/fn.two.html '//section[@id="main-content"]//pre' "-> impl Sized + use<'b, 'a>" pub fn two<'a, 'b, 'c>() -> impl Sized + use<'b, 'a /* no 'c */> {} @@ -12,3 +16,12 @@ pub fn none() -> impl Sized + use<> {} //@ has foo/fn.first.html '//section[@id="main-content"]//pre' "-> impl use<> + Sized" pub fn first() -> impl use<> + Sized {} + +//@ has foo/fn.cross_crate_empty.html '//section[@id="main-content"]//pre' "-> impl Sized + use<>" +pub use precise_capturing::cross_crate_empty; + +//@ matches foo/fn.cross_crate_missing.html '//section[@id="main-content"]//pre' "-> impl Sized$" +pub use precise_capturing::cross_crate_missing; + +//@ has foo/fn.cross_crate_args.html '//section[@id="main-content"]//pre' "-> impl Sized + use<'a, T, N>" +pub use precise_capturing::cross_crate_args; From b84e2b7c98c687b07e28458db1e8ca68157b0d15 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 15 Jul 2024 17:51:15 -0400 Subject: [PATCH 285/734] Put the dots back --- compiler/rustc_middle/src/ty/print/pretty.rs | 7 +- .../return-type-notation/basic.without.stderr | 4 +- .../return-type-notation/display.rs | 25 ++++++ .../return-type-notation/display.stderr | 78 +++++++++++++++++++ .../issue-110963-early.stderr | 8 +- 5 files changed, 114 insertions(+), 8 deletions(-) create mode 100644 tests/ui/associated-type-bounds/return-type-notation/display.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/display.stderr diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index df080b2887b8..57cd2dc73c41 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1214,11 +1214,14 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { && let ty::Alias(_, alias_ty) = self.tcx().fn_sig(fn_def_id).skip_binder().output().skip_binder().kind() && alias_ty.def_id == def_id + && let generics = self.tcx().generics_of(fn_def_id) + // FIXME(return_type_notation): We only support lifetime params for now. + && generics.own_params.iter().all(|param| matches!(param.kind, ty::GenericParamDefKind::Lifetime)) { - let num_args = self.tcx().generics_of(fn_def_id).count(); + let num_args = generics.count(); write!(self, " {{ ")?; self.print_def_path(fn_def_id, &args[..num_args])?; - write!(self, "() }}")?; + write!(self, "(..) }}")?; } Ok(()) diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr index dde7036231e2..e9fd8503296e 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr @@ -13,12 +13,12 @@ error: future cannot be sent between threads safely LL | is_send(foo::()); | ^^^^^^^^^^ future returned by `foo` is not `Send` | - = help: within `impl Future>`, the trait `Send` is not implemented for `impl Future> { ::method() }`, which is required by `impl Future>: Send` + = help: within `impl Future>`, the trait `Send` is not implemented for `impl Future> { ::method(..) }`, which is required by `impl Future>: Send` note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/basic.rs:13:5 | LL | T::method().await?; - | ^^^^^^^^^^^ await occurs here on type `impl Future> { ::method() }`, which is not `Send` + | ^^^^^^^^^^^ await occurs here on type `impl Future> { ::method(..) }`, which is not `Send` note: required by a bound in `is_send` --> $DIR/basic.rs:17:20 | diff --git a/tests/ui/associated-type-bounds/return-type-notation/display.rs b/tests/ui/associated-type-bounds/return-type-notation/display.rs new file mode 100644 index 000000000000..c5be2ca00ea1 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/display.rs @@ -0,0 +1,25 @@ +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait Trait {} +fn needs_trait(_: impl Trait) {} + +trait Assoc { + fn method() -> impl Sized; + fn method_with_lt() -> impl Sized; + fn method_with_ty() -> impl Sized; + fn method_with_ct() -> impl Sized; +} + +fn foo(t: T) { + needs_trait(T::method()); + //~^ ERROR the trait bound + needs_trait(T::method_with_lt()); + //~^ ERROR the trait bound + needs_trait(T::method_with_ty()); + //~^ ERROR the trait bound + needs_trait(T::method_with_ct()); + //~^ ERROR the trait bound +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/display.stderr b/tests/ui/associated-type-bounds/return-type-notation/display.stderr new file mode 100644 index 000000000000..4915ec1aa831 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/display.stderr @@ -0,0 +1,78 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/display.rs:1:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: the trait bound `impl Sized { ::method(..) }: Trait` is not satisfied + --> $DIR/display.rs:15:17 + | +LL | needs_trait(T::method()); + | ----------- ^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Sized { ::method(..) }` + | | + | required by a bound introduced by this call + | +note: required by a bound in `needs_trait` + --> $DIR/display.rs:5:24 + | +LL | fn needs_trait(_: impl Trait) {} + | ^^^^^ required by this bound in `needs_trait` + +error[E0277]: the trait bound `impl Sized { ::method_with_lt(..) }: Trait` is not satisfied + --> $DIR/display.rs:17:17 + | +LL | needs_trait(T::method_with_lt()); + | ----------- ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Sized { ::method_with_lt(..) }` + | | + | required by a bound introduced by this call + | +note: required by a bound in `needs_trait` + --> $DIR/display.rs:5:24 + | +LL | fn needs_trait(_: impl Trait) {} + | ^^^^^ required by this bound in `needs_trait` + +error[E0277]: the trait bound `impl Sized: Trait` is not satisfied + --> $DIR/display.rs:19:17 + | +LL | needs_trait(T::method_with_ty()); + | ----------- ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Sized` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/display.rs:4:1 + | +LL | trait Trait {} + | ^^^^^^^^^^^ +note: required by a bound in `needs_trait` + --> $DIR/display.rs:5:24 + | +LL | fn needs_trait(_: impl Trait) {} + | ^^^^^ required by this bound in `needs_trait` + +error[E0277]: the trait bound `impl Sized: Trait` is not satisfied + --> $DIR/display.rs:21:17 + | +LL | needs_trait(T::method_with_ct()); + | ----------- ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Sized` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/display.rs:4:1 + | +LL | trait Trait {} + | ^^^^^^^^^^^ +note: required by a bound in `needs_trait` + --> $DIR/display.rs:5:24 + | +LL | fn needs_trait(_: impl Trait) {} + | ^^^^^ required by this bound in `needs_trait` + +error: aborting due to 4 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.stderr index 23ede089b5a8..acad8bd37917 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.stderr @@ -18,8 +18,8 @@ LL | | } LL | | }); | |______^ implementation of `Send` is not general enough | - = note: `Send` would have to be implemented for the type `impl Future { ::check<'0>() }`, for any two lifetimes `'0` and `'1`... - = note: ...but `Send` is actually implemented for the type `impl Future { ::check<'2>() }`, for some specific lifetime `'2` + = note: `Send` would have to be implemented for the type `impl Future { ::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... + = note: ...but `Send` is actually implemented for the type `impl Future { ::check<'2>(..) }`, for some specific lifetime `'2` error: implementation of `Send` is not general enough --> $DIR/issue-110963-early.rs:14:5 @@ -32,8 +32,8 @@ LL | | } LL | | }); | |______^ implementation of `Send` is not general enough | - = note: `Send` would have to be implemented for the type `impl Future { ::check<'0>() }`, for any two lifetimes `'0` and `'1`... - = note: ...but `Send` is actually implemented for the type `impl Future { ::check<'2>() }`, for some specific lifetime `'2` + = note: `Send` would have to be implemented for the type `impl Future { ::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... + = note: ...but `Send` is actually implemented for the type `impl Future { ::check<'2>(..) }`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 2 previous errors; 1 warning emitted From 2b5a9821eb730ab2e294bc2600af8ee580421e27 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 17 Jul 2024 18:14:54 +0300 Subject: [PATCH 286/734] abstract merge-base commit logic Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/llvm.rs | 33 ++++++++------------ src/bootstrap/src/core/config/config.rs | 36 ++++++++++------------ src/bootstrap/src/utils/helpers.rs | 24 +++++++++++++++ src/tools/build_helper/src/git.rs | 2 +- 4 files changed, 54 insertions(+), 41 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 888290a0479b..b6b890674620 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -26,7 +26,6 @@ use crate::{generate_smart_stamp_hash, CLang, GitRepo, Kind}; use crate::utils::exec::command; use build_helper::ci::CiEnv; -use build_helper::git::get_git_merge_base; #[derive(Clone)] pub struct LlvmResult { @@ -154,26 +153,18 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L /// This retrieves the LLVM sha we *want* to use, according to git history. pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String { let llvm_sha = if is_git { - // We proceed in 2 steps. First we get the closest commit that is actually upstream. Then we - // walk back further to the last bors merge commit that actually changed LLVM. The first - // step will fail on CI because only the `auto` branch exists; we just fall back to `HEAD` - // in that case. - let closest_upstream = get_git_merge_base(&config.git_config(), Some(&config.src)) - .unwrap_or_else(|_| "HEAD".into()); - let mut rev_list = helpers::git(Some(&config.src)); - rev_list.args(&[ - PathBuf::from("rev-list"), - format!("--author={}", config.stage0_metadata.config.git_merge_commit_email).into(), - "-n1".into(), - "--first-parent".into(), - closest_upstream.into(), - "--".into(), - config.src.join("src/llvm-project"), - config.src.join("src/bootstrap/download-ci-llvm-stamp"), - // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly` - config.src.join("src/version"), - ]); - output(rev_list.as_command_mut()).trim().to_owned() + helpers::get_closest_merge_base_commit( + Some(&config.src), + &config.git_config(), + &config.stage0_metadata.config.git_merge_commit_email, + &[ + config.src.join("src/llvm-project"), + config.src.join("src/bootstrap/download-ci-llvm-stamp"), + // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly` + config.src.join("src/version"), + ], + ) + .unwrap() } else if let Some(info) = channel::read_commit_info_file(&config.src) { info.sha.trim().to_owned() } else { diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index f96633b059a1..9d5aa795c6c0 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -20,7 +20,7 @@ use crate::core::build_steps::llvm; use crate::core::config::flags::{Color, Flags, Warnings}; use crate::utils::cache::{Interned, INTERNER}; use crate::utils::channel::{self, GitInfo}; -use crate::utils::helpers::{self, exe, output, t}; +use crate::utils::helpers::{self, exe, get_closest_merge_base_commit, output, t}; use build_helper::exit; use serde::{Deserialize, Deserializer}; use serde_derive::Deserialize; @@ -2471,14 +2471,13 @@ impl Config { // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. - let merge_base = output( - helpers::git(Some(&self.src)) - .arg("rev-list") - .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email)) - .args(["-n1", "--first-parent", "HEAD"]) - .as_command_mut(), - ); - let commit = merge_base.trim_end(); + let commit = get_closest_merge_base_commit( + Some(&self.src), + &self.git_config(), + &self.stage0_metadata.config.git_merge_commit_email, + &[], + ) + .unwrap(); if commit.is_empty() { println!("ERROR: could not find commit hash for downloading rustc"); println!("HELP: maybe your repository history is too shallow?"); @@ -2489,7 +2488,7 @@ impl Config { // Warn if there were changes to the compiler or standard library since the ancestor commit. let has_changes = !t!(helpers::git(Some(&self.src)) - .args(["diff-index", "--quiet", commit]) + .args(["diff-index", "--quiet", &commit]) .arg("--") .args([self.src.join("compiler"), self.src.join("library")]) .as_command_mut() @@ -2565,14 +2564,13 @@ impl Config { ) -> Option { // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. - let merge_base = output( - helpers::git(Some(&self.src)) - .arg("rev-list") - .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email)) - .args(["-n1", "--first-parent", "HEAD"]) - .as_command_mut(), - ); - let commit = merge_base.trim_end(); + let commit = get_closest_merge_base_commit( + Some(&self.src), + &self.git_config(), + &self.stage0_metadata.config.git_merge_commit_email, + &[], + ) + .unwrap(); if commit.is_empty() { println!("error: could not find commit hash for downloading components from CI"); println!("help: maybe your repository history is too shallow?"); @@ -2583,7 +2581,7 @@ impl Config { // Warn if there were changes to the compiler or standard library since the ancestor commit. let mut git = helpers::git(Some(&self.src)); - git.args(["diff-index", "--quiet", commit, "--"]); + git.args(["diff-index", "--quiet", &commit, "--"]); // Handle running from a directory other than the top level let top_level = &self.src; diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 3c82fa189be3..773a873e47cc 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -3,6 +3,7 @@ //! Simple things like testing the various filesystem operations here and there, //! not a lot of interesting happenings here unfortunately. +use build_helper::git::{get_git_merge_base, output_result, GitConfig}; use build_helper::util::fail; use std::env; use std::ffi::OsStr; @@ -521,3 +522,26 @@ pub fn git(source_dir: Option<&Path>) -> BootstrapCommand { git } + +/// Returns the closest commit available from upstream for the given `author` and `target_paths`. +/// +/// If it fails to find the commit from upstream using `git merge-base`, fallbacks to HEAD. +pub fn get_closest_merge_base_commit( + source_dir: Option<&Path>, + config: &GitConfig<'_>, + author: &str, + target_paths: &[PathBuf], +) -> Result { + let mut git = git(source_dir).capture_stdout(); + + let merge_base = get_git_merge_base(config, source_dir).unwrap_or_else(|_| "HEAD".into()); + + git.arg(Path::new("rev-list")); + git.args([&format!("--author={author}"), "-n1", "--first-parent", &merge_base]); + + if !target_paths.is_empty() { + git.arg("--").args(target_paths); + } + + Ok(output_result(git.as_command_mut())?.trim().to_owned()) +} diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs index b4522de6897d..8be38dc855f7 100644 --- a/src/tools/build_helper/src/git.rs +++ b/src/tools/build_helper/src/git.rs @@ -7,7 +7,7 @@ pub struct GitConfig<'a> { } /// Runs a command and returns the output -fn output_result(cmd: &mut Command) -> Result { +pub fn output_result(cmd: &mut Command) -> Result { let output = match cmd.stderr(Stdio::inherit()).output() { Ok(status) => status, Err(e) => return Err(format!("failed to run command: {:?}: {}", cmd, e)), From aebf4d07f3c4a9a3d20c10a4c4a16dac9f300b5d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 17 Jul 2024 08:31:40 -0700 Subject: [PATCH 287/734] Add `wasm32-wasip2` to `build-manifest` tool This is an accidental omission of mine from #126967 which means that `rustup target add wasm32-wasip2` isn't working on today's nightlies. --- src/tools/build-manifest/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index a2e7907b532e..e0bea5f053d9 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -157,6 +157,7 @@ static TARGETS: &[&str] = &[ "wasm32-wasi", "wasm32-wasip1", "wasm32-wasip1-threads", + "wasm32-wasip2", "x86_64-apple-darwin", "x86_64-apple-ios", "x86_64-fortanix-unknown-sgx", From f3f0b572640e32297d58b4edf36ef69c62e47305 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 16 Jul 2024 15:08:18 -0500 Subject: [PATCH 288/734] Commonize `uname -m` results for `aarch64` in docker runner `uname -m` on Linux reports `aarch64`, but on MacOS reports `arm64`. Commonize this to `aarch64`. With this fix, it is now possible to run aarch64 CI docker images on Arm MacOS. --- src/ci/docker/run.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 40f421714118..fad4b5af0953 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -27,8 +27,11 @@ do shift done +# MacOS reports "arm64" while Linux reports "aarch64". Commonize this. +machine="$(uname -m | sed 's/arm64/aarch64/')" + script_dir="`dirname $script`" -docker_dir="${script_dir}/host-$(uname -m)" +docker_dir="${script_dir}/host-${machine}" ci_dir="`dirname $script_dir`" src_dir="`dirname $ci_dir`" root_dir="`dirname $src_dir`" @@ -68,7 +71,7 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then # Include the architecture in the hash key, since our Linux CI does not # only run in x86_64 machines. - uname -m >> $hash_key + echo "$machine" >> $hash_key # Include cache version. Can be used to manually bust the Docker cache. echo "2" >> $hash_key @@ -178,7 +181,7 @@ elif [ -f "$docker_dir/disabled/$image/Dockerfile" ]; then build \ --rm \ -t rust-ci \ - -f "host-$(uname -m)/$image/Dockerfile" \ + -f "host-${machine}/$image/Dockerfile" \ - else echo Invalid image: $image @@ -201,7 +204,7 @@ else else continue fi - echo "Note: the current host architecture is $(uname -m)" + echo "Note: the current host architecture is $machine" done exit 1 From e34c6dbae5768b5dce90c02465f3492376327c65 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Fri, 12 Jul 2024 00:00:03 -0400 Subject: [PATCH 289/734] Refactor for using config values: * Construct lint passes by taking `Conf` by reference. * Use `HashSet` configs in less places * Move some `check_crate` code into the pass constructor when possible. --- book/src/development/adding_lints.md | 14 +- book/src/lint_configuration.md | 2 +- clippy_config/src/conf.rs | 14 +- clippy_config/src/types.rs | 14 +- clippy_dev/src/new_lint.rs | 8 +- clippy_lints/src/absolute_paths.rs | 12 +- clippy_lints/src/almost_complete_range.rs | 7 +- clippy_lints/src/approx_const.rs | 8 +- clippy_lints/src/assigning_clones.rs | 8 +- clippy_lints/src/attrs/mod.rs | 19 +- clippy_lints/src/await_holding_invalid.rs | 39 +- clippy_lints/src/cargo/mod.rs | 16 +- clippy_lints/src/casts/mod.rs | 8 +- clippy_lints/src/checked_conversions.rs | 8 +- clippy_lints/src/cognitive_complexity.rs | 6 +- clippy_lints/src/copies.rs | 14 +- clippy_lints/src/dbg_macro.rs | 6 +- clippy_lints/src/derivable_impls.rs | 8 +- clippy_lints/src/disallowed_macros.rs | 31 +- clippy_lints/src/disallowed_methods.rs | 42 +- clippy_lints/src/disallowed_names.rs | 11 +- clippy_lints/src/disallowed_script_idents.rs | 18 +- clippy_lints/src/disallowed_types.rs | 91 ++-- clippy_lints/src/doc/mod.rs | 12 +- clippy_lints/src/escape.rs | 12 +- clippy_lints/src/excessive_bools.rs | 8 +- clippy_lints/src/excessive_nesting.rs | 9 +- .../src/extra_unused_type_parameters.rs | 5 +- clippy_lints/src/format_args.rs | 8 +- clippy_lints/src/format_impl.rs | 1 - clippy_lints/src/from_over_into.rs | 8 +- clippy_lints/src/functions/mod.rs | 35 +- clippy_lints/src/if_then_some_else_none.rs | 8 +- clippy_lints/src/incompatible_msrv.rs | 5 +- clippy_lints/src/index_refutable_slice.rs | 7 +- clippy_lints/src/indexing_slicing.rs | 6 +- clippy_lints/src/instant_subtraction.rs | 8 +- clippy_lints/src/item_name_repetitions.rs | 20 +- clippy_lints/src/large_const_arrays.rs | 12 +- clippy_lints/src/large_enum_variant.rs | 7 +- clippy_lints/src/large_futures.rs | 8 +- clippy_lints/src/large_include_file.rs | 8 +- clippy_lints/src/large_stack_arrays.rs | 10 +- clippy_lints/src/large_stack_frames.rs | 6 +- clippy_lints/src/legacy_numeric_constants.rs | 8 +- clippy_lints/src/lib.rs | 460 ++++-------------- clippy_lints/src/literal_representation.rs | 18 +- clippy_lints/src/loops/mod.rs | 7 +- clippy_lints/src/macro_metavars_in_unsafe.rs | 20 +- clippy_lints/src/manual_bits.rs | 9 +- clippy_lints/src/manual_clamp.rs | 7 +- clippy_lints/src/manual_hash_one.rs | 8 +- clippy_lints/src/manual_is_ascii_check.rs | 8 +- clippy_lints/src/manual_main_separator_str.rs | 8 +- clippy_lints/src/manual_non_exhaustive.rs | 13 +- clippy_lints/src/manual_rem_euclid.rs | 8 +- clippy_lints/src/manual_retain.rs | 8 +- clippy_lints/src/manual_strip.rs | 8 +- clippy_lints/src/matches/mod.rs | 6 +- clippy_lints/src/mem_replace.rs | 8 +- clippy_lints/src/methods/mod.rs | 24 +- .../src/methods/path_ends_with_ext.rs | 2 +- clippy_lints/src/min_ident_chars.rs | 13 +- clippy_lints/src/missing_const_for_fn.rs | 8 +- .../src/missing_const_for_thread_local.rs | 8 +- clippy_lints/src/missing_doc.rs | 13 +- .../src/missing_enforced_import_rename.rs | 29 +- clippy_lints/src/mut_key.rs | 13 +- .../src/needless_borrows_for_generic_args.rs | 6 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 9 +- clippy_lints/src/non_copy_const.rs | 11 +- clippy_lints/src/non_expressive_names.rs | 23 +- .../src/non_send_fields_in_send_ty.rs | 6 +- clippy_lints/src/nonstandard_macro_braces.rs | 7 +- .../src/operators/arithmetic_side_effects.rs | 55 ++- clippy_lints/src/operators/mod.rs | 21 +- clippy_lints/src/panic_unimplemented.rs | 12 +- clippy_lints/src/pass_by_ref_or_value.rs | 19 +- clippy_lints/src/pub_underscore_fields.rs | 11 +- clippy_lints/src/question_mark.rs | 8 +- clippy_lints/src/ranges.rs | 8 +- clippy_lints/src/raw_strings.rs | 14 +- clippy_lints/src/redundant_field_names.rs | 8 +- .../src/redundant_static_lifetimes.rs | 8 +- clippy_lints/src/regex.rs | 2 +- clippy_lints/src/semicolon_block.rs | 12 +- clippy_lints/src/serde_api.rs | 2 +- clippy_lints/src/single_call_fn.rs | 13 +- clippy_lints/src/single_range_in_vec_init.rs | 2 +- clippy_lints/src/string_patterns.rs | 8 +- clippy_lints/src/trait_bounds.rs | 10 +- clippy_lints/src/transmute/mod.rs | 8 +- clippy_lints/src/tuple_array_conversions.rs | 11 +- clippy_lints/src/types/mod.rs | 9 +- .../src/undocumented_unsafe_blocks.rs | 8 +- clippy_lints/src/unnecessary_box_returns.rs | 7 +- clippy_lints/src/unnecessary_wraps.rs | 5 +- clippy_lints/src/unnested_or_patterns.rs | 8 +- clippy_lints/src/unused_self.rs | 5 +- clippy_lints/src/upper_case_acronyms.rs | 8 +- clippy_lints/src/use_self.rs | 6 +- .../interning_defined_symbol.rs | 2 +- .../src/utils/internal_lints/invalid_paths.rs | 2 +- .../internal_lints/unnecessary_def_path.rs | 4 +- clippy_lints/src/vec.rs | 20 +- clippy_lints/src/wildcard_imports.rs | 12 +- clippy_lints/src/write.rs | 8 +- clippy_utils/src/lib.rs | 27 +- clippy_utils/src/ty.rs | 8 +- clippy_utils/src/ty/type_certainty/mod.rs | 2 +- tests/ui-internal/disallow_span_lint.stderr | 4 +- .../await_holding_invalid_type.stderr | 10 +- .../disallowed_macros.stderr | 2 +- .../conf_disallowed_methods.stderr | 2 +- .../conf_disallowed_types.stderr | 44 +- 115 files changed, 824 insertions(+), 994 deletions(-) diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index 48c00bcbf341..a71d94daca74 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -458,9 +458,8 @@ pub struct ManualStrip { } impl ManualStrip { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { msrv: conf.msrv.clone() } } } ``` @@ -689,7 +688,6 @@ for some users. Adding a configuration is done in the following steps: ]); // New manual definition struct - #[derive(Copy, Clone)] pub struct StructName {} impl_lint_pass!(StructName => [ @@ -700,7 +698,6 @@ for some users. Adding a configuration is done in the following steps: 2. Next add the configuration value and a corresponding creation method like this: ```rust - #[derive(Copy, Clone)] pub struct StructName { configuration_ident: Type, } @@ -708,9 +705,9 @@ for some users. Adding a configuration is done in the following steps: // ... impl StructName { - pub fn new(configuration_ident: Type) -> Self { + pub fn new(conf: &'static Conf) -> Self { Self { - configuration_ident, + configuration_ident: conf.configuration_ident, } } } @@ -726,8 +723,7 @@ for some users. Adding a configuration is done in the following steps: store.register_*_pass(|| box module::StructName); // New registration with configuration value - let configuration_ident = conf.configuration_ident.clone(); - store.register_*_pass(move || box module::StructName::new(configuration_ident)); + store.register_*_pass(move || box module::StructName::new(conf)); ``` Congratulations the work is almost done. The configuration value can now be diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index a750f3619d0d..ce6cbc62a505 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -455,7 +455,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "AccessKit", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` +**Default Value:** `["TiB", "CoreGraphics", "CoffeeScript", "TeX", "Direct2D", "PiB", "DirectX", "NetBSD", "OAuth", "NaN", "OpenType", "WebGL2", "WebTransport", "JavaScript", "OpenSSL", "OpenSSH", "EiB", "PureScript", "OpenAL", "MiB", "WebAssembly", "MinGW", "CoreFoundation", "WebGPU", "ClojureScript", "CamelCase", "OpenDNS", "NaNs", "OpenMP", "GitLab", "KiB", "sRGB", "CoreText", "macOS", "TypeScript", "GiB", "OpenExr", "YCbCr", "OpenTelemetry", "OpenBSD", "FreeBSD", "GPLv2", "PostScript", "WebP", "LaTeX", "TensorFlow", "AccessKit", "TrueType", "OpenStreetMap", "OpenGL", "DevOps", "OCaml", "WebRTC", "WebGL", "BibLaTeX", "GitHub", "GraphQL", "iOS", "Direct3D", "BibTeX", "DirectWrite", "GPLv3", "IPv6", "WebSocket", "IPv4", "ECMAScript"]` --- **Affected lints:** diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 18e481b7af95..7eec3d4945a2 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -238,7 +238,7 @@ define_Conf! { /// /// A type, say `SomeType`, listed in this configuration has the same behavior of /// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`. - (arithmetic_side_effects_allowed: FxHashSet = <_>::default()), + (arithmetic_side_effects_allowed: Vec = <_>::default()), /// Lint: ARITHMETIC_SIDE_EFFECTS. /// /// Suppress checking of the passed type pair names in binary operations like addition or @@ -265,7 +265,7 @@ define_Conf! { /// ```toml /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] /// ``` - (arithmetic_side_effects_allowed_unary: FxHashSet = <_>::default()), + (arithmetic_side_effects_allowed_unary: Vec = <_>::default()), /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN, NEEDLESS_PASS_BY_REF_MUT. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. @@ -314,7 +314,7 @@ define_Conf! { /// default configuration of Clippy. By default, any configuration will replace the default value. For example: /// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. /// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. - (doc_valid_idents: Vec = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()), + (doc_valid_idents: FxHashSet = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()), /// Lint: TOO_MANY_ARGUMENTS. /// /// The maximum number of argument a function or method can have @@ -550,7 +550,7 @@ define_Conf! { /// Lint: PATH_ENDS_WITH_EXT. /// /// Additional dotfiles (files or directories starting with a dot) to allow - (allowed_dotfiles: FxHashSet = FxHashSet::default()), + (allowed_dotfiles: Vec = Vec::default()), /// Lint: MULTIPLE_CRATE_VERSIONS. /// /// A list of crate names to allow duplicates of @@ -703,7 +703,6 @@ pub fn lookup_conf_file() -> io::Result<(Option, Vec)> { fn deserialize(file: &SourceFile) -> TryConf { match toml::de::Deserializer::new(file.src.as_ref().unwrap()).deserialize_map(ConfVisitor(file)) { Ok(mut conf) => { - extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS); extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES); extend_vec_if_indicator_present(&mut conf.conf.allowed_prefixes, DEFAULT_ALLOWED_PREFIXES); extend_vec_if_indicator_present( @@ -716,6 +715,11 @@ fn deserialize(file: &SourceFile) -> TryConf { .allowed_idents_below_min_chars .extend(DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string)); } + if conf.conf.doc_valid_idents.contains("..") { + conf.conf + .doc_valid_idents + .extend(DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string)); + } conf }, diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs index 435aa9244c52..d47e34bb5bce 100644 --- a/clippy_config/src/types.rs +++ b/clippy_config/src/types.rs @@ -2,13 +2,13 @@ use serde::de::{self, Deserializer, Visitor}; use serde::{ser, Deserialize, Serialize}; use std::fmt; -#[derive(Clone, Debug, Deserialize)] +#[derive(Debug, Deserialize)] pub struct Rename { pub path: String, pub rename: String, } -#[derive(Clone, Debug, Deserialize)] +#[derive(Debug, Deserialize)] #[serde(untagged)] pub enum DisallowedPath { Simple(String), @@ -22,12 +22,10 @@ impl DisallowedPath { path } - pub fn reason(&self) -> Option { - match self { - Self::WithReason { - reason: Some(reason), .. - } => Some(format!("{reason} (from clippy.toml)")), - _ => None, + pub fn reason(&self) -> Option<&str> { + match &self { + Self::WithReason { reason, .. } => reason.as_deref(), + Self::Simple(_) => None, } } } diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index d762e30ef02e..de91233d196c 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -140,7 +140,7 @@ fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { let new_lint = if enable_msrv { format!( - "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(msrv())));\n ", + "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(conf)));\n ", lint_pass = lint.pass, ctor_arg = if lint.pass == "late" { "_" } else { "" }, module_name = lint.name, @@ -274,6 +274,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { formatdoc!( r#" use clippy_config::msrvs::{{self, Msrv}}; + use clippy_config::Conf; {pass_import} use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; use rustc_session::impl_lint_pass; @@ -301,9 +302,8 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { }} impl {name_camel} {{ - #[must_use] - pub fn new(msrv: Msrv) -> Self {{ - Self {{ msrv }} + pub fn new(conf: &'static Conf) -> Self {{ + Self {{ msrv: conf.msrv.clone() }} }} }} diff --git a/clippy_lints/src/absolute_paths.rs b/clippy_lints/src/absolute_paths.rs index 461117cf965d..c0a9d888e0b0 100644 --- a/clippy_lints/src/absolute_paths.rs +++ b/clippy_lints/src/absolute_paths.rs @@ -1,3 +1,4 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet_opt; use rustc_data_structures::fx::FxHashSet; @@ -47,7 +48,16 @@ impl_lint_pass!(AbsolutePaths => [ABSOLUTE_PATHS]); pub struct AbsolutePaths { pub absolute_paths_max_segments: u64, - pub absolute_paths_allowed_crates: FxHashSet, + pub absolute_paths_allowed_crates: &'static FxHashSet, +} + +impl AbsolutePaths { + pub fn new(conf: &'static Conf) -> Self { + Self { + absolute_paths_max_segments: conf.absolute_paths_max_segments, + absolute_paths_allowed_crates: &conf.absolute_paths_allowed_crates, + } + } } impl LateLintPass<'_> for AbsolutePaths { diff --git a/clippy_lints/src/almost_complete_range.rs b/clippy_lints/src/almost_complete_range.rs index 96e9c949b750..451bae959874 100644 --- a/clippy_lints/src/almost_complete_range.rs +++ b/clippy_lints/src/almost_complete_range.rs @@ -1,4 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{trim_span, walk_span_to_context}; use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits}; @@ -34,8 +35,10 @@ pub struct AlmostCompleteRange { msrv: Msrv, } impl AlmostCompleteRange { - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } impl EarlyLintPass for AlmostCompleteRange { diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index ec28fd461118..e6d52bcef717 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -1,4 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; @@ -67,9 +68,10 @@ pub struct ApproxConstant { } impl ApproxConstant { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } fn check_lit(&self, cx: &LateContext<'_>, lit: &LitKind, e: &Expr<'_>) { diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index 0de0031ed24f..03f777600f08 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -1,4 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap}; use clippy_utils::sugg::Sugg; @@ -57,9 +58,10 @@ pub struct AssigningClones { } impl AssigningClones { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 8ec60314cc9a..8f430ae601a8 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -16,6 +16,7 @@ mod useless_attribute; mod utils; use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; @@ -499,7 +500,6 @@ declare_clippy_lint! { "duplicated attribute" } -#[derive(Clone)] pub struct Attributes { msrv: Msrv, } @@ -517,9 +517,10 @@ impl_lint_pass!(Attributes => [ ]); impl Attributes { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } @@ -589,7 +590,15 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { } pub struct EarlyAttributes { - pub msrv: Msrv, + msrv: Msrv, +} + +impl EarlyAttributes { + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } + } } impl_lint_pass!(EarlyAttributes => [ diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index d4a1e2780d08..d5f017b26509 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -1,11 +1,11 @@ -use clippy_config::types::DisallowedPath; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{match_def_path, paths}; -use rustc_data_structures::fx::FxHashMap; +use clippy_utils::{create_disallowed_map, match_def_path, paths}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, DefIdMap}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::CoroutineLayout; +use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; @@ -172,31 +172,19 @@ declare_clippy_lint! { impl_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF, AWAIT_HOLDING_INVALID_TYPE]); -#[derive(Debug)] pub struct AwaitHolding { - conf_invalid_types: Vec, - def_ids: FxHashMap, + def_ids: DefIdMap<(&'static str, Option<&'static str>)>, } impl AwaitHolding { - pub(crate) fn new(conf_invalid_types: Vec) -> Self { + pub(crate) fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { Self { - conf_invalid_types, - def_ids: FxHashMap::default(), + def_ids: create_disallowed_map(tcx, &conf.await_holding_invalid_types), } } } impl<'tcx> LateLintPass<'tcx> for AwaitHolding { - fn check_crate(&mut self, cx: &LateContext<'tcx>) { - for conf in &self.conf_invalid_types { - let segs: Vec<_> = conf.path().split("::").collect(); - for id in clippy_utils::def_path_def_ids(cx, &segs) { - self.def_ids.insert(id, conf.clone()); - } - } - } - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { if let hir::ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)), @@ -258,25 +246,22 @@ impl AwaitHolding { ); }, ); - } else if let Some(disallowed) = self.def_ids.get(&adt.did()) { - emit_invalid_type(cx, ty_cause.source_info.span, disallowed); + } else if let Some(&(path, reason)) = self.def_ids.get(&adt.did()) { + emit_invalid_type(cx, ty_cause.source_info.span, path, reason); } } } } } -fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPath) { +fn emit_invalid_type(cx: &LateContext<'_>, span: Span, path: &'static str, reason: Option<&'static str>) { span_lint_and_then( cx, AWAIT_HOLDING_INVALID_TYPE, span, - format!( - "`{}` may not be held across an await point per `clippy.toml`", - disallowed.path() - ), + format!("holding a disallowed type across an await point `{path}`"), |diag| { - if let Some(reason) = disallowed.reason() { + if let Some(reason) = reason { diag.note(reason); } }, diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs index 593bc6c81ee8..312ad4c29900 100644 --- a/clippy_lints/src/cargo/mod.rs +++ b/clippy_lints/src/cargo/mod.rs @@ -5,6 +5,7 @@ mod multiple_crate_versions; mod wildcard_dependencies; use cargo_metadata::MetadataCommand; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_lint_allowed; use rustc_data_structures::fx::FxHashSet; @@ -204,8 +205,8 @@ declare_clippy_lint! { } pub struct Cargo { - pub allowed_duplicate_crates: FxHashSet, - pub ignore_publish: bool, + allowed_duplicate_crates: &'static FxHashSet, + ignore_publish: bool, } impl_lint_pass!(Cargo => [ @@ -217,6 +218,15 @@ impl_lint_pass!(Cargo => [ LINT_GROUPS_PRIORITY, ]); +impl Cargo { + pub fn new(conf: &'static Conf) -> Self { + Self { + allowed_duplicate_crates: &conf.allowed_duplicate_crates, + ignore_publish: conf.cargo_ignore_publish, + } + } +} + impl LateLintPass<'_> for Cargo { fn check_crate(&mut self, cx: &LateContext<'_>) { static NO_DEPS_LINTS: &[&Lint] = &[ @@ -253,7 +263,7 @@ impl LateLintPass<'_> for Cargo { { match MetadataCommand::new().exec() { Ok(metadata) => { - multiple_crate_versions::check(cx, &metadata, &self.allowed_duplicate_crates); + multiple_crate_versions::check(cx, &metadata, self.allowed_duplicate_crates); }, Err(e) => { for lint in WITH_DEPS_LINTS { diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index e9f9084af073..773731113ca8 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -24,6 +24,7 @@ mod utils; mod zero_ptr; use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::is_hir_ty_cfg_dependant; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -722,9 +723,10 @@ pub struct Casts { } impl Casts { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 1ec4b831a2c4..0b1ab5411bf1 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -1,6 +1,7 @@ //! lint on manually implemented checked conversions that could be transformed into `try_from` use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{in_constant, is_integer_literal, SpanlessEq}; @@ -40,9 +41,10 @@ pub struct CheckedConversions { } impl CheckedConversions { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 60815f4f2afb..5fa0522e4e5f 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -1,5 +1,6 @@ //! calculate cognitive complexity and warn about overly complex functions +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; @@ -39,10 +40,9 @@ pub struct CognitiveComplexity { } impl CognitiveComplexity { - #[must_use] - pub fn new(limit: u64) -> Self { + pub fn new(conf: &'static Conf) -> Self { Self { - limit: LimitStack::new(limit), + limit: LimitStack::new(conf.cognitive_complexity_threshold), } } } diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index d896452be920..86e0368c4e42 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,3 +1,4 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, IntoSpan, SpanRangeExt}; use clippy_utils::ty::{needs_ordered_drop, InteriorMut}; @@ -11,6 +12,7 @@ use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; use rustc_span::hygiene::walk_chain; use rustc_span::source_map::SourceMap; @@ -159,15 +161,13 @@ declare_clippy_lint! { } pub struct CopyAndPaste<'tcx> { - ignore_interior_mutability: Vec, interior_mut: InteriorMut<'tcx>, } -impl CopyAndPaste<'_> { - pub fn new(ignore_interior_mutability: Vec) -> Self { +impl<'tcx> CopyAndPaste<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf) -> Self { Self { - ignore_interior_mutability, - interior_mut: InteriorMut::default(), + interior_mut: InteriorMut::new(tcx, &conf.ignore_interior_mutability), } } } @@ -180,10 +180,6 @@ impl_lint_pass!(CopyAndPaste<'_> => [ ]); impl<'tcx> LateLintPass<'tcx> for CopyAndPaste<'tcx> { - fn check_crate(&mut self, cx: &LateContext<'tcx>) { - self.interior_mut = InteriorMut::new(cx, &self.ignore_interior_mutability); - } - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if !expr.span.from_expansion() && matches!(expr.kind, ExprKind::If(..)) && !is_else_clause(cx.tcx, expr) { let (conds, blocks) = if_sequence(expr); diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index b0590b0a71cb..788c6f3ada29 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -1,3 +1,4 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_in_test; use clippy_utils::macros::{macro_backtrace, MacroCall}; @@ -33,7 +34,6 @@ declare_clippy_lint! { "`dbg!` macro is intended as a debugging tool" } -#[derive(Clone)] pub struct DbgMacro { allow_dbg_in_tests: bool, /// Tracks the `dbg!` macro callsites that are already checked. @@ -45,9 +45,9 @@ pub struct DbgMacro { impl_lint_pass!(DbgMacro => [DBG_MACRO]); impl DbgMacro { - pub fn new(allow_dbg_in_tests: bool) -> Self { + pub fn new(conf: &'static Conf) -> Self { DbgMacro { - allow_dbg_in_tests, + allow_dbg_in_tests: conf.allow_dbg_in_tests, checked_dbg_call_site: FxHashSet::default(), prev_ctxt: SyntaxContext::root(), } diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 0c9ad5e8d001..f27f68e2cbc5 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -1,4 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::indent_of; use clippy_utils::{is_default_equivalent, peel_blocks}; @@ -60,9 +61,10 @@ pub struct DerivableImpls { } impl DerivableImpls { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - DerivableImpls { msrv } + pub fn new(conf: &'static Conf) -> Self { + DerivableImpls { + msrv: conf.msrv.clone(), + } } } diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs index 871f529da6c4..b51d343132b2 100644 --- a/clippy_lints/src/disallowed_macros.rs +++ b/clippy_lints/src/disallowed_macros.rs @@ -1,4 +1,5 @@ -use clippy_config::types::DisallowedPath; +use clippy_config::Conf; +use clippy_utils::create_disallowed_map; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::macros::macro_backtrace; use rustc_ast::Attribute; @@ -9,6 +10,7 @@ use rustc_hir::{ Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty, }; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; use rustc_span::{ExpnId, MacroKind, Span}; @@ -57,27 +59,24 @@ declare_clippy_lint! { } pub struct DisallowedMacros { - conf_disallowed: Vec, - disallowed: DefIdMap, + disallowed: DefIdMap<(&'static str, Option<&'static str>)>, seen: FxHashSet, - // Track the most recently seen node that can have a `derive` attribute. // Needed to use the correct lint level. derive_src: Option, } impl DisallowedMacros { - pub fn new(conf_disallowed: Vec) -> Self { + pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { Self { - conf_disallowed, - disallowed: DefIdMap::default(), + disallowed: create_disallowed_map(tcx, &conf.disallowed_macros), seen: FxHashSet::default(), derive_src: None, } } fn check(&mut self, cx: &LateContext<'_>, span: Span, derive_src: Option) { - if self.conf_disallowed.is_empty() { + if self.disallowed.is_empty() { return; } @@ -86,11 +85,10 @@ impl DisallowedMacros { return; } - if let Some(&index) = self.disallowed.get(&mac.def_id) { - let conf = &self.conf_disallowed[index]; - let msg = format!("use of a disallowed macro `{}`", conf.path()); + if let Some(&(path, reason)) = self.disallowed.get(&mac.def_id) { + let msg = format!("use of a disallowed macro `{path}`"); let add_note = |diag: &mut Diag<'_, _>| { - if let Some(reason) = conf.reason() { + if let Some(reason) = reason { diag.note(reason); } }; @@ -116,15 +114,6 @@ impl DisallowedMacros { impl_lint_pass!(DisallowedMacros => [DISALLOWED_MACROS]); impl LateLintPass<'_> for DisallowedMacros { - fn check_crate(&mut self, cx: &LateContext<'_>) { - for (index, conf) in self.conf_disallowed.iter().enumerate() { - let segs: Vec<_> = conf.path().split("::").collect(); - for id in clippy_utils::def_path_def_ids(cx, &segs) { - self.disallowed.insert(id, index); - } - } - } - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { self.check(cx, expr.span, None); // `$t + $t` can have the context of $t, check also the span of the binary operator diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 38fe687f7ccf..5a01d76a2a62 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -1,9 +1,11 @@ -use clippy_config::types::DisallowedPath; +use clippy_config::Conf; +use clippy_utils::create_disallowed_map; use clippy_utils::diagnostics::span_lint_and_then; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; declare_clippy_lint! { @@ -55,17 +57,14 @@ declare_clippy_lint! { "use of a disallowed method call" } -#[derive(Clone, Debug)] pub struct DisallowedMethods { - conf_disallowed: Vec, - disallowed: DefIdMap, + disallowed: DefIdMap<(&'static str, Option<&'static str>)>, } impl DisallowedMethods { - pub fn new(conf_disallowed: Vec) -> Self { + pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { Self { - conf_disallowed, - disallowed: DefIdMap::default(), + disallowed: create_disallowed_map(tcx, &conf.disallowed_methods), } } } @@ -73,15 +72,6 @@ impl DisallowedMethods { impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]); impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { - fn check_crate(&mut self, cx: &LateContext<'_>) { - for (index, conf) in self.conf_disallowed.iter().enumerate() { - let segs: Vec<_> = conf.path().split("::").collect(); - for id in clippy_utils::def_path_def_ids(cx, &segs) { - self.disallowed.insert(id, index); - } - } - } - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let (id, span) = match &expr.kind { ExprKind::Path(path) @@ -95,14 +85,18 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { }, _ => return, }; - if let Some(&index) = self.disallowed.get(&id) { - let conf = &self.conf_disallowed[index]; - let msg = format!("use of a disallowed method `{}`", conf.path()); - span_lint_and_then(cx, DISALLOWED_METHODS, span, msg, |diag| { - if let Some(reason) = conf.reason() { - diag.note(reason); - } - }); + if let Some(&(path, reason)) = self.disallowed.get(&id) { + span_lint_and_then( + cx, + DISALLOWED_METHODS, + span, + format!("use of a disallowed method `{path}`"), + |diag| { + if let Some(reason) = reason { + diag.note(reason); + } + }, + ); } } } diff --git a/clippy_lints/src/disallowed_names.rs b/clippy_lints/src/disallowed_names.rs index 58809604c373..f55b0cf1c503 100644 --- a/clippy_lints/src/disallowed_names.rs +++ b/clippy_lints/src/disallowed_names.rs @@ -1,9 +1,11 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_in_test; use rustc_data_structures::fx::FxHashSet; use rustc_hir::{Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; +use rustc_span::Symbol; declare_clippy_lint! { /// ### What it does @@ -24,15 +26,14 @@ declare_clippy_lint! { "usage of a disallowed/placeholder name" } -#[derive(Clone, Debug)] pub struct DisallowedNames { - disallow: FxHashSet, + disallow: FxHashSet, } impl DisallowedNames { - pub fn new(disallowed_names: &[String]) -> Self { + pub fn new(conf: &'static Conf) -> Self { Self { - disallow: disallowed_names.iter().cloned().collect(), + disallow: conf.disallowed_names.iter().map(|x| Symbol::intern(x)).collect(), } } } @@ -42,7 +43,7 @@ impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]); impl<'tcx> LateLintPass<'tcx> for DisallowedNames { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { if let PatKind::Binding(.., ident, _) = pat.kind - && self.disallow.contains(&ident.name.to_string()) + && self.disallow.contains(&ident.name) && !is_in_test(cx.tcx, pat.hir_id) { span_lint( diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index 5ce11900adf8..f79264e6b04a 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -1,3 +1,4 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use rustc_ast::ast; use rustc_data_structures::fx::FxHashSet; @@ -44,19 +45,20 @@ declare_clippy_lint! { "usage of non-allowed Unicode scripts" } -#[derive(Clone, Debug)] pub struct DisallowedScriptIdents { whitelist: FxHashSet