From c7f54daaf44b16469193b03694360153c82aab08 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Sat, 17 Sep 2022 18:09:50 -0600 Subject: [PATCH 001/272] Add better assert messages for f32/f64 clamps --- library/core/src/num/f32.rs | 2 +- library/core/src/num/f64.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 2c6a0ba64f26..d946f6547b0d 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1391,7 +1391,7 @@ impl f32 { #[stable(feature = "clamp", since = "1.50.0")] #[inline] pub fn clamp(mut self, min: f32, max: f32) -> f32 { - assert!(min <= max); + assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}"); if self < min { self = min; } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index fd3c18ce29bd..b96af86aabaf 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1389,7 +1389,7 @@ impl f64 { #[stable(feature = "clamp", since = "1.50.0")] #[inline] pub fn clamp(mut self, min: f64, max: f64) -> f64 { - assert!(min <= max); + assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}"); if self < min { self = min; } From 1d24374521496aad0d60c490f8e793e6b8ed80e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20La=C3=BCgt?= Date: Mon, 28 Nov 2022 10:07:36 +0100 Subject: [PATCH 002/272] linkat() not available in the system headers of Solaris 10 --- library/std/src/sys/unix/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 37a49f2d78ac..c9deb1fc6bd3 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1423,7 +1423,7 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> { run_path_with_cstr(original, |original| { run_path_with_cstr(link, |link| { cfg_if::cfg_if! { - if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon"))] { + if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "solaris"))] { // VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves // it implementation-defined whether `link` follows symlinks, so rely on the // `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior. From 7e21b417d4d7e60ce61ebe0991f9b8a61df4bdb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20La=C3=BCgt?= Date: Tue, 29 Nov 2022 23:23:14 +0100 Subject: [PATCH 003/272] Add in the comment that solaris lacks also the 'linkat' --- library/std/src/sys/unix/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index c9deb1fc6bd3..0abf7c1be47a 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1424,7 +1424,7 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> { run_path_with_cstr(link, |link| { cfg_if::cfg_if! { if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "solaris"))] { - // VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves + // VxWorks, Redox, ESP-IDF and Solaris lack `linkat`, so use `link` instead. POSIX leaves // it implementation-defined whether `link` follows symlinks, so rely on the // `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior. // Android has `linkat` on newer versions, but we happen to know `link` From 471de0cb9f7ed11a437d830329050ee419d2ead0 Mon Sep 17 00:00:00 2001 From: Daniel Parks Date: Wed, 25 Jan 2023 21:22:25 -0800 Subject: [PATCH 004/272] Document `cargo-clippy` feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is possible to use conditional compilation to prevent Clippy from evaluating certain code. This adds a brief explanation of how to use the feature with conditional compilation, and mentions that generally it’s preferable to use something like `#[allow(clippy::all)]`. Fixes #10220 — Ability to skip files or blocks entirely --- book/src/configuration.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/book/src/configuration.md b/book/src/configuration.md index 87f4a697af9f..b044507dfdb1 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -100,3 +100,24 @@ Note: `custom_inner_attributes` is an unstable feature so it has to be enabled e Lints that recognize this configuration option can be found [here](https://rust-lang.github.io/rust-clippy/master/index.html#msrv) + +### Disabling evaluation of certain code + +> **Note:** This should only be used in cases where other solutions, like `#[allow(clippy::all)]`, are not sufficient. + +Very rarely, you may wish to prevent Clippy from evaluating certain sections of code entirely. You can do this with +[conditional compilation](https://doc.rust-lang.org/reference/conditional-compilation.html) by checking that the +`cargo-clippy` feature is not set. You may need to provide a stub so that the code compiles: + +```rust +#[cfg(not(feature = "cargo-clippy"))] +include!(concat!(env!("OUT_DIR"), "/my_big_function-generated.rs")); + +#[cfg(feature = "cargo-clippy")] +fn my_big_function(_input: &str) -> Option { + None +} +``` + +This feature is not actually part of your crate, so specifying `--all-features` to other tools, e.g. `cargo test +--all-features`, will not disable it. From 2c66c8f9c623b03bc0d11d214936a51f28effaff Mon Sep 17 00:00:00 2001 From: yukang Date: Sun, 12 Mar 2023 07:50:39 +0800 Subject: [PATCH 005/272] Fix diff option conflict in UI test --- tests/run-make/rustdoc-verify-output-files/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-make/rustdoc-verify-output-files/Makefile b/tests/run-make/rustdoc-verify-output-files/Makefile index 0666122e8abc..ca921fd491d5 100644 --- a/tests/run-make/rustdoc-verify-output-files/Makefile +++ b/tests/run-make/rustdoc-verify-output-files/Makefile @@ -14,7 +14,7 @@ all: $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR) # Check if everything exactly same - $(DIFF) -r -q $(OUTPUT_DIR) $(TMP_OUTPUT_DIR) + $(DIFF) -r $(OUTPUT_DIR) $(TMP_OUTPUT_DIR) # Generate json doc on the same output $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR) -Z unstable-options --output-format json @@ -29,4 +29,4 @@ all: $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR) -Z unstable-options --output-format json # Check if all docs(including both json and html formats) are still the same after multiple compilations - $(DIFF) -r -q $(OUTPUT_DIR) $(TMP_OUTPUT_DIR) + $(DIFF) -r $(OUTPUT_DIR) $(TMP_OUTPUT_DIR) From 54567efda7c08d04383001456976f0f2e43bbfbd Mon Sep 17 00:00:00 2001 From: Sean Linsley Date: Thu, 16 Mar 2023 11:07:42 -0500 Subject: [PATCH 006/272] Clarify that RUST_MIN_STACK is internally cached For larger applications it's important that users set `RUST_MIN_STACK` at the start of their program because `min_stack` caches the value. Not doing so can lead to their `env::set_var` call surprisingly not having any effect. --- library/std/src/thread/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index b9aaf5f6e15d..ff65c00483d7 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -131,7 +131,8 @@ //! //! * Build the thread with [`Builder`] and pass the desired stack size to [`Builder::stack_size`]. //! * Set the `RUST_MIN_STACK` environment variable to an integer representing the desired stack -//! size (in bytes). Note that setting [`Builder::stack_size`] will override this. +//! size (in bytes). Note that setting [`Builder::stack_size`] will override this. Also, note +//! that `RUST_MIN_STACK` is cached internally so should be set before any threads are started. //! //! Note that the stack size of the main thread is *not* determined by Rust. //! From 6eef755012a0f1ac0c40148b7135a125e512f6f0 Mon Sep 17 00:00:00 2001 From: Sean Linsley Date: Fri, 17 Mar 2023 09:12:54 -0500 Subject: [PATCH 007/272] Update mod.rs --- library/std/src/thread/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index ff65c00483d7..13b845b25c92 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -131,8 +131,8 @@ //! //! * Build the thread with [`Builder`] and pass the desired stack size to [`Builder::stack_size`]. //! * Set the `RUST_MIN_STACK` environment variable to an integer representing the desired stack -//! size (in bytes). Note that setting [`Builder::stack_size`] will override this. Also, note -//! that `RUST_MIN_STACK` is cached internally so should be set before any threads are started. +//! size (in bytes). Note that setting [`Builder::stack_size`] will override this. Be aware that +//! changes to `RUST_MIN_STACK` may be ignored after program start. //! //! Note that the stack size of the main thread is *not* determined by Rust. //! From 1e17a443b347098085981f4cb9df9313aedaaae0 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 31 Jan 2023 22:13:25 +0100 Subject: [PATCH 008/272] Remove the `NodeId` of `ast::ExprKind::Async` --- clippy_lints/src/redundant_async_block.rs | 2 +- clippy_lints/src/suspicious_operation_groupings.rs | 2 +- clippy_utils/src/ast_utils.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 27ad43086374..56be8c07e924 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -42,7 +42,7 @@ impl EarlyLintPass for RedundantAsyncBlock { if expr.span.from_expansion() { return; } - if let ExprKind::Async(_, _, block) = &expr.kind && block.stmts.len() == 1 && + if let ExprKind::Async(_, block) = &expr.kind && block.stmts.len() == 1 && let Some(Stmt { kind: StmtKind::Expr(last), .. }) = block.stmts.last() && let ExprKind::Await(future) = &last.kind && !future.span.from_expansion() && diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index 8aa47b62ebff..fab8e9c2ec1c 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -578,7 +578,7 @@ fn ident_difference_expr_with_base_location( | (Assign(_, _, _), Assign(_, _, _)) | (TryBlock(_), TryBlock(_)) | (Await(_), Await(_)) - | (Async(_, _, _), Async(_, _, _)) + | (Async(_, _), Async(_, _)) | (Block(_, _), Block(_, _)) | (Closure(_), Closure(_)) | (Match(_, _), Match(_, _)) diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 809d654603a6..d2dedc204395 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -209,7 +209,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { && eq_fn_decl(lf, rf) && eq_expr(le, re) }, - (Async(lc, _, lb), Async(rc, _, rb)) => lc == rc && eq_block(lb, rb), + (Async(lc, lb), Async(rc, rb)) => lc == rc && eq_block(lb, rb), (Range(lf, lt, ll), Range(rf, rt, rl)) => ll == rl && eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt), (AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re), (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp), From 4fdae81c70bfa1481eebc7ebec09f121c6eaf53c Mon Sep 17 00:00:00 2001 From: csmoe Date: Mon, 27 Feb 2023 11:57:32 +0000 Subject: [PATCH 009/272] add large future lint --- CHANGELOG.md | 3 +- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/large_futures.rs | 90 +++++++++++++++++++ clippy_lints/src/lib.rs | 3 + clippy_lints/src/utils/conf.rs | 4 + tests/ui-toml/large_futures/clippy.toml | 1 + .../ui-toml/large_futures/large_futures.fixed | 29 ++++++ tests/ui-toml/large_futures/large_futures.rs | 29 ++++++ .../large_futures/large_futures.stderr | 10 +++ .../toml_unknown_key/conf_unknown_key.stderr | 1 + tests/ui/large_futures.fixed | 41 +++++++++ tests/ui/large_futures.rs | 41 +++++++++ tests/ui/large_futures.stderr | 40 +++++++++ 13 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 clippy_lints/src/large_futures.rs create mode 100644 tests/ui-toml/large_futures/clippy.toml create mode 100644 tests/ui-toml/large_futures/large_futures.fixed create mode 100644 tests/ui-toml/large_futures/large_futures.rs create mode 100644 tests/ui-toml/large_futures/large_futures.stderr create mode 100644 tests/ui/large_futures.fixed create mode 100644 tests/ui/large_futures.rs create mode 100644 tests/ui/large_futures.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 765826ed867d..0352f956dfb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -278,7 +278,7 @@ Released 2022-12-15 [#9490](https://github.com/rust-lang/rust-clippy/pull/9490) * [`almost_complete_letter_range`]: No longer lints in external macros [#9467](https://github.com/rust-lang/rust-clippy/pull/9467) -* [`drop_copy`]: No longer lints on idiomatic cases in match arms +* [`drop_copy`]: No longer lints on idiomatic cases in match arms [#9491](https://github.com/rust-lang/rust-clippy/pull/9491) * [`question_mark`]: No longer lints in const context [#9487](https://github.com/rust-lang/rust-clippy/pull/9487) @@ -4485,6 +4485,7 @@ Released 2018-09-13 [`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays [`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups [`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant +[`large_futures`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_futures [`large_include_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_include_file [`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays [`large_types_passed_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index cd5dd7a57065..208112b4025a 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -216,6 +216,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO, crate::large_const_arrays::LARGE_CONST_ARRAYS_INFO, crate::large_enum_variant::LARGE_ENUM_VARIANT_INFO, + crate::large_futures::LARGE_FUTURES_INFO, crate::large_include_file::LARGE_INCLUDE_FILE_INFO, crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO, crate::len_zero::COMPARISON_TO_EMPTY_INFO, diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs new file mode 100644 index 000000000000..494bb2a97d26 --- /dev/null +++ b/clippy_lints/src/large_futures.rs @@ -0,0 +1,90 @@ +use clippy_utils::source::snippet; +use clippy_utils::{diagnostics::span_lint_and_sugg, ty::implements_trait}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_target::abi::Size; + +declare_clippy_lint! { + /// ### What it does + /// It checks for the size of a `Future` created by `async fn` or `async {}`. + /// + /// ### Why is this bad? + /// Due to the current [unideal implemention](https://github.com/rust-lang/rust/issues/69826) of `Generator`, + /// large size of a `Future` may cause stack overflows. + /// + /// ### Example + /// ```rust + /// async fn wait(f: impl std::future::Future) {} + /// + /// async fn big_fut(arg: [u8; 1024]) {} + /// + /// pub async fn test() { + /// let fut = big_fut([0u8; 1024]); + /// wait(fut).await; + /// } + /// ``` + /// + /// `Box::pin` the big future instead. + /// + /// ```rust + /// async fn wait(f: impl std::future::Future) {} + /// + /// async fn big_fut(arg: [u8; 1024]) {} + /// + /// pub async fn test() { + /// let fut = Box::pin(big_fut([0u8; 1024])); + /// wait(fut).await; + /// } + /// ``` + #[clippy::version = "1.68.0"] + pub LARGE_FUTURES, + pedantic, + "large future may lead to unexpected stack overflows" +} + +#[derive(Copy, Clone)] +pub struct LargeFuture { + future_size_threshold: u64, +} + +impl LargeFuture { + pub fn new(future_size_threshold: u64) -> Self { + Self { future_size_threshold } + } +} + +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 let ExprKind::Match(expr, _, MatchSource::AwaitDesugar) = expr.kind { + if let ExprKind::Call(func, [expr, ..]) = expr.kind { + if matches!( + func.kind, + ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) + ) { + let ty = cx.typeck_results().expr_ty(expr); + if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() + && implements_trait(cx, ty, future_trait_def_id, &[]) { + if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) { + let size = layout.layout.size(); + if 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::MachineApplicable, + ); + } + } + } + } + } + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 145cf524652f..155aa106322b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -161,6 +161,7 @@ mod items_after_statements; mod iter_not_returning_iterator; mod large_const_arrays; mod large_enum_variant; +mod large_futures; mod large_include_file; mod large_stack_arrays; mod len_zero; @@ -800,6 +801,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv()))); store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse)); store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend)); + let future_size_threshold = conf.future_size_threshold; + store.register_late_pass(move |_| Box::new(large_futures::LargeFuture::new(future_size_threshold))); store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex)); store.register_late_pass(|_| Box::new(if_not_else::IfNotElse)); store.register_late_pass(|_| Box::new(equatable_if_let::PatternEquality)); diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 5f74de5a2886..639f8d958776 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -459,6 +459,10 @@ define_Conf! { /// Whether to **only** check for missing documentation in items visible within the current /// crate. For example, `pub(crate)` items. (missing_docs_in_crate_items: bool = false), + /// Lint: LARGE_FUTURES. + /// + /// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint + (future_size_threshold: u64 = 16 * 1024), } /// Search for the configuration file. diff --git a/tests/ui-toml/large_futures/clippy.toml b/tests/ui-toml/large_futures/clippy.toml new file mode 100644 index 000000000000..61bb17fdf6bd --- /dev/null +++ b/tests/ui-toml/large_futures/clippy.toml @@ -0,0 +1 @@ +future-size-threshold = 1024 diff --git a/tests/ui-toml/large_futures/large_futures.fixed b/tests/ui-toml/large_futures/large_futures.fixed new file mode 100644 index 000000000000..1238c512b0fa --- /dev/null +++ b/tests/ui-toml/large_futures/large_futures.fixed @@ -0,0 +1,29 @@ +// run-rustfix + +#![warn(clippy::large_futures)] + +fn main() {} + +pub async fn should_warn() { + let x = [0u8; 1024]; + async {}.await; + dbg!(x); +} + +pub async fn should_not_warn() { + let x = [0u8; 1020]; + async {}.await; + dbg!(x); +} + +pub async fn bar() { + Box::pin(should_warn()).await; + + async { + let x = [0u8; 1024]; + dbg!(x); + } + .await; + + should_not_warn().await; +} diff --git a/tests/ui-toml/large_futures/large_futures.rs b/tests/ui-toml/large_futures/large_futures.rs new file mode 100644 index 000000000000..80039d9047b3 --- /dev/null +++ b/tests/ui-toml/large_futures/large_futures.rs @@ -0,0 +1,29 @@ +// run-rustfix + +#![warn(clippy::large_futures)] + +fn main() {} + +pub async fn should_warn() { + let x = [0u8; 1024]; + async {}.await; + dbg!(x); +} + +pub async fn should_not_warn() { + let x = [0u8; 1020]; + async {}.await; + dbg!(x); +} + +pub async fn bar() { + should_warn().await; + + async { + let x = [0u8; 1024]; + dbg!(x); + } + .await; + + should_not_warn().await; +} diff --git a/tests/ui-toml/large_futures/large_futures.stderr b/tests/ui-toml/large_futures/large_futures.stderr new file mode 100644 index 000000000000..f7895f8eaf7a --- /dev/null +++ b/tests/ui-toml/large_futures/large_futures.stderr @@ -0,0 +1,10 @@ +error: large future with a size of 1026 bytes + --> $DIR/large_futures.rs:20:5 + | +LL | should_warn().await; + | ^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(should_warn())` + | + = note: `-D clippy::large-futures` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 6a246afac76e..8447c31722dd 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -24,6 +24,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie enforced-import-renames enum-variant-name-threshold enum-variant-size-threshold + future-size-threshold ignore-interior-mutability large-error-threshold literal-representation-threshold diff --git a/tests/ui/large_futures.fixed b/tests/ui/large_futures.fixed new file mode 100644 index 000000000000..9d839998afd7 --- /dev/null +++ b/tests/ui/large_futures.fixed @@ -0,0 +1,41 @@ +// run-rustfix + +#![feature(generators)] +#![warn(clippy::large_futures)] +#![allow(clippy::future_not_send)] +#![allow(clippy::manual_async_fn)] + +async fn big_fut(_arg: [u8; 1024 * 16]) {} + +async fn wait() { + let f = async { + Box::pin(big_fut([0u8; 1024 * 16])).await; + }; + Box::pin(f).await +} +async fn calls_fut(fut: impl std::future::Future) { + loop { + Box::pin(wait()).await; + if true { + return fut.await; + } else { + Box::pin(wait()).await; + } + } +} + +pub async fn test() { + let fut = big_fut([0u8; 1024 * 16]); + Box::pin(foo()).await; + Box::pin(calls_fut(fut)).await; +} + +pub fn foo() -> impl std::future::Future { + async { + let x = [0i32; 1024 * 16]; + async {}.await; + dbg!(x); + } +} + +fn main() {} diff --git a/tests/ui/large_futures.rs b/tests/ui/large_futures.rs new file mode 100644 index 000000000000..8b7aaa61b888 --- /dev/null +++ b/tests/ui/large_futures.rs @@ -0,0 +1,41 @@ +// run-rustfix + +#![feature(generators)] +#![warn(clippy::large_futures)] +#![allow(clippy::future_not_send)] +#![allow(clippy::manual_async_fn)] + +async fn big_fut(_arg: [u8; 1024 * 16]) {} + +async fn wait() { + let f = async { + big_fut([0u8; 1024 * 16]).await; + }; + f.await +} +async fn calls_fut(fut: impl std::future::Future) { + loop { + wait().await; + if true { + return fut.await; + } else { + wait().await; + } + } +} + +pub async fn test() { + let fut = big_fut([0u8; 1024 * 16]); + foo().await; + calls_fut(fut).await; +} + +pub fn foo() -> impl std::future::Future { + async { + let x = [0i32; 1024 * 16]; + async {}.await; + dbg!(x); + } +} + +fn main() {} diff --git a/tests/ui/large_futures.stderr b/tests/ui/large_futures.stderr new file mode 100644 index 000000000000..557455299a9c --- /dev/null +++ b/tests/ui/large_futures.stderr @@ -0,0 +1,40 @@ +error: large future with a size of 16385 bytes + --> $DIR/large_futures.rs:12:9 + | +LL | big_fut([0u8; 1024 * 16]).await; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(big_fut([0u8; 1024 * 16]))` + | + = note: `-D clippy::large-futures` implied by `-D warnings` + +error: large future with a size of 16386 bytes + --> $DIR/large_futures.rs:14:5 + | +LL | f.await + | ^ help: consider `Box::pin` on it: `Box::pin(f)` + +error: large future with a size of 16387 bytes + --> $DIR/large_futures.rs:18:9 + | +LL | wait().await; + | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` + +error: large future with a size of 16387 bytes + --> $DIR/large_futures.rs:22:13 + | +LL | wait().await; + | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` + +error: large future with a size of 65540 bytes + --> $DIR/large_futures.rs:29:5 + | +LL | foo().await; + | ^^^^^ help: consider `Box::pin` on it: `Box::pin(foo())` + +error: large future with a size of 49159 bytes + --> $DIR/large_futures.rs:30:5 + | +LL | calls_fut(fut).await; + | ^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(calls_fut(fut))` + +error: aborting due to 6 previous errors + From 7f44530f54002401ba771bcc19f56f4950b22bb1 Mon Sep 17 00:00:00 2001 From: bluthej Date: Sat, 18 Mar 2023 10:43:02 +0100 Subject: [PATCH 010/272] Create `clear_with_drain` lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/clear_with_drain.rs | 8 ++++++++ clippy_lints/src/methods/mod.rs | 21 ++++++++++++++++++++ tests/ui/clear_with_drain.rs | 12 +++++++++++ 5 files changed, 43 insertions(+) create mode 100644 clippy_lints/src/methods/clear_with_drain.rs create mode 100644 tests/ui/clear_with_drain.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 47a503510c10..81d0ff809686 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4441,6 +4441,7 @@ Released 2018-09-13 [`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 [`checked_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions +[`clear_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#clear_with_drain [`clone_double_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref [`clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy [`clone_on_ref_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_ref_ptr diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 2331e857b1f7..f7b108c923ad 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -307,6 +307,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS_INFO, crate::methods::CHARS_LAST_CMP_INFO, crate::methods::CHARS_NEXT_CMP_INFO, + crate::methods::CLEAR_WITH_DRAIN_INFO, crate::methods::CLONED_INSTEAD_OF_COPIED_INFO, crate::methods::CLONE_DOUBLE_REF_INFO, crate::methods::CLONE_ON_COPY_INFO, diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs new file mode 100644 index 000000000000..9e55852ef7a6 --- /dev/null +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -0,0 +1,8 @@ +use rustc_lint::{LateContext, LintContext}; + +use super::CLEAR_WITH_DRAIN; + +// TODO: Adjust the parameters as necessary +pub(super) fn check(cx: &LateContext) { + todo!(); +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 56e3988bf097..859284b6a5cc 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -9,6 +9,7 @@ mod chars_last_cmp; mod chars_last_cmp_with_unwrap; mod chars_next_cmp; mod chars_next_cmp_with_unwrap; +mod clear_with_drain; mod clone_on_copy; mod clone_on_ref_ptr; mod cloned_instead_of_copied; @@ -3190,6 +3191,25 @@ declare_clippy_lint! { "single command line argument that looks like it should be multiple arguments" } +declare_clippy_lint! { + /// ### What it does + /// + /// ### Why is this bad? + /// + /// ### Example + /// ```rust + /// // example code where clippy issues a warning + /// ``` + /// Use instead: + /// ```rust + /// // example code which does not raise clippy warning + /// ``` + #[clippy::version = "1.69.0"] + pub CLEAR_WITH_DRAIN, + nursery, + "default lint description" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3318,6 +3338,7 @@ impl_lint_pass!(Methods => [ SEEK_TO_START_INSTEAD_OF_REWIND, NEEDLESS_COLLECT, SUSPICIOUS_COMMAND_ARG_SPACE, + CLEAR_WITH_DRAIN, ]); /// Extracts a method call name, args, and `Span` of the method name. diff --git a/tests/ui/clear_with_drain.rs b/tests/ui/clear_with_drain.rs new file mode 100644 index 000000000000..bb3a371cc089 --- /dev/null +++ b/tests/ui/clear_with_drain.rs @@ -0,0 +1,12 @@ +#![allow(unused)] +#![warn(clippy::clear_with_drain)] + +fn main() { + let mut vec: Vec = Vec::new(); + //Lint + vec.drain(..); + vec.drain(0..vec.len()); + + // Dont Lint + let iter = vec.drain(..); +} From 85d428101dc757f7aa41e47696c94683d8398903 Mon Sep 17 00:00:00 2001 From: bluthej Date: Sat, 18 Mar 2023 11:34:30 +0100 Subject: [PATCH 011/272] Pull `is_full_range` method from `iter_with_drain` Rename method to `is_range_full` because the type is actually `RangeFull`. Method moved to `clippy_utils` for reuse in `clear_with_drain`. --- clippy_lints/src/methods/iter_with_drain.rs | 23 +++------------------ clippy_utils/src/lib.rs | 21 ++++++++++++++++++- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/clippy_lints/src/methods/iter_with_drain.rs b/clippy_lints/src/methods/iter_with_drain.rs index 3da230e12d7f..ea92e3a549f4 100644 --- a/clippy_lints/src/methods/iter_with_drain.rs +++ b/clippy_lints/src/methods/iter_with_drain.rs @@ -1,9 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::Range; -use clippy_utils::is_integer_const; -use rustc_ast::ast::RangeLimits; +use clippy_utils::is_range_full; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; use rustc_span::Span; @@ -16,7 +15,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span && let Some(ty_name) = cx.tcx.get_diagnostic_name(adt.did()) && matches!(ty_name, sym::Vec | sym::VecDeque) && let Some(range) = Range::hir(arg) - && is_full_range(cx, recv, range) + && is_range_full(cx, recv, range) { span_lint_and_sugg( cx, @@ -29,19 +28,3 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span ); }; } - -fn is_full_range(cx: &LateContext<'_>, container: &Expr<'_>, range: Range<'_>) -> bool { - range.start.map_or(true, |e| is_integer_const(cx, e, 0)) - && range.end.map_or(true, |e| { - if range.limits == RangeLimits::HalfOpen - && let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind - && let ExprKind::MethodCall(name, self_arg, [], _) = e.kind - && name.ident.name == sym::len - && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind - { - container_path.res == path.res - } else { - false - } - }) -} diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 44b6b9f7b0b1..0fdbd7a63411 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -78,7 +78,7 @@ use std::sync::OnceLock; use std::sync::{Mutex, MutexGuard}; use if_chain::if_chain; -use rustc_ast::ast::{self, LitKind}; +use rustc_ast::ast::{self, LitKind, RangeLimits}; use rustc_ast::Attribute; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unhash::UnhashMap; @@ -115,6 +115,7 @@ use rustc_span::Span; use rustc_target::abi::Integer; use crate::consts::{constant, Constant}; +use crate::higher::Range; use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param}; use crate::visitors::for_each_expr; @@ -1491,6 +1492,24 @@ pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { } } +/// Checks whether the given `Range` is equivalent to a `RangeFull`. +/// Inclusive ranges are not considered because they already constitute a lint. +pub fn is_range_full(cx: &LateContext<'_>, container: &Expr<'_>, range: Range<'_>) -> bool { + range.start.map_or(true, |e| is_integer_const(cx, e, 0)) + && range.end.map_or(true, |e| { + if range.limits == RangeLimits::HalfOpen + && let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind + && let ExprKind::MethodCall(name, self_arg, [], _) = e.kind + && name.ident.name == sym::len + && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind + { + container_path.res == path.res + } else { + false + } + }) +} + /// Checks whether the given expression is a constant integer of the given value. /// unlike `is_integer_literal`, this version does const folding pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool { From 589d7e1ab40af9950d33715ef6cf866efa04f9a2 Mon Sep 17 00:00:00 2001 From: bluthej Date: Sat, 18 Mar 2023 14:45:57 +0100 Subject: [PATCH 012/272] Add tests to cover all cases --- tests/ui/clear_with_drain.rs | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/tests/ui/clear_with_drain.rs b/tests/ui/clear_with_drain.rs index bb3a371cc089..3f8517011cdb 100644 --- a/tests/ui/clear_with_drain.rs +++ b/tests/ui/clear_with_drain.rs @@ -1,12 +1,28 @@ #![allow(unused)] #![warn(clippy::clear_with_drain)] -fn main() { - let mut vec: Vec = Vec::new(); - //Lint - vec.drain(..); - vec.drain(0..vec.len()); - - // Dont Lint - let iter = vec.drain(..); +fn range() { + let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); + let iter = u.drain(0..u.len()); // Yay + v.drain(0..v.len()); // Nay } + +fn range_from() { + let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); + let iter = u.drain(0..); // Yay + v.drain(0..); // Nay +} + +fn range_full() { + let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); + let iter = u.drain(..); // Yay + v.drain(..); // Nay +} + +fn range_to() { + let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); + let iter = u.drain(..u.len()); // Yay + v.drain(..v.len()); // Nay +} + +fn main() {} From 484c82e0418325df5d25e8d0e11e10a5d1371502 Mon Sep 17 00:00:00 2001 From: bluthej Date: Mon, 20 Mar 2023 18:46:18 +0100 Subject: [PATCH 013/272] Update lint declaration --- clippy_lints/src/methods/mod.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 859284b6a5cc..4e74ac6af2bb 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3193,21 +3193,27 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does + /// Checks for usage of `.drain(..)` for the sole purpose of clearing a `Vec`. /// /// ### Why is this bad? + /// This creates an unnecessary iterator that is dropped immediately. + /// + /// Calling `.clear()` also makes the intent clearer. /// /// ### Example /// ```rust - /// // example code where clippy issues a warning + /// let mut v = vec![1, 2, 3]; + /// v.drain(..); /// ``` /// Use instead: /// ```rust - /// // example code which does not raise clippy warning + /// let mut v = vec![1, 2, 3]; + /// v.clear(); /// ``` #[clippy::version = "1.69.0"] pub CLEAR_WITH_DRAIN, nursery, - "default lint description" + "calling `drain` in order to `clear` a `Vec`" } pub struct Methods { From c7e3e304d5d2ac82dbebe5f3d3e0611b407d81be Mon Sep 17 00:00:00 2001 From: bluthej Date: Tue, 21 Mar 2023 22:08:37 +0100 Subject: [PATCH 014/272] Add the lint logic --- clippy_lints/src/methods/clear_with_drain.rs | 27 +++++++++++++++++--- clippy_lints/src/methods/mod.rs | 10 ++++++-- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs index 9e55852ef7a6..ac6c0e57257c 100644 --- a/clippy_lints/src/methods/clear_with_drain.rs +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -1,8 +1,29 @@ -use rustc_lint::{LateContext, LintContext}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::higher::Range; +use clippy_utils::is_range_full; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; +use rustc_span::Span; use super::CLEAR_WITH_DRAIN; // TODO: Adjust the parameters as necessary -pub(super) fn check(cx: &LateContext) { - todo!(); +// see clippy_lints/src/methods/mod.rs to add call to this check in `check_methods` +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: &Expr<'_>) { + let ty = cx.typeck_results().expr_ty(recv); + if is_type_diagnostic_item(cx, ty, sym::Vec) && let Some(range) = Range::hir(arg) && is_range_full(cx, recv, range) + { + span_lint_and_sugg( + cx, + CLEAR_WITH_DRAIN, + span.with_hi(expr.span.hi()), + "`drain` used to clear a `Vec`", + "try", + "clear()".to_string(), + Applicability::MachineApplicable, + ); + } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4e74ac6af2bb..257bc4eccc30 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -111,7 +111,7 @@ use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_ use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, return_ty}; use if_chain::if_chain; use rustc_hir as hir; -use rustc_hir::{Expr, ExprKind, TraitItem, TraitItemKind}; +use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind}; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -3590,7 +3590,13 @@ impl Methods { _ => {}, }, ("drain", [arg]) => { - iter_with_drain::check(cx, expr, recv, span, arg); + if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.hir().get_parent(expr.hir_id) + && matches!(kind, StmtKind::Semi(_)) + { + clear_with_drain::check(cx, expr, recv, span, arg); + } else { + iter_with_drain::check(cx, expr, recv, span, arg); + } }, ("ends_with", [arg]) => { if let ExprKind::MethodCall(.., span) = expr.kind { From 1d0acce984f9be9f085fd5ebcb44dd6988b1f295 Mon Sep 17 00:00:00 2001 From: bluthej Date: Tue, 21 Mar 2023 22:09:26 +0100 Subject: [PATCH 015/272] Add test for partial range --- tests/ui/clear_with_drain.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/ui/clear_with_drain.rs b/tests/ui/clear_with_drain.rs index 3f8517011cdb..28119deaebbe 100644 --- a/tests/ui/clear_with_drain.rs +++ b/tests/ui/clear_with_drain.rs @@ -25,4 +25,15 @@ fn range_to() { v.drain(..v.len()); // Nay } +fn partial_drains() { + let mut v = vec![1, 2, 3]; + v.drain(1..); // Yay + + let mut v = vec![1, 2, 3]; + v.drain(..v.len() - 1); // Yay + + let mut v = vec![1, 2, 3]; + v.drain(1..v.len() - 1); // Yay +} + fn main() {} From e8ec242a61e7fcadf1a8cb3c6f7ec162b5e2726e Mon Sep 17 00:00:00 2001 From: bluthej Date: Tue, 21 Mar 2023 22:46:59 +0100 Subject: [PATCH 016/272] Finish tests - add rustfix --- clippy_lints/src/methods/clear_with_drain.rs | 2 - tests/ui/clear_with_drain.fixed | 40 ++++++++++++++++++++ tests/ui/clear_with_drain.rs | 1 + tests/ui/clear_with_drain.stderr | 28 ++++++++++++++ 4 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 tests/ui/clear_with_drain.fixed create mode 100644 tests/ui/clear_with_drain.stderr diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs index ac6c0e57257c..bf7e7d124051 100644 --- a/clippy_lints/src/methods/clear_with_drain.rs +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -10,8 +10,6 @@ use rustc_span::Span; use super::CLEAR_WITH_DRAIN; -// TODO: Adjust the parameters as necessary -// see clippy_lints/src/methods/mod.rs to add call to this check in `check_methods` pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: &Expr<'_>) { let ty = cx.typeck_results().expr_ty(recv); if is_type_diagnostic_item(cx, ty, sym::Vec) && let Some(range) = Range::hir(arg) && is_range_full(cx, recv, range) diff --git a/tests/ui/clear_with_drain.fixed b/tests/ui/clear_with_drain.fixed new file mode 100644 index 000000000000..62b0af08eeae --- /dev/null +++ b/tests/ui/clear_with_drain.fixed @@ -0,0 +1,40 @@ +// run-rustfix +#![allow(unused)] +#![warn(clippy::clear_with_drain)] + +fn range() { + let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); + let iter = u.drain(0..u.len()); // Yay + v.clear(); // Nay +} + +fn range_from() { + let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); + let iter = u.drain(0..); // Yay + v.clear(); // Nay +} + +fn range_full() { + let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); + let iter = u.drain(..); // Yay + v.clear(); // Nay +} + +fn range_to() { + let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); + let iter = u.drain(..u.len()); // Yay + v.clear(); // Nay +} + +fn partial_drains() { + let mut v = vec![1, 2, 3]; + v.drain(1..); // Yay + + let mut v = vec![1, 2, 3]; + v.drain(..v.len() - 1); // Yay + + let mut v = vec![1, 2, 3]; + v.drain(1..v.len() - 1); // Yay +} + +fn main() {} diff --git a/tests/ui/clear_with_drain.rs b/tests/ui/clear_with_drain.rs index 28119deaebbe..721af7d2ea7e 100644 --- a/tests/ui/clear_with_drain.rs +++ b/tests/ui/clear_with_drain.rs @@ -1,3 +1,4 @@ +// run-rustfix #![allow(unused)] #![warn(clippy::clear_with_drain)] diff --git a/tests/ui/clear_with_drain.stderr b/tests/ui/clear_with_drain.stderr new file mode 100644 index 000000000000..0d6d8263e10d --- /dev/null +++ b/tests/ui/clear_with_drain.stderr @@ -0,0 +1,28 @@ +error: `drain` used to clear a `Vec` + --> $DIR/clear_with_drain.rs:8:7 + | +LL | v.drain(0..v.len()); // Nay + | ^^^^^^^^^^^^^^^^^ help: try: `clear()` + | + = note: `-D clippy::clear-with-drain` implied by `-D warnings` + +error: `drain` used to clear a `Vec` + --> $DIR/clear_with_drain.rs:14:7 + | +LL | v.drain(0..); // Nay + | ^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `Vec` + --> $DIR/clear_with_drain.rs:20:7 + | +LL | v.drain(..); // Nay + | ^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `Vec` + --> $DIR/clear_with_drain.rs:26:7 + | +LL | v.drain(..v.len()); // Nay + | ^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: aborting due to 4 previous errors + From f0aa3c63540aa792408453881c59d2c10e1541d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20La=C3=BCgt?= Date: Wed, 22 Mar 2023 11:06:08 +0100 Subject: [PATCH 017/272] Check the presence of linkat() on Solaris (not available in version 10, available in version 11) --- library/std/src/sys/unix/fs.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 0abf7c1be47a..24f68e606721 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -33,7 +33,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; target_os = "watchos", ))] use crate::sys::weak::syscall; -#[cfg(any(target_os = "android", target_os = "macos"))] +#[cfg(any(target_os = "android", target_os = "macos", target_os = "solaris"))] use crate::sys::weak::weak; use libc::{c_int, mode_t}; @@ -42,6 +42,7 @@ use libc::{c_int, mode_t}; target_os = "macos", target_os = "ios", target_os = "watchos", + target_os = "solaris", all(target_os = "linux", target_env = "gnu") ))] use libc::c_char; @@ -1423,15 +1424,15 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> { run_path_with_cstr(original, |original| { run_path_with_cstr(link, |link| { cfg_if::cfg_if! { - if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "solaris"))] { - // VxWorks, Redox, ESP-IDF and Solaris lack `linkat`, so use `link` instead. POSIX leaves + if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon"))] { + // VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves // it implementation-defined whether `link` follows symlinks, so rely on the // `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior. // Android has `linkat` on newer versions, but we happen to know `link` // always has the correct behavior, so it's here as well. cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?; - } else if #[cfg(target_os = "macos")] { - // On MacOS, older versions (<=10.9) lack support for linkat while newer + } else if #[cfg(any(target_os = "macos", target_os = "solaris"))] { + // MacOS (<=10.9) and Solaris 10 lack support for linkat while newer // versions have it. We want to use linkat if it is available, so we use weak! // to check. `linkat` is preferable to `link` because it gives us a flag to // specify how symlinks should be handled. We pass 0 as the flags argument, From a90e5cc9af1fcf7897194ac6a275407dc54db689 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 17 Mar 2023 13:43:32 +0000 Subject: [PATCH 018/272] Use split-debuginfo = "unpacked" for debug builds --- .cargo/config.toml | 3 +++ .github/workflows/clippy_bors.yml | 2 ++ 2 files changed, 5 insertions(+) diff --git a/.cargo/config.toml b/.cargo/config.toml index f3dd9275a42b..4d80d3ce63da 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -11,3 +11,6 @@ target-dir = "target" [unstable] binary-dep-depinfo = true + +[profile.dev] +split-debuginfo = "unpacked" diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 24e677ce8e17..93198aabdb5f 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -180,6 +180,8 @@ jobs: # Run - name: Build Integration Test + env: + CARGO_PROFILE_DEV_SPLIT_DEBUGINFO: off run: cargo test --test integration --features integration --no-run # Upload From 8dd0ec6de7c8473e5730972c4e6206d5fb47b4e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 23 Mar 2023 13:01:01 +0200 Subject: [PATCH 019/272] Set up standard library path substitution in rust-gdb and gdbgui --- src/etc/rust-gdb | 4 ++++ src/etc/rust-gdbgui | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/etc/rust-gdb b/src/etc/rust-gdb index b950cea79edf..d812f7a802b1 100755 --- a/src/etc/rust-gdb +++ b/src/etc/rust-gdb @@ -13,6 +13,8 @@ fi # Find out where the pretty printer Python module is RUSTC_SYSROOT="$("$RUSTC" --print=sysroot)" GDB_PYTHON_MODULE_DIRECTORY="$RUSTC_SYSROOT/lib/rustlib/etc" +# Get the commit hash for path remapping +RUSTC_COMMIT_HASH="$("$RUSTC" -vV | sed -n 's/commit-hash: \(\w*\)/\1/p')" # Run GDB with the additional arguments that load the pretty printers # Set the environment variable `RUST_GDB` to overwrite the call to a @@ -21,4 +23,6 @@ RUST_GDB="${RUST_GDB:-gdb}" PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" exec ${RUST_GDB} \ --directory="$GDB_PYTHON_MODULE_DIRECTORY" \ -iex "add-auto-load-safe-path $GDB_PYTHON_MODULE_DIRECTORY" \ + -iex "set substitute-path /rustc/$RUSTC_COMMIT_HASH $RUSTC_SYSROOT/lib/rustlib/src/rust" \ "$@" + \ No newline at end of file diff --git a/src/etc/rust-gdbgui b/src/etc/rust-gdbgui index 590e488e643a..e7bafcc99b81 100755 --- a/src/etc/rust-gdbgui +++ b/src/etc/rust-gdbgui @@ -42,6 +42,8 @@ fi # Find out where the pretty printer Python module is RUSTC_SYSROOT="$("$RUSTC" --print=sysroot)" GDB_PYTHON_MODULE_DIRECTORY="$RUSTC_SYSROOT/lib/rustlib/etc" +# Get the commit hash for path remapping +RUSTC_COMMIT_HASH="$("$RUSTC" -vV | sed -n 's/commit-hash: \(\w*\)/\1/p')" # Set the environment variable `RUST_GDB` to overwrite the call to a # different/specific command (defaults to `gdb`). @@ -53,7 +55,9 @@ RUST_GDBGUI="${RUST_GDBGUI:-gdbgui}" # These arguments get passed through to GDB and make it load the # Rust pretty printers. -GDB_ARGS="--directory=\"$GDB_PYTHON_MODULE_DIRECTORY\" -iex \"add-auto-load-safe-path $GDB_PYTHON_MODULE_DIRECTORY\"" +GDB_ARGS="--directory=\"$GDB_PYTHON_MODULE_DIRECTORY\"" \ + "-iex \"add-auto-load-safe-path $GDB_PYTHON_MODULE_DIRECTORY\"" \ + "-iex \"set substitute-path /rustc/$RUSTC_COMMIT_HASH $RUSTC_SYSROOT/lib/rustlib/src/rust\"" # Finally we execute gdbgui. PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" \ From ecc201253ee060071442f6f0c1a52b380aa3b3af Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Thu, 23 Mar 2023 18:58:10 +0000 Subject: [PATCH 020/272] Wrap transmutes_expressible_as_ptr_casts suggestions in parentheses --- .../transmute/transmutes_expressible_as_ptr_casts.rs | 11 +++++++++-- tests/ui/transmutes_expressible_as_ptr_casts.fixed | 8 +++++++- tests/ui/transmutes_expressible_as_ptr_casts.rs | 8 +++++++- tests/ui/transmutes_expressible_as_ptr_casts.stderr | 8 +++++++- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index 8530b43243fa..85cd74f23ef7 100644 --- a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -2,8 +2,9 @@ use super::utils::check_cast; use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; +use rustc_ast::ExprPrecedence; use rustc_errors::Applicability; -use rustc_hir::Expr; +use rustc_hir::{Expr, Node}; use rustc_lint::LateContext; use rustc_middle::ty::{cast::CastKind, Ty}; @@ -19,7 +20,7 @@ pub(super) fn check<'tcx>( ) -> bool { use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast}; let mut app = Applicability::MachineApplicable; - let sugg = match check_cast(cx, e, from_ty, to_ty) { + let mut sugg = match check_cast(cx, e, from_ty, to_ty) { Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => { Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app) .as_ty(to_ty.to_string()) @@ -39,6 +40,12 @@ pub(super) fn check<'tcx>( _ => return false, }; + if let Node::Expr(parent) = cx.tcx.hir().get_parent(e.hir_id) + && parent.precedence().order() > ExprPrecedence::Cast.order() + { + sugg = format!("({sugg})"); + } + span_lint_and_sugg( cx, TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/tests/ui/transmutes_expressible_as_ptr_casts.fixed index 55307506eb3c..cc84ba25bd0d 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.fixed +++ b/tests/ui/transmutes_expressible_as_ptr_casts.fixed @@ -4,7 +4,7 @@ // would otherwise be responsible for #![warn(clippy::useless_transmute)] #![warn(clippy::transmute_ptr_to_ptr)] -#![allow(dead_code, unused_unsafe, clippy::borrow_as_ptr)] +#![allow(unused, clippy::borrow_as_ptr)] use std::mem::{size_of, transmute}; @@ -77,3 +77,9 @@ fn cannot_be_expressed_as_pointer_cast(in_param: Single) -> Pair { unsafe { transmute::(in_param) } } + +fn issue_10449() { + fn f() {} + + let _x: u8 = unsafe { *(f as *const u8) }; +} diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.rs b/tests/ui/transmutes_expressible_as_ptr_casts.rs index e7360f3f9dcb..aa65ab4dd247 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.rs +++ b/tests/ui/transmutes_expressible_as_ptr_casts.rs @@ -4,7 +4,7 @@ // would otherwise be responsible for #![warn(clippy::useless_transmute)] #![warn(clippy::transmute_ptr_to_ptr)] -#![allow(dead_code, unused_unsafe, clippy::borrow_as_ptr)] +#![allow(unused, clippy::borrow_as_ptr)] use std::mem::{size_of, transmute}; @@ -77,3 +77,9 @@ fn cannot_be_expressed_as_pointer_cast(in_param: Single) -> Pair { unsafe { transmute::(in_param) } } + +fn issue_10449() { + fn f() {} + + let _x: u8 = unsafe { *std::mem::transmute::(f) }; +} diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.stderr b/tests/ui/transmutes_expressible_as_ptr_casts.stderr index e862fcb67a4a..58f5162c78e7 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.stderr +++ b/tests/ui/transmutes_expressible_as_ptr_casts.stderr @@ -58,5 +58,11 @@ error: transmute from a reference to a pointer LL | unsafe { transmute::<&[i32; 1], *const u8>(in_param) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `in_param as *const [i32; 1] as *const u8` -error: aborting due to 9 previous errors +error: transmute from `fn()` to `*const u8` which could be expressed as a pointer cast instead + --> $DIR/transmutes_expressible_as_ptr_casts.rs:84:28 + | +LL | let _x: u8 = unsafe { *std::mem::transmute::(f) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(f as *const u8)` + +error: aborting due to 10 previous errors From 765c6b865cc5bac5dc173bdfa9524ca210d1c10f Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Thu, 10 Nov 2022 11:37:28 -0500 Subject: [PATCH 021/272] A MIR transform that checks pointers are aligned --- clippy_utils/src/qualify_min_const_fn.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 9f6adf3e3fab..cd9cc8bccb6e 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -169,7 +169,7 @@ fn check_rvalue<'tcx>( Err((span, "unsizing casts are not allowed in const fn".into())) } }, - Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => { + Rvalue::Cast(CastKind::PointerExposeAddress | CastKind::PointerAddress, _, _) => { Err((span, "casting pointers to ints is unstable in const fn".into())) }, Rvalue::Cast(CastKind::DynStar, _, _) => { From f96e38becba21476460a8596f9af058f14f24339 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Thu, 23 Mar 2023 20:19:45 -0400 Subject: [PATCH 022/272] Fix clippy --- clippy_utils/src/qualify_min_const_fn.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index cd9cc8bccb6e..9f6adf3e3fab 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -169,7 +169,7 @@ fn check_rvalue<'tcx>( Err((span, "unsizing casts are not allowed in const fn".into())) } }, - Rvalue::Cast(CastKind::PointerExposeAddress | CastKind::PointerAddress, _, _) => { + Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => { Err((span, "casting pointers to ints is unstable in const fn".into())) }, Rvalue::Cast(CastKind::DynStar, _, _) => { From 50d92d0b60a0ac28b5311e0a04e3353af862079c Mon Sep 17 00:00:00 2001 From: Michael Krasnitski Date: Wed, 22 Mar 2023 22:34:53 -0400 Subject: [PATCH 023/272] Add suggestions to `extra_unused_type_parameters` --- .../src/extra_unused_type_parameters.rs | 179 ++++++++++++------ .../extra_unused_type_parameters/clippy.toml | 1 + .../extra_unused_type_parameters.rs | 9 + tests/ui/extra_unused_type_parameters.fixed | 105 ++++++++++ tests/ui/extra_unused_type_parameters.rs | 11 +- tests/ui/extra_unused_type_parameters.stderr | 83 ++++---- .../extra_unused_type_parameters_unfixable.rs | 24 +++ ...ra_unused_type_parameters_unfixable.stderr | 27 +++ 8 files changed, 323 insertions(+), 116 deletions(-) create mode 100644 tests/ui-toml/extra_unused_type_parameters/clippy.toml create mode 100644 tests/ui-toml/extra_unused_type_parameters/extra_unused_type_parameters.rs create mode 100644 tests/ui/extra_unused_type_parameters.fixed create mode 100644 tests/ui/extra_unused_type_parameters_unfixable.rs create mode 100644 tests/ui/extra_unused_type_parameters_unfixable.stderr diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index 20565e1d232e..eeb4de8b58f4 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -1,10 +1,10 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::trait_ref_of_method; -use rustc_data_structures::fx::FxHashMap; -use rustc_errors::MultiSpan; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor}; use rustc_hir::{ - BodyId, ExprKind, GenericBound, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, + BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, PredicateOrigin, Ty, TyKind, WherePredicate, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -53,13 +53,19 @@ impl ExtraUnusedTypeParameters { } } - /// Don't lint external macros or functions with empty bodies. Also, don't lint public items if - /// the `avoid_breaking_exported_api` config option is set. - fn check_false_positive(&self, cx: &LateContext<'_>, span: Span, def_id: LocalDefId, body_id: BodyId) -> bool { + /// 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) || (self.avoid_breaking_exported_api && is_exported) || fn_empty + in_external_macro(cx.sess(), span) || fn_empty || (is_exported && self.avoid_breaking_exported_api) } } @@ -69,85 +75,129 @@ impl_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]); /// trait bounds those parameters have. struct TypeWalker<'cx, 'tcx> { cx: &'cx LateContext<'tcx>, - /// Collection of all the function's type parameters. + /// Collection of the function's type parameters. Once the function has been walked, this will + /// contain only unused type parameters. ty_params: FxHashMap, - /// Collection of any (inline) trait bounds corresponding to each type parameter. - bounds: FxHashMap, + /// Collection of any inline trait bounds corresponding to each type parameter. + inline_bounds: FxHashMap, + /// Collection of any type parameters with trait bounds that appear in a where clause. + where_bounds: FxHashSet, /// The entire `Generics` object of the function, useful for querying purposes. generics: &'tcx Generics<'tcx>, - /// The value of this will remain `true` if *every* parameter: - /// 1. Is a type parameter, and - /// 2. Goes unused in the function. - /// Otherwise, if any type parameters end up being used, or if any lifetime or const-generic - /// parameters are present, this will be set to `false`. - all_params_unused: bool, } impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'tcx>) -> Self { - let mut all_params_unused = true; let ty_params = generics .params .iter() - .filter_map(|param| { - if let GenericParamKind::Type { synthetic, .. } = param.kind { - (!synthetic).then_some((param.def_id.into(), param.span)) - } else { - if !param.is_elided_lifetime() { - all_params_unused = false; - } - None - } + .filter_map(|param| match param.kind { + GenericParamKind::Type { synthetic, .. } if !synthetic => Some((param.def_id.into(), param.span)), + _ => None, }) .collect(); Self { cx, ty_params, - bounds: FxHashMap::default(), + inline_bounds: FxHashMap::default(), + where_bounds: FxHashSet::default(), generics, - all_params_unused, } } - fn mark_param_used(&mut self, def_id: DefId) { - if self.ty_params.remove(&def_id).is_some() { - self.all_params_unused = false; - } + fn get_bound_span(&self, param: &'tcx GenericParam<'tcx>) -> Span { + self.inline_bounds + .get(¶m.def_id.to_def_id()) + .map_or(param.span, |bound_span| param.span.with_hi(bound_span.hi())) + } + + fn emit_help(&self, spans: Vec, msg: &str, help: &'static str) { + span_lint_and_help(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, spans, msg, None, help); + } + + fn emit_sugg(&self, spans: Vec, msg: &str, help: &'static str) { + let suggestions: Vec<(Span, String)> = spans.iter().copied().zip(std::iter::repeat(String::new())).collect(); + span_lint_and_then(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, spans, msg, |diag| { + diag.multipart_suggestion(help, suggestions, Applicability::MachineApplicable); + }); } fn emit_lint(&self) { - let (msg, help) = match self.ty_params.len() { + let explicit_params = self + .generics + .params + .iter() + .filter(|param| !param.is_elided_lifetime() && !param.is_impl_trait()) + .collect::>(); + + let extra_params = explicit_params + .iter() + .enumerate() + .filter(|(_, param)| self.ty_params.contains_key(¶m.def_id.to_def_id())) + .collect::>(); + + let (msg, help) = match extra_params.len() { 0 => return, 1 => ( - "type parameter goes unused in function definition", + format!( + "type parameter `{}` goes unused in function definition", + extra_params[0].1.name.ident() + ), "consider removing the parameter", ), _ => ( - "type parameters go unused in function definition", + format!( + "type parameters go unused in function definition: {}", + extra_params + .iter() + .map(|(_, param)| param.name.ident().to_string()) + .collect::>() + .join(", ") + ), "consider removing the parameters", ), }; - let source_map = self.cx.sess().source_map(); - let span = if self.all_params_unused { - self.generics.span.into() // Remove the entire list of generics + // If any parameters are bounded in where clauses, don't try to form a suggestion. + // Otherwise, the leftover where bound would produce code that wouldn't compile. + if extra_params + .iter() + .any(|(_, param)| self.where_bounds.contains(¶m.def_id.to_def_id())) + { + let spans = extra_params + .iter() + .map(|(_, param)| self.get_bound_span(param)) + .collect::>(); + self.emit_help(spans, &msg, help); } else { - MultiSpan::from_spans( - self.ty_params + let spans = if explicit_params.len() == extra_params.len() { + vec![self.generics.span] // Remove the entire list of generics + } else { + let mut end: Option = None; + extra_params .iter() - .map(|(def_id, &span)| { - // Extend the span past any trait bounds, and include the comma at the end. - let span_to_extend = self.bounds.get(def_id).copied().map_or(span, Span::shrink_to_hi); - let comma_range = source_map.span_extend_to_next_char(span_to_extend, '>', false); - let comma_span = source_map.span_through_char(comma_range, ','); - span.with_hi(comma_span.hi()) - }) - .collect(), - ) - }; + .rev() + .map(|(idx, param)| { + if let Some(next) = explicit_params.get(idx + 1) && end != Some(next.def_id) { + // Extend the current span forward, up until the next param in the list. + param.span.until(next.span) + } else { + // Extend the current span back to include the comma following the previous + // param. If the span of the next param in the list has already been + // extended, we continue the chain. This is why we're iterating in reverse. + end = Some(param.def_id); - span_lint_and_help(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, span, msg, None, help); + // idx will never be 0, else we'd be removing the entire list of generics + let prev = explicit_params[idx - 1]; + let prev_span = self.get_bound_span(prev); + self.get_bound_span(param).with_lo(prev_span.hi()) + } + }) + .collect() + }; + self.emit_sugg(spans, &msg, help); + }; } } @@ -162,7 +212,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) { if let Some((def_id, _)) = t.peel_refs().as_generic_param() { - self.mark_param_used(def_id); + self.ty_params.remove(&def_id); } else if let TyKind::OpaqueDef(id, _, _) = t.kind { // Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls // `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're @@ -176,9 +226,18 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) { if let WherePredicate::BoundPredicate(predicate) = predicate { - // Collect spans for any bounds on type parameters. We only keep bounds that appear in - // the list of generics (not in a where-clause). + // Collect spans for any bounds on type parameters. if let Some((def_id, _)) = predicate.bounded_ty.peel_refs().as_generic_param() { + match predicate.origin { + PredicateOrigin::GenericParam => { + self.inline_bounds.insert(def_id, predicate.span); + }, + PredicateOrigin::WhereClause => { + self.where_bounds.insert(def_id); + }, + PredicateOrigin::ImplTrait => (), + } + // If the bound contains non-public traits, err on the safe side and don't lint the // corresponding parameter. if !predicate @@ -187,12 +246,10 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { .filter_map(bound_to_trait_def_id) .all(|id| self.cx.effective_visibilities.is_exported(id)) { - self.mark_param_used(def_id); - } else if let PredicateOrigin::GenericParam = predicate.origin { - self.bounds.insert(def_id, predicate.span); + self.ty_params.remove(&def_id); } } - // Only walk the right-hand side of where-bounds + // Only walk the right-hand side of where bounds for bound in predicate.bounds { walk_param_bound(self, bound); } @@ -207,7 +264,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { 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.check_false_positive(cx, item.span, item.owner_id.def_id, body_id) + && !self.is_empty_exported_or_macro(cx, item.span, item.owner_id.def_id, body_id) { let mut walker = TypeWalker::new(cx, generics); walk_item(&mut walker, item); @@ -219,7 +276,7 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters { // Only lint on inherent methods, not trait methods. if let ImplItemKind::Fn(.., body_id) = item.kind && trait_ref_of_method(cx, item.owner_id.def_id).is_none() - && !self.check_false_positive(cx, item.span, item.owner_id.def_id, body_id) + && !self.is_empty_exported_or_macro(cx, item.span, item.owner_id.def_id, body_id) { let mut walker = TypeWalker::new(cx, item.generics); walk_impl_item(&mut walker, item); diff --git a/tests/ui-toml/extra_unused_type_parameters/clippy.toml b/tests/ui-toml/extra_unused_type_parameters/clippy.toml new file mode 100644 index 000000000000..5f304987aa94 --- /dev/null +++ b/tests/ui-toml/extra_unused_type_parameters/clippy.toml @@ -0,0 +1 @@ +avoid-breaking-exported-api = true diff --git a/tests/ui-toml/extra_unused_type_parameters/extra_unused_type_parameters.rs b/tests/ui-toml/extra_unused_type_parameters/extra_unused_type_parameters.rs new file mode 100644 index 000000000000..5655232455cb --- /dev/null +++ b/tests/ui-toml/extra_unused_type_parameters/extra_unused_type_parameters.rs @@ -0,0 +1,9 @@ +pub struct S; + +impl S { + pub fn exported_fn() { + unimplemented!(); + } +} + +fn main() {} diff --git a/tests/ui/extra_unused_type_parameters.fixed b/tests/ui/extra_unused_type_parameters.fixed new file mode 100644 index 000000000000..19e718625582 --- /dev/null +++ b/tests/ui/extra_unused_type_parameters.fixed @@ -0,0 +1,105 @@ +// run-rustfix + +#![allow(unused, clippy::needless_lifetimes)] +#![warn(clippy::extra_unused_type_parameters)] + +fn unused_ty(x: u8) { + unimplemented!() +} + +fn unused_multi(x: u8) { + unimplemented!() +} + +fn unused_with_lt<'a>(x: &'a u8) { + unimplemented!() +} + +fn used_ty(x: T, y: u8) {} + +fn used_ref<'a, T>(x: &'a T) {} + +fn used_ret(x: u8) -> T { + T::default() +} + +fn unused_bounded(x: U) { + unimplemented!(); +} + +fn some_unused(b: B, c: C) { + unimplemented!(); +} + +fn used_opaque(iter: impl Iterator) -> usize { + iter.count() +} + +fn used_ret_opaque() -> impl Iterator { + std::iter::empty() +} + +fn used_vec_box(x: Vec>) {} + +fn used_body() -> String { + T::default().to_string() +} + +fn used_closure() -> impl Fn() { + || println!("{}", T::default().to_string()) +} + +struct S; + +impl S { + fn unused_ty_impl(&self) { + unimplemented!() + } +} + +// Don't lint on trait methods +trait Foo { + fn bar(&self); +} + +impl Foo for S { + fn bar(&self) {} +} + +fn skip_index(iter: Iter, index: usize) -> impl Iterator +where + Iter: Iterator, +{ + iter.enumerate() + .filter_map(move |(i, a)| if i == index { None } else { Some(a) }) +} + +fn unused_opaque(dummy: impl Default) { + unimplemented!() +} + +mod unexported_trait_bounds { + mod private { + pub trait Private {} + } + + fn priv_trait_bound() { + unimplemented!(); + } + + fn unused_with_priv_trait_bound() { + unimplemented!(); + } +} + +mod issue10319 { + fn assert_send() {} + + fn assert_send_where() + where + T: Send, + { + } +} + +fn main() {} diff --git a/tests/ui/extra_unused_type_parameters.rs b/tests/ui/extra_unused_type_parameters.rs index 480174342765..e53bb587e89a 100644 --- a/tests/ui/extra_unused_type_parameters.rs +++ b/tests/ui/extra_unused_type_parameters.rs @@ -1,3 +1,5 @@ +// run-rustfix + #![allow(unused, clippy::needless_lifetimes)] #![warn(clippy::extra_unused_type_parameters)] @@ -21,14 +23,7 @@ fn used_ret(x: u8) -> T { T::default() } -fn unused_bounded(x: U) { - unimplemented!(); -} - -fn unused_where_clause(x: U) -where - T: Default, -{ +fn unused_bounded(x: U) { unimplemented!(); } diff --git a/tests/ui/extra_unused_type_parameters.stderr b/tests/ui/extra_unused_type_parameters.stderr index 86c88fc9bf00..c042a5a2290e 100644 --- a/tests/ui/extra_unused_type_parameters.stderr +++ b/tests/ui/extra_unused_type_parameters.stderr @@ -1,75 +1,64 @@ -error: type parameter goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:4:13 +error: type parameter `T` goes unused in function definition + --> $DIR/extra_unused_type_parameters.rs:6:13 | LL | fn unused_ty(x: u8) { - | ^^^ + | ^^^ help: consider removing the parameter | - = help: consider removing the parameter = note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings` -error: type parameters go unused in function definition - --> $DIR/extra_unused_type_parameters.rs:8:16 +error: type parameters go unused in function definition: T, U + --> $DIR/extra_unused_type_parameters.rs:10:16 | LL | fn unused_multi(x: u8) { - | ^^^^^^ - | - = help: consider removing the parameters + | ^^^^^^ help: consider removing the parameters -error: type parameter goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:12:23 +error: type parameter `T` goes unused in function definition + --> $DIR/extra_unused_type_parameters.rs:14:21 | LL | fn unused_with_lt<'a, T>(x: &'a u8) { - | ^ - | - = help: consider removing the parameter + | ^^^ help: consider removing the parameter -error: type parameter goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:24:19 +error: type parameters go unused in function definition: T, V + --> $DIR/extra_unused_type_parameters.rs:26:19 | -LL | fn unused_bounded(x: U) { - | ^^^^^^^^^^^ +LL | fn unused_bounded(x: U) { + | ^^^^^^^^^^^^ ^^^^^^^^^^^^ + | +help: consider removing the parameters + | +LL - fn unused_bounded(x: U) { +LL + fn unused_bounded(x: U) { | - = help: consider removing the parameter -error: type parameter goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:28:24 - | -LL | fn unused_where_clause(x: U) - | ^^ - | - = help: consider removing the parameter - -error: type parameters go unused in function definition - --> $DIR/extra_unused_type_parameters.rs:35:16 +error: type parameters go unused in function definition: A, D, E + --> $DIR/extra_unused_type_parameters.rs:30:16 | LL | fn some_unused, E>(b: B, c: C) { - | ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ + | ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider removing the parameters + | +LL - fn some_unused, E>(b: B, c: C) { +LL + fn some_unused(b: B, c: C) { | - = help: consider removing the parameters -error: type parameter goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:60:22 +error: type parameter `T` goes unused in function definition + --> $DIR/extra_unused_type_parameters.rs:55:22 | LL | fn unused_ty_impl(&self) { - | ^^^ - | - = help: consider removing the parameter + | ^^^ help: consider removing the parameter -error: type parameters go unused in function definition - --> $DIR/extra_unused_type_parameters.rs:82:17 +error: type parameters go unused in function definition: A, B + --> $DIR/extra_unused_type_parameters.rs:77:17 | LL | fn unused_opaque(dummy: impl Default) { - | ^^^^^^ - | - = help: consider removing the parameters + | ^^^^^^ help: consider removing the parameters -error: type parameter goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:95:58 +error: type parameter `U` goes unused in function definition + --> $DIR/extra_unused_type_parameters.rs:90:56 | LL | fn unused_with_priv_trait_bound() { - | ^ - | - = help: consider removing the parameter + | ^^^ help: consider removing the parameter -error: aborting due to 9 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/extra_unused_type_parameters_unfixable.rs b/tests/ui/extra_unused_type_parameters_unfixable.rs new file mode 100644 index 000000000000..10b39aa8f2c5 --- /dev/null +++ b/tests/ui/extra_unused_type_parameters_unfixable.rs @@ -0,0 +1,24 @@ +#![warn(clippy::extra_unused_type_parameters)] + +fn unused_where_clause(x: U) +where + T: Default, +{ + unimplemented!(); +} + +fn unused_multi_where_clause(x: U) +where + T: Default, +{ + unimplemented!(); +} + +fn unused_all_where_clause() +where + T: Default, +{ + unimplemented!(); +} + +fn main() {} diff --git a/tests/ui/extra_unused_type_parameters_unfixable.stderr b/tests/ui/extra_unused_type_parameters_unfixable.stderr new file mode 100644 index 000000000000..a9580cc894f3 --- /dev/null +++ b/tests/ui/extra_unused_type_parameters_unfixable.stderr @@ -0,0 +1,27 @@ +error: type parameter `T` goes unused in function definition + --> $DIR/extra_unused_type_parameters_unfixable.rs:3:24 + | +LL | fn unused_where_clause(x: U) + | ^ + | + = help: consider removing the parameter + = note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings` + +error: type parameters go unused in function definition: T, V + --> $DIR/extra_unused_type_parameters_unfixable.rs:10:30 + | +LL | fn unused_multi_where_clause(x: U) + | ^ ^^^^^^^^^^ + | + = help: consider removing the parameters + +error: type parameters go unused in function definition: T, U, V + --> $DIR/extra_unused_type_parameters_unfixable.rs:17:28 + | +LL | fn unused_all_where_clause() + | ^ ^^^^^^^^^^ ^^^^^^^^^^ + | + = help: consider removing the parameters + +error: aborting due to 3 previous errors + From 8df896c076fd993bad58878ee8a6ed29d8e586ba Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 24 Mar 2023 14:04:35 +0100 Subject: [PATCH 024/272] Merge commit 'd5e2a7aca55ed49fc943b7a07a8eba05ab5a0079' into clippyup --- CHANGELOG.md | 9 +- CONTRIBUTING.md | 2 +- book/src/lint_configuration.md | 1 + clippy_lints/src/allow_attributes.rs | 71 +++ clippy_lints/src/booleans.rs | 25 +- clippy_lints/src/copies.rs | 70 ++- clippy_lints/src/declared_lints.rs | 3 + clippy_lints/src/default.rs | 9 +- clippy_lints/src/derive.rs | 8 +- clippy_lints/src/functions/must_use.rs | 5 +- clippy_lints/src/if_then_some_else_none.rs | 17 +- clippy_lints/src/let_with_type_underscore.rs | 2 +- clippy_lints/src/lib.rs | 9 +- clippy_lints/src/loops/same_item_push.rs | 32 +- clippy_lints/src/manual_async_fn.rs | 15 +- clippy_lints/src/manual_clamp.rs | 7 +- clippy_lints/src/manual_main_separator_str.rs | 74 +++ clippy_lints/src/matches/manual_unwrap_or.rs | 12 +- clippy_lints/src/matches/match_bool.rs | 20 +- clippy_lints/src/matches/match_ref_pats.rs | 28 +- .../src/matches/match_single_binding.rs | 52 +- .../src/matches/redundant_pattern_match.rs | 17 +- clippy_lints/src/matches/single_match.rs | 18 +- .../src/methods/bind_instead_of_map.rs | 11 +- clippy_lints/src/methods/clone_on_ref_ptr.rs | 8 +- clippy_lints/src/methods/or_fun_call.rs | 28 +- clippy_lints/src/misc.rs | 17 +- clippy_lints/src/mut_key.rs | 60 +-- clippy_lints/src/needless_bool.rs | 13 +- clippy_lints/src/no_mangle_with_rust_abi.rs | 28 +- clippy_lints/src/option_if_let_else.rs | 28 +- clippy_lints/src/redundant_async_block.rs | 39 +- .../src/semicolon_if_nothing_returned.rs | 13 +- .../src/significant_drop_tightening.rs | 38 +- clippy_lints/src/swap.rs | 7 +- clippy_lints/src/unit_types/let_unit_value.rs | 7 +- .../src/unnecessary_struct_initialization.rs | 84 ++++ clippy_lints/src/useless_conversion.rs | 14 +- clippy_lints/src/utils/conf.rs | 2 +- clippy_lints/src/wildcard_imports.rs | 8 +- clippy_utils/src/attrs.rs | 2 +- clippy_utils/src/eager_or_lazy.rs | 7 +- clippy_utils/src/msrvs.rs | 1 + clippy_utils/src/paths.rs | 1 + clippy_utils/src/qualify_min_const_fn.rs | 7 +- clippy_utils/src/source.rs | 42 +- clippy_utils/src/sugg.rs | 10 +- clippy_utils/src/ty.rs | 63 ++- clippy_utils/src/visitors.rs | 4 +- rust-toolchain | 2 +- tests/dogfood.rs | 4 +- tests/ui-internal/custom_ice_message.stderr | 1 + tests/ui-toml/ifs_same_cond/clippy.toml | 1 + tests/ui-toml/ifs_same_cond/ifs_same_cond.rs | 18 + .../ifs_same_cond/ifs_same_cond.stderr | 15 + tests/ui/allow_attributes.fixed | 25 + tests/ui/allow_attributes.rs | 25 + tests/ui/allow_attributes.stderr | 16 + tests/ui/almost_complete_range.fixed | 49 +- tests/ui/almost_complete_range.rs | 49 +- tests/ui/almost_complete_range.stderr | 93 ++-- tests/ui/as_conversions.rs | 13 +- tests/ui/as_conversions.stderr | 6 +- tests/ui/auxiliary/doc_unsafe_macros.rs | 16 - tests/ui/auxiliary/implicit_hasher_macros.rs | 6 - tests/ui/auxiliary/macro_rules.rs | 141 +----- tests/ui/auxiliary/macro_use_helper.rs | 2 +- tests/ui/auxiliary/proc_macro_with_span.rs | 32 -- tests/ui/auxiliary/proc_macros.rs | 474 ++++++++++++++++++ .../auxiliary/helper.rs | 2 +- tests/ui/crashes/ice-10148.rs | 6 +- tests/ui/default_numeric_fallback_f64.fixed | 17 +- tests/ui/default_numeric_fallback_f64.rs | 17 +- tests/ui/default_numeric_fallback_f64.stderr | 11 +- tests/ui/default_numeric_fallback_i32.fixed | 17 +- tests/ui/default_numeric_fallback_i32.rs | 17 +- tests/ui/default_numeric_fallback_i32.stderr | 11 +- tests/ui/default_trait_access.fixed | 6 +- tests/ui/default_trait_access.rs | 6 +- tests/ui/deref_addrof.fixed | 24 +- tests/ui/deref_addrof.rs | 24 +- tests/ui/deref_addrof.stderr | 38 +- tests/ui/deref_addrof_macro.rs | 15 +- tests/ui/doc_unsafe.rs | 12 +- tests/ui/empty_loop.rs | 15 +- tests/ui/equatable_if_let.fixed | 16 +- tests/ui/equatable_if_let.rs | 16 +- tests/ui/equatable_if_let.stderr | 32 +- tests/ui/field_reassign_with_default.rs | 36 +- tests/ui/field_reassign_with_default.stderr | 44 +- tests/ui/ifs_same_cond.rs | 26 + tests/ui/ifs_same_cond.stderr | 14 +- tests/ui/implicit_hasher.rs | 25 +- tests/ui/implicit_hasher.stderr | 55 +- .../ui/inconsistent_struct_constructor.fixed | 21 +- tests/ui/inconsistent_struct_constructor.rs | 21 +- .../ui/inconsistent_struct_constructor.stderr | 4 +- tests/ui/large_enum_variant.rs | 13 +- tests/ui/macro_use_imports.fixed | 4 +- tests/ui/macro_use_imports.rs | 2 +- tests/ui/macro_use_imports.stderr | 2 +- tests/ui/macro_use_imports_expect.rs | 2 +- tests/ui/manual_async_fn.fixed | 6 + tests/ui/manual_async_fn.rs | 12 + tests/ui/manual_async_fn.stderr | 47 +- tests/ui/manual_clamp.rs | 19 + tests/ui/manual_main_separator_str.fixed | 39 ++ tests/ui/manual_main_separator_str.rs | 39 ++ tests/ui/manual_main_separator_str.stderr | 28 ++ tests/ui/manual_rem_euclid.fixed | 24 +- tests/ui/manual_rem_euclid.rs | 24 +- tests/ui/manual_rem_euclid.stderr | 17 +- tests/ui/match_single_binding.fixed | 41 +- tests/ui/match_single_binding.rs | 55 +- tests/ui/match_single_binding.stderr | 111 +++- tests/ui/match_single_binding2.fixed | 4 +- tests/ui/match_single_binding2.stderr | 4 +- tests/ui/mem_replace_macro.rs | 23 +- tests/ui/mem_replace_macro.stderr | 11 +- .../ui/missing_const_for_fn/cant_be_const.rs | 6 +- tests/ui/missing_doc.rs | 6 +- tests/ui/missing_doc_impl.rs | 6 +- tests/ui/mistyped_literal_suffix.fixed | 6 +- tests/ui/mistyped_literal_suffix.rs | 6 +- tests/ui/multiple_unsafe_ops_per_block.rs | 11 +- tests/ui/multiple_unsafe_ops_per_block.stderr | 18 +- tests/ui/must_use_unit.fixed | 11 +- tests/ui/must_use_unit.rs | 11 +- tests/ui/mut_mut.rs | 11 +- tests/ui/mut_mut.stderr | 25 +- tests/ui/needless_late_init.fixed | 36 +- tests/ui/needless_late_init.rs | 36 +- tests/ui/needless_late_init.stderr | 32 +- tests/ui/needless_lifetimes.fixed | 41 +- tests/ui/needless_lifetimes.rs | 41 +- tests/ui/needless_lifetimes.stderr | 15 +- tests/ui/needless_update.rs | 2 +- tests/ui/no_effect.rs | 7 +- tests/ui/no_effect.stderr | 58 +-- tests/ui/no_mangle_with_rust_abi.fixed | 48 -- tests/ui/no_mangle_with_rust_abi.rs | 2 - tests/ui/no_mangle_with_rust_abi.stderr | 74 ++- tests/ui/nonminimal_bool.rs | 29 ++ tests/ui/option_env_unwrap.rs | 24 +- tests/ui/option_env_unwrap.stderr | 42 +- tests/ui/ptr_as_ptr.fixed | 16 +- tests/ui/ptr_as_ptr.rs | 16 +- tests/ui/ptr_as_ptr.stderr | 25 +- tests/ui/redundant_async_block.fixed | 47 ++ tests/ui/redundant_async_block.rs | 47 ++ tests/ui/redundant_async_block.stderr | 22 +- .../redundant_pattern_matching_result.fixed | 4 +- .../redundant_pattern_matching_result.stderr | 4 +- tests/ui/single_match_else.rs | 6 +- tests/ui/string_add.rs | 11 +- tests/ui/swap.fixed | 15 +- tests/ui/swap.rs | 15 +- tests/ui/swap.stderr | 34 +- tests/ui/toplevel_ref_arg.fixed | 24 +- tests/ui/toplevel_ref_arg.rs | 24 +- tests/ui/toplevel_ref_arg.stderr | 21 +- tests/ui/toplevel_ref_arg_non_rustfix.rs | 22 +- tests/ui/toplevel_ref_arg_non_rustfix.stderr | 7 +- tests/ui/try_err.fixed | 67 +-- tests/ui/try_err.rs | 67 +-- tests/ui/try_err.stderr | 32 +- tests/ui/uninit.rs | 23 +- tests/ui/uninit.stderr | 16 +- tests/ui/uninit_vec.rs | 27 + tests/ui/uninit_vec.stderr | 33 +- tests/ui/uninlined_format_args.fixed | 6 +- tests/ui/uninlined_format_args.rs | 6 +- tests/ui/unit_arg.rs | 6 +- tests/ui/unnecessary_lazy_eval.fixed | 6 +- tests/ui/unnecessary_lazy_eval.rs | 6 +- tests/ui/unnecessary_operation.fixed | 8 +- tests/ui/unnecessary_operation.rs | 8 +- tests/ui/unnecessary_operation.stderr | 38 +- .../unnecessary_struct_initialization.fixed | 73 +++ tests/ui/unnecessary_struct_initialization.rs | 77 +++ .../unnecessary_struct_initialization.stderr | 46 ++ tests/ui/unnecessary_unsafety_doc.rs | 12 +- tests/ui/unnecessary_unsafety_doc.stderr | 2 +- triagebot.toml | 1 + 184 files changed, 3000 insertions(+), 1635 deletions(-) create mode 100644 clippy_lints/src/allow_attributes.rs create mode 100644 clippy_lints/src/manual_main_separator_str.rs create mode 100644 clippy_lints/src/unnecessary_struct_initialization.rs create mode 100644 tests/ui-toml/ifs_same_cond/clippy.toml create mode 100644 tests/ui-toml/ifs_same_cond/ifs_same_cond.rs create mode 100644 tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr create mode 100644 tests/ui/allow_attributes.fixed create mode 100644 tests/ui/allow_attributes.rs create mode 100644 tests/ui/allow_attributes.stderr delete mode 100644 tests/ui/auxiliary/doc_unsafe_macros.rs delete mode 100644 tests/ui/auxiliary/implicit_hasher_macros.rs delete mode 100644 tests/ui/auxiliary/proc_macro_with_span.rs create mode 100644 tests/ui/auxiliary/proc_macros.rs create mode 100644 tests/ui/manual_main_separator_str.fixed create mode 100644 tests/ui/manual_main_separator_str.rs create mode 100644 tests/ui/manual_main_separator_str.stderr delete mode 100644 tests/ui/no_mangle_with_rust_abi.fixed create mode 100644 tests/ui/unnecessary_struct_initialization.fixed create mode 100644 tests/ui/unnecessary_struct_initialization.rs create mode 100644 tests/ui/unnecessary_struct_initialization.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 0abe234fc8f7..1323f973ccfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -152,6 +152,8 @@ Current stable, released 2023-03-09 * `SYSROOT` and `--sysroot` can now be set at the same time [#10149](https://github.com/rust-lang/rust-clippy/pull/10149) +* Fix error when providing an `array-size-threshold` in `clippy.toml` + [#10423](https://github.com/rust-lang/rust-clippy/pull/10423) ## Rust 1.67 @@ -186,8 +188,6 @@ Released 2023-01-26 ### Moves and Deprecations -* Moved [`uninlined_format_args`] to `style` (Now warn-by-default) - [#9865](https://github.com/rust-lang/rust-clippy/pull/9865) * Moved [`needless_collect`] to `nursery` (Now allow-by-default) [#9705](https://github.com/rust-lang/rust-clippy/pull/9705) * Moved [`or_fun_call`] to `nursery` (Now allow-by-default) @@ -423,7 +423,7 @@ Released 2022-12-15 [#9490](https://github.com/rust-lang/rust-clippy/pull/9490) * [`almost_complete_letter_range`]: No longer lints in external macros [#9467](https://github.com/rust-lang/rust-clippy/pull/9467) -* [`drop_copy`]: No longer lints on idiomatic cases in match arms +* [`drop_copy`]: No longer lints on idiomatic cases in match arms [#9491](https://github.com/rust-lang/rust-clippy/pull/9491) * [`question_mark`]: No longer lints in const context [#9487](https://github.com/rust-lang/rust-clippy/pull/9487) @@ -4382,6 +4382,7 @@ Released 2018-09-13 [`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons [`alloc_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#alloc_instead_of_core +[`allow_attributes`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes [`allow_attributes_without_reason`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes_without_reason [`almost_complete_letter_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_letter_range [`almost_complete_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range @@ -4661,6 +4662,7 @@ Released 2018-09-13 [`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check [`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else +[`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive @@ -4985,6 +4987,7 @@ Released 2018-09-13 [`unnecessary_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc [`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports [`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by +[`unnecessary_struct_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_struct_initialization [`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap [`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3158080d2b30..3df132803694 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -50,7 +50,7 @@ a [developer guide] and is a good place to start your journey. All issues on Clippy are mentored, if you want help simply ask someone from the Clippy team directly by mentioning them in the issue or over on [Zulip]. All currently active team members can be found -[here](https://github.com/rust-lang/highfive/blob/master/highfive/configs/rust-lang/rust-clippy.json#L3) +[here](https://github.com/rust-lang/rust-clippy/blob/master/triagebot.toml#L18) Some issues are easier than others. The [`good-first-issue`] label can be used to find the easy issues. You can use `@rustbot claim` to assign the issue to yourself. diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 995dd2f04b1e..9ed6627b7413 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -519,6 +519,7 @@ for the generic parameters for determining interior mutability **Default Value:** `["bytes::Bytes"]` (`Vec`) * [mutable_key_type](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type) +* [ifs_same_cond](https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond) ### allow-mixed-uninlined-format-args diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs new file mode 100644 index 000000000000..15d46e954a9a --- /dev/null +++ b/clippy_lints/src/allow_attributes.rs @@ -0,0 +1,71 @@ +use ast::AttrStyle; +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast as ast; +use rustc_errors::Applicability; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// Detects uses of the `#[allow]` attribute and suggests replacing it with + /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html)) + /// + /// The expect attribute is still unstable and requires the `lint_reasons` + /// on nightly. It can be enabled by adding `#![feature(lint_reasons)]` to + /// the crate root. + /// + /// This lint only warns outer attributes (`#[allow]`), as inner attributes + /// (`#![allow]`) are usually used to enable or disable lints on a global scale. + /// + /// ### Why is this bad? + /// + /// `#[expect]` attributes suppress the lint emission, but emit a warning, if + /// the expectation is unfulfilled. This can be useful to be notified when the + /// lint is no longer triggered. + /// + /// ### Example + /// ```rust,ignore + /// #[allow(unused_mut)] + /// fn foo() -> usize { + /// let mut a = Vec::new(); + /// a.len() + /// } + /// ``` + /// Use instead: + /// ```rust,ignore + /// #![feature(lint_reasons)] + /// #[expect(unused_mut)] + /// fn foo() -> usize { + /// let mut a = Vec::new(); + /// a.len() + /// } + /// ``` + #[clippy::version = "1.69.0"] + pub ALLOW_ATTRIBUTES, + restriction, + "`#[allow]` will not trigger if a warning isn't found. `#[expect]` triggers if there are no warnings." +} + +declare_lint_pass!(AllowAttribute => [ALLOW_ATTRIBUTES]); + +impl LateLintPass<'_> for AllowAttribute { + // Separate each crate's features. + fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) { + if_chain! { + if cx.tcx.features().lint_reasons; + if let AttrStyle::Outer = attr.style; + if let Some(ident) = attr.ident(); + if ident.name == rustc_span::symbol::sym::allow; + then { + span_lint_and_sugg( + cx, + ALLOW_ATTRIBUTES, + ident.span, + "#[allow] attribute found", + "replace it with", + "expect".into(), + Applicability::MachineApplicable, + ); + } + } + } +} diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index e8106beec374..29fde9336c0b 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -495,18 +495,19 @@ struct NotSimplificationVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind { - if let Some(suggestion) = simplify_not(self.cx, inner) { - span_lint_and_sugg( - self.cx, - NONMINIMAL_BOOL, - expr.span, - "this boolean expression can be simplified", - "try", - suggestion, - Applicability::MachineApplicable, - ); - } + if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind && + !inner.span.from_expansion() && + let Some(suggestion) = simplify_not(self.cx, inner) + { + span_lint_and_sugg( + self.cx, + NONMINIMAL_BOOL, + expr.span, + "this boolean expression can be simplified", + "try", + suggestion, + Applicability::MachineApplicable, + ); } walk_expr(self, expr); diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index f10c35cde52a..970f50049935 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,18 +1,20 @@ 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, snippet_opt}; -use clippy_utils::ty::needs_ordered_drop; +use clippy_utils::ty::{is_interior_mut_ty, needs_ordered_drop}; use clippy_utils::visitors::for_each_expr; use clippy_utils::{ - capture_local_usage, eq_expr_value, get_enclosing_block, hash_expr, hash_stmt, if_sequence, is_else_clause, - is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq, + capture_local_usage, def_path_def_ids, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt, + if_sequence, is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq, }; use core::iter; use core::ops::ControlFlow; use rustc_errors::Applicability; +use rustc_hir::def_id::DefIdSet; use rustc_hir::intravisit; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_middle::query::Key; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::walk_chain; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Span, Symbol}; @@ -159,7 +161,21 @@ declare_clippy_lint! { "`if` statement with shared code in all blocks" } -declare_lint_pass!(CopyAndPaste => [ +pub struct CopyAndPaste { + ignore_interior_mutability: Vec, + ignored_ty_ids: DefIdSet, +} + +impl CopyAndPaste { + pub fn new(ignore_interior_mutability: Vec) -> Self { + Self { + ignore_interior_mutability, + ignored_ty_ids: DefIdSet::new(), + } + } +} + +impl_lint_pass!(CopyAndPaste => [ IFS_SAME_COND, SAME_FUNCTIONS_IN_IF_CONDITION, IF_SAME_THEN_ELSE, @@ -167,10 +183,18 @@ declare_lint_pass!(CopyAndPaste => [ ]); impl<'tcx> LateLintPass<'tcx> for CopyAndPaste { + fn check_crate(&mut self, cx: &LateContext<'tcx>) { + for ignored_ty in &self.ignore_interior_mutability { + let path: Vec<&str> = ignored_ty.split("::").collect(); + for id in def_path_def_ids(cx, path.as_slice()) { + self.ignored_ty_ids.insert(id); + } + } + } 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); - lint_same_cond(cx, &conds); + lint_same_cond(cx, &conds, &self.ignored_ty_ids); lint_same_fns_in_if_cond(cx, &conds); let all_same = !is_lint_allowed(cx, IF_SAME_THEN_ELSE, expr.hir_id) && lint_if_same_then_else(cx, &conds, &blocks); @@ -547,9 +571,39 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo }) } +fn method_caller_is_mutable(cx: &LateContext<'_>, caller_expr: &Expr<'_>, ignored_ty_ids: &DefIdSet) -> bool { + let caller_ty = cx.typeck_results().expr_ty(caller_expr); + // Check if given type has inner mutability and was not set to ignored by the configuration + let is_inner_mut_ty = is_interior_mut_ty(cx, caller_ty) + && !matches!(caller_ty.ty_adt_id(), Some(adt_id) if ignored_ty_ids.contains(&adt_id)); + + is_inner_mut_ty + || caller_ty.is_mutable_ptr() + // `find_binding_init` will return the binding iff its not mutable + || path_to_local(caller_expr) + .and_then(|hid| find_binding_init(cx, hid)) + .is_none() +} + /// Implementation of `IFS_SAME_COND`. -fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) { - for (i, j) in search_same(conds, |e| hash_expr(cx, e), |lhs, rhs| eq_expr_value(cx, lhs, rhs)) { +fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &DefIdSet) { + for (i, j) in search_same( + conds, + |e| hash_expr(cx, e), + |lhs, rhs| { + // Ignore eq_expr side effects iff one of the expressin kind is a method call + // and the caller is not a mutable, including inner mutable type. + if let ExprKind::MethodCall(_, caller, _, _) = lhs.kind { + if method_caller_is_mutable(cx, caller, ignored_ty_ids) { + false + } else { + SpanlessEq::new(cx).eq_expr(lhs, rhs) + } + } else { + eq_expr_value(cx, lhs, rhs) + } + }, + ) { span_lint_and_note( cx, IFS_SAME_COND, diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index cc6024b87cda..8ca91301472e 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -35,6 +35,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO, #[cfg(feature = "internal")] crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO, + crate::allow_attributes::ALLOW_ATTRIBUTES_INFO, crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO, crate::approx_const::APPROX_CONSTANT_INFO, crate::as_conversions::AS_CONVERSIONS_INFO, @@ -262,6 +263,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::manual_clamp::MANUAL_CLAMP_INFO, crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO, crate::manual_let_else::MANUAL_LET_ELSE_INFO, + crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO, crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO, crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO, crate::manual_retain::MANUAL_RETAIN_INFO, @@ -616,6 +618,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::unnamed_address::VTABLE_ADDRESS_COMPARISONS_INFO, crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO, crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO, + crate::unnecessary_struct_initialization::UNNECESSARY_STRUCT_INITIALIZATION_INFO, crate::unnecessary_wraps::UNNECESSARY_WRAPS_INFO, crate::unnested_or_patterns::UNNESTED_OR_PATTERNS_INFO, crate::unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME_INFO, diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 080d44e6398c..80c22742ba44 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; -use clippy_utils::source::snippet_with_macro_callsite; +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, match_def_path, paths, @@ -160,6 +160,8 @@ impl<'tcx> LateLintPass<'tcx> for Default { } }; + let init_ctxt = local.span.ctxt(); + // find all "later statement"'s where the fields of the binding set as // Default::default() get reassigned, unless the reassignment refers to the original binding let mut first_assign = None; @@ -169,7 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { // find out if and which field was set by this `consecutive_statement` if let Some((field_ident, assign_rhs)) = field_reassigned_by_stmt(consecutive_statement, binding_name) { // interrupt and cancel lint if assign_rhs references the original binding - if contains_name(binding_name, assign_rhs, cx) { + if contains_name(binding_name, assign_rhs, cx) || init_ctxt != consecutive_statement.span.ctxt() { cancel_lint = true; break; } @@ -204,11 +206,12 @@ impl<'tcx> LateLintPass<'tcx> for Default { .iter() .all(|field| assigned_fields.iter().any(|(a, _)| a == &field.name)); + let mut app = Applicability::Unspecified; let field_list = assigned_fields .into_iter() .map(|(field, rhs)| { // extract and store the assigned value for help message - let value_snippet = snippet_with_macro_callsite(cx, rhs.span, ".."); + let value_snippet = snippet_with_context(cx, rhs.span, init_ctxt, "..", &mut app).0; format!("{field}: {value_snippet}") }) .collect::>() diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 715348e869ef..f425dd5fb70b 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -24,8 +24,8 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Checks for deriving `Hash` but implementing `PartialEq` - /// explicitly or vice versa. + /// Lints against manual `PartialEq` implementations for types with a derived `Hash` + /// implementation. /// /// ### Why is this bad? /// The implementation of these traits must agree (for @@ -54,8 +54,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for deriving `Ord` but implementing `PartialOrd` - /// explicitly or vice versa. + /// Lints against manual `PartialOrd` and `Ord` implementations for types with a derived `Ord` + /// or `PartialOrd` implementation. /// /// ### Why is this bad? /// The implementation of these traits must agree (for diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 67877780c0e9..1e9e826631c3 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -50,10 +50,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); - } else if is_public - && !is_proc_macro(attrs) - && trait_ref_of_method(cx, item.owner_id.def_id).is_none() - { + } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none() { check_must_use_candidate( cx, sig.decl, diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 9cadaaa493e4..725bd3d54bc2 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,8 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::source::snippet_with_context; +use clippy_utils::sugg::Sugg; use clippy_utils::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks}; +use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -72,21 +74,20 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { return; } + let ctxt = expr.span.ctxt(); + if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr) && let ExprKind::Block(then_block, _) = then.kind && let Some(then_expr) = then_block.expr && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind + && 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) && !stmts_contains_early_return(then_block.stmts) { - let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]"); - let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) { - format!("({cond_snip})") - } else { - cond_snip.into_owned() - }; - let arg_snip = snippet_with_macro_callsite(cx, then_arg.span, ""); + let mut app = Applicability::Unspecified; + let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app).maybe_par().to_string(); + let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0; let mut method_body = if then_block.stmts.is_empty() { arg_snip.into_owned() } else { diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs index ba51973f2f9c..c01e3882d529 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 rustc_hir::*; +use rustc_hir::{Local, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 491732be2087..c9210bf73f89 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -67,6 +67,7 @@ mod declared_lints; mod renamed_lints; // begin lints modules, do not remove this comment, it’s used in `update_lints` +mod allow_attributes; mod almost_complete_range; mod approx_const; mod as_conversions; @@ -179,6 +180,7 @@ mod manual_bits; mod manual_clamp; mod manual_is_ascii_check; mod manual_let_else; +mod manual_main_separator_str; mod manual_non_exhaustive; mod manual_rem_euclid; mod manual_retain; @@ -300,6 +302,7 @@ mod unit_types; mod unnamed_address; mod unnecessary_owned_empty_strings; mod unnecessary_self_imports; +mod unnecessary_struct_initialization; mod unnecessary_wraps; mod unnested_or_patterns; mod unsafe_removed_from_name; @@ -656,7 +659,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum)); store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons)); store.register_late_pass(|_| Box::new(regex::Regex)); - store.register_late_pass(|_| Box::new(copies::CopyAndPaste)); + let ignore_interior_mutability = conf.ignore_interior_mutability.clone(); + store.register_late_pass(move |_| Box::new(copies::CopyAndPaste::new(ignore_interior_mutability.clone()))); store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator)); store.register_late_pass(|_| Box::new(format::UselessFormat)); store.register_late_pass(|_| Box::new(swap::Swap)); @@ -933,6 +937,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(missing_assert_message::MissingAssertMessage)); store.register_early_pass(|| Box::new(redundant_async_block::RedundantAsyncBlock)); store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped)); + store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute)); + store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(msrv()))); + store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 540656a2cd99..9d9341559ac7 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -1,15 +1,17 @@ use super::SAME_ITEM_PUSH; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::path_to_local; -use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; +use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; +use rustc_span::SyntaxContext; use std::iter::Iterator; /// Detects for loop pushing the same item into a Vec @@ -20,9 +22,10 @@ pub(super) fn check<'tcx>( body: &'tcx Expr<'_>, _: &'tcx Expr<'_>, ) { - fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>) { - let vec_str = snippet_with_macro_callsite(cx, vec.span, ""); - let item_str = snippet_with_macro_callsite(cx, pushed_item.span, ""); + fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>, ctxt: SyntaxContext) { + let mut app = Applicability::Unspecified; + let vec_str = snippet_with_context(cx, vec.span, ctxt, "", &mut app).0; + let item_str = snippet_with_context(cx, pushed_item.span, ctxt, "", &mut app).0; span_lint_and_help( cx, @@ -43,7 +46,7 @@ pub(super) fn check<'tcx>( walk_expr(&mut same_item_push_visitor, body); if_chain! { if same_item_push_visitor.should_lint(); - if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push; + if let Some((vec, pushed_item, ctxt)) = same_item_push_visitor.vec_push; let vec_ty = cx.typeck_results().expr_ty(vec); let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); if cx @@ -69,11 +72,11 @@ pub(super) fn check<'tcx>( then { match init.kind { // immutable bindings that are initialized with literal - ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item), + ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt), // immutable bindings that are initialized with constant ExprKind::Path(ref path) => { if let Res::Def(DefKind::Const, ..) = cx.qpath_res(path, init.hir_id) { - emit_lint(cx, vec, pushed_item); + emit_lint(cx, vec, pushed_item, ctxt); } } _ => {}, @@ -82,11 +85,11 @@ pub(super) fn check<'tcx>( } }, // constant - Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item), + Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item, ctxt), _ => {}, } }, - ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item), + ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt), _ => {}, } } @@ -98,7 +101,7 @@ struct SameItemPushVisitor<'a, 'tcx> { non_deterministic_expr: bool, multiple_pushes: bool, // this field holds the last vec push operation visited, which should be the only push seen - vec_push: Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)>, + vec_push: Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, SyntaxContext)>, cx: &'a LateContext<'tcx>, used_locals: FxHashSet, } @@ -118,7 +121,7 @@ impl<'a, 'tcx> SameItemPushVisitor<'a, 'tcx> { if_chain! { if !self.non_deterministic_expr; if !self.multiple_pushes; - if let Some((vec, _)) = self.vec_push; + if let Some((vec, _, _)) = self.vec_push; if let Some(hir_id) = path_to_local(vec); then { !self.used_locals.contains(&hir_id) @@ -173,7 +176,10 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> { // Given some statement, determine if that statement is a push on a Vec. If it is, return // the Vec being pushed into and the item being pushed -fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { +fn get_vec_push<'tcx>( + cx: &LateContext<'tcx>, + stmt: &'tcx Stmt<'_>, +) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, SyntaxContext)> { if_chain! { // Extract method being called if let StmtKind::Semi(semi_stmt) = &stmt.kind; @@ -184,7 +190,7 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(& if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec); if path.ident.name.as_str() == "push"; then { - return Some((self_expr, pushed_item)) + return Some((self_expr, pushed_item, semi_stmt.span.ctxt())) } } None diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index f97c6bcb5d18..577bc1d661db 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ AsyncGeneratorKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, - ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind, + ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { decl: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, span: Span, - _: LocalDefId, + def_id: LocalDefId, ) { if_chain! { if let Some(header) = kind.header(); @@ -59,6 +59,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { if let ExprKind::Block(block, _) = body.value.kind; if block.stmts.is_empty(); if let Some(closure_body) = desugared_async_block(cx, block); + if let Node::Item(Item {vis_span, ..}) | Node::ImplItem(ImplItem {vis_span, ..}) = + cx.tcx.hir().get_by_def_id(def_id); then { let header_span = span.with_hi(ret_ty.span.hi()); @@ -69,15 +71,22 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { "this function can be simplified using the `async fn` syntax", |diag| { if_chain! { + if let Some(vis_snip) = snippet_opt(cx, *vis_span); if let Some(header_snip) = snippet_opt(cx, header_span); if let Some(ret_pos) = position_before_rarrow(&header_snip); if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output); then { + let header_snip = if vis_snip.is_empty() { + format!("async {}", &header_snip[..ret_pos]) + } else { + format!("{} async {}", vis_snip, &header_snip[vis_snip.len() + 1..ret_pos]) + }; + let help = format!("make the function `async` and {ret_sugg}"); diag.span_suggestion( header_span, help, - format!("async {}{ret_snip}", &header_snip[..ret_pos]), + format!("{header_snip}{ret_snip}"), Applicability::MachineApplicable ); diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index f239736d38a4..440362b96b47 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -6,7 +6,8 @@ use clippy_utils::ty::implements_trait; use clippy_utils::visitors::is_const_evaluatable; use clippy_utils::MaybePath; use clippy_utils::{ - eq_expr_value, is_diag_trait_item, is_trait_method, path_res, path_to_local_id, peel_blocks, peel_blocks_with_stmt, + eq_expr_value, in_constant, is_diag_trait_item, is_trait_method, path_res, path_to_local_id, peel_blocks, + peel_blocks_with_stmt, }; use itertools::Itertools; use rustc_errors::Applicability; @@ -117,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp { if !self.msrv.meets(msrvs::CLAMP) { return; } - if !expr.span.from_expansion() { + if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) { let suggestion = is_if_elseif_else_pattern(cx, expr) .or_else(|| is_max_min_pattern(cx, expr)) .or_else(|| is_call_max_min_pattern(cx, expr)) @@ -130,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp { } fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { - if !self.msrv.meets(msrvs::CLAMP) { + if !self.msrv.meets(msrvs::CLAMP) || in_constant(cx, block.hir_id) { return; } for suggestion in is_two_if_pattern(cx, block) { diff --git a/clippy_lints/src/manual_main_separator_str.rs b/clippy_lints/src/manual_main_separator_str.rs new file mode 100644 index 000000000000..c292bbe4e934 --- /dev/null +++ b/clippy_lints/src/manual_main_separator_str.rs @@ -0,0 +1,74 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::{is_trait_method, match_def_path, paths, peel_hir_expr_refs}; +use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Expr, ExprKind, Mutability, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Checks for references on `std::path::MAIN_SEPARATOR.to_string()` used + /// to build a `&str`. + /// + /// ### Why is this bad? + /// There exists a `std::path::MAIN_SEPARATOR_STR` which does not require + /// an extra memory allocation. + /// + /// ### Example + /// ```rust + /// let s: &str = &std::path::MAIN_SEPARATOR.to_string(); + /// ``` + /// Use instead: + /// ```rust + /// let s: &str = std::path::MAIN_SEPARATOR_STR; + /// ``` + #[clippy::version = "1.70.0"] + pub MANUAL_MAIN_SEPARATOR_STR, + complexity, + "`&std::path::MAIN_SEPARATOR.to_string()` can be replaced by `std::path::MAIN_SEPARATOR_STR`" +} + +pub struct ManualMainSeparatorStr { + msrv: Msrv, +} + +impl ManualMainSeparatorStr { + #[must_use] + pub fn new(msrv: Msrv) -> Self { + Self { msrv } + } +} + +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 && + 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 && + 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() + { + span_lint_and_sugg( + cx, + MANUAL_MAIN_SEPARATOR_STR, + expr.span, + "taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`", + "replace with", + "std::path::MAIN_SEPARATOR_STR".to_owned(), + Applicability::MachineApplicable, + ); + } + } + + extract_msrv_attr!(LateContext); +} diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index 6447899f2b94..b94501bf0ad3 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -32,14 +32,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: let reindented_or_body = reindent_multiline(or_body_snippet.into(), true, Some(indent)); - let suggestion = if scrutinee.span.from_expansion() { - // we don't want parentheses around macro, e.g. `(some_macro!()).unwrap_or(0)` - sugg::Sugg::hir_with_macro_callsite(cx, scrutinee, "..") - } - else { - sugg::Sugg::hir(cx, scrutinee, "..").maybe_par() - }; - + let mut app = Applicability::MachineApplicable; + let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par(); span_lint_and_sugg( cx, MANUAL_UNWRAP_OR, expr.span, @@ -48,7 +42,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: format!( "{suggestion}.unwrap_or({reindented_or_body})", ), - Applicability::MachineApplicable, + app, ); } } diff --git a/clippy_lints/src/matches/match_bool.rs b/clippy_lints/src/matches/match_bool.rs index 1c216e135704..df1e585f10b2 100644 --- a/clippy_lints/src/matches/match_bool.rs +++ b/clippy_lints/src/matches/match_bool.rs @@ -10,9 +10,9 @@ use rustc_middle::ty; use super::MATCH_BOOL; -pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { +pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { // Type of expression is `bool`. - if *cx.typeck_results().expr_ty(ex).kind() == ty::Bool { + if *cx.typeck_results().expr_ty(scrutinee).kind() == ty::Bool { span_lint_and_then( cx, MATCH_BOOL, @@ -36,24 +36,26 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: }; if let Some((true_expr, false_expr)) = exprs { + let mut app = Applicability::HasPlaceholders; + let ctxt = expr.span.ctxt(); let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) { (false, false) => Some(format!( "if {} {} else {}", - snippet(cx, ex.span, "b"), - expr_block(cx, true_expr, None, "..", Some(expr.span)), - expr_block(cx, false_expr, None, "..", Some(expr.span)) + snippet(cx, scrutinee.span, "b"), + expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app), + expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) )), (false, true) => Some(format!( "if {} {}", - snippet(cx, ex.span, "b"), - expr_block(cx, true_expr, None, "..", Some(expr.span)) + snippet(cx, scrutinee.span, "b"), + expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app) )), (true, false) => { - let test = Sugg::hir(cx, ex, ".."); + let test = Sugg::hir(cx, scrutinee, ".."); Some(format!( "if {} {}", !test, - expr_block(cx, false_expr, None, "..", Some(expr.span)) + expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) )) }, (true, true) => None, diff --git a/clippy_lints/src/matches/match_ref_pats.rs b/clippy_lints/src/matches/match_ref_pats.rs index 80f964ba1b72..aba4c85c59e2 100644 --- a/clippy_lints/src/matches/match_ref_pats.rs +++ b/clippy_lints/src/matches/match_ref_pats.rs @@ -1,13 +1,14 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::sugg::Sugg; use core::iter::once; +use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::LateContext; use super::MATCH_REF_PATS; -pub(crate) fn check<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>) +pub(crate) fn check<'a, 'b, I>(cx: &LateContext<'_>, scrutinee: &Expr<'_>, pats: I, expr: &Expr<'_>) where 'b: 'a, I: Clone + Iterator>, @@ -17,13 +18,28 @@ where } let (first_sugg, msg, title); - let span = ex.span.source_callsite(); - if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = ex.kind { - first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string())); + let ctxt = expr.span.ctxt(); + let mut app = Applicability::Unspecified; + if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = scrutinee.kind { + if scrutinee.span.ctxt() != ctxt { + return; + } + first_sugg = once(( + scrutinee.span, + Sugg::hir_with_context(cx, inner, ctxt, "..", &mut app).to_string(), + )); msg = "try"; title = "you don't need to add `&` to both the expression and the patterns"; } else { - first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string())); + let Some(span) = walk_span_to_context(scrutinee.span, ctxt) else { + return; + }; + first_sugg = once(( + span, + Sugg::hir_with_context(cx, scrutinee, ctxt, "..", &mut app) + .deref() + .to_string(), + )); msg = "instead of prefixing all patterns with `&`, you can dereference the expression"; title = "you don't need to add `&` to all patterns"; } diff --git a/clippy_lints/src/matches/match_single_binding.rs b/clippy_lints/src/matches/match_single_binding.rs index 065a5c72621c..89da7a55cbd5 100644 --- a/clippy_lints/src/matches/match_single_binding.rs +++ b/clippy_lints/src/matches/match_single_binding.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::HirNode; -use clippy_utils::source::{indent_of, snippet, snippet_block, snippet_with_applicability}; -use clippy_utils::sugg::Sugg; +use clippy_utils::source::{indent_of, snippet, snippet_block_with_context, snippet_with_applicability}; use clippy_utils::{get_parent_expr, is_refutable, peel_blocks}; use rustc_errors::Applicability; -use rustc_hir::{Arm, Expr, ExprKind, Node, PatKind}; +use rustc_hir::{Arm, Expr, ExprKind, Node, PatKind, StmtKind}; use rustc_lint::LateContext; use rustc_span::Span; @@ -24,21 +23,30 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e let matched_vars = ex.span; let bind_names = arms[0].pat.span; let match_body = peel_blocks(arms[0].body); - let mut snippet_body = if match_body.span.from_expansion() { - Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string() - } else { - snippet_block(cx, match_body.span, "..", Some(expr.span)).to_string() - }; + let mut app = Applicability::MaybeIncorrect; + let mut snippet_body = snippet_block_with_context( + cx, + match_body.span, + arms[0].span.ctxt(), + "..", + Some(expr.span), + &mut app, + ) + .0 + .to_string(); // Do we need to add ';' to suggestion ? - if let ExprKind::Block(block, _) = match_body.kind { - // macro + expr_ty(body) == () - if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() { - snippet_body.push(';'); + if let Node::Stmt(stmt) = cx.tcx.hir().get_parent(expr.hir_id) + && let StmtKind::Expr(_) = stmt.kind + && match match_body.kind { + // We don't need to add a ; to blocks, unless that block is from a macro expansion + ExprKind::Block(block, _) => block.span.from_expansion(), + _ => true, } + { + snippet_body.push(';'); } - let mut applicability = Applicability::MaybeIncorrect; match arms[0].pat.kind { PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => { let (target_span, sugg) = match opt_parent_assign_span(cx, ex) { @@ -48,7 +56,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e (ex, expr), (bind_names, matched_vars), &snippet_body, - &mut applicability, + &mut app, Some(span), true, ); @@ -60,7 +68,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e "this assignment could be simplified", "consider removing the `match` expression", sugg, - applicability, + app, ); return; @@ -69,10 +77,10 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e span, format!( "let {} = {};\n{}let {} = {snippet_body};", - snippet_with_applicability(cx, bind_names, "..", &mut applicability), - snippet_with_applicability(cx, matched_vars, "..", &mut applicability), + snippet_with_applicability(cx, bind_names, "..", &mut app), + snippet_with_applicability(cx, matched_vars, "..", &mut app), " ".repeat(indent_of(cx, expr.span).unwrap_or(0)), - snippet_with_applicability(cx, pat_span, "..", &mut applicability) + snippet_with_applicability(cx, pat_span, "..", &mut app) ), ), None => { @@ -81,7 +89,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e (ex, expr), (bind_names, matched_vars), &snippet_body, - &mut applicability, + &mut app, None, true, ); @@ -96,7 +104,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e "this match could be written as a `let` statement", "consider using a `let` statement", sugg, - applicability, + app, ); }, PatKind::Wild => { @@ -106,7 +114,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e (ex, expr), (bind_names, matched_vars), &snippet_body, - &mut applicability, + &mut app, None, false, ); @@ -118,7 +126,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e "this match could be replaced by its scrutinee and body", "consider using the scrutinee and body instead", sugg, - applicability, + app, ); } else { span_lint_and_sugg( diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index df0ea7f5b863..7b609ff3df8f 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -1,6 +1,6 @@ use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; use clippy_utils::visitors::any_temporaries_need_ordered_drop; @@ -150,22 +150,25 @@ fn find_sugg_for_if_let<'tcx>( // if/while let ... = ... { ... } // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ let expr_span = expr.span; + let ctxt = expr.span.ctxt(); // if/while let ... = ... { ... } - // ^^^ - let op_span = result_expr.span.source_callsite(); + // ^^^ + let Some(res_span) = walk_span_to_context(result_expr.span.source_callsite(), ctxt) else { + return; + }; // if/while let ... = ... { ... } - // ^^^^^^^^^^^^^^^^^^^ - let span = expr_span.until(op_span.shrink_to_hi()); + // ^^^^^^^^^^^^^^^^^^^^^^ + let span = expr_span.until(res_span.shrink_to_hi()); - let app = if needs_drop { + let mut app = if needs_drop { Applicability::MaybeIncorrect } else { Applicability::MachineApplicable }; - let sugg = Sugg::hir_with_macro_callsite(cx, result_expr, "_") + let sugg = Sugg::hir_with_context(cx, result_expr, ctxt, "_", &mut app) .maybe_par() .to_string(); diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 19b49c44d570..ad47c13896c5 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -67,8 +67,10 @@ fn report_single_pattern( els: Option<&Expr<'_>>, ) { let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH }; + let ctxt = expr.span.ctxt(); + let mut app = Applicability::HasPlaceholders; let els_str = els.map_or(String::new(), |els| { - format!(" else {}", expr_block(cx, els, None, "..", Some(expr.span))) + format!(" else {}", expr_block(cx, els, ctxt, "..", Some(expr.span), &mut app)) }); let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat); @@ -103,7 +105,7 @@ fn report_single_pattern( // PartialEq for different reference counts may not exist. "&".repeat(ref_count_diff), snippet(cx, arms[0].pat.span, ".."), - expr_block(cx, arms[0].body, None, "..", Some(expr.span)), + expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app), ); (msg, sugg) } else { @@ -112,21 +114,13 @@ fn report_single_pattern( "if let {} = {} {}{els_str}", snippet(cx, arms[0].pat.span, ".."), snippet(cx, ex.span, ".."), - expr_block(cx, arms[0].body, None, "..", Some(expr.span)), + expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app), ); (msg, sugg) } }; - span_lint_and_sugg( - cx, - lint, - expr.span, - msg, - "try this", - sugg, - Applicability::HasPlaceholders, - ); + span_lint_and_sugg(cx, lint, expr.span, msg, "try this", sugg, app); } fn check_opt_like<'a>( diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 8e1130cf8dfa..00853348840e 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,6 +1,6 @@ use super::{contains_return, BIND_INSTEAD_OF_MAP}; use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_with_macro_callsite}; +use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::{peel_blocks, visitors::find_all_ret_expressions}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -76,11 +76,8 @@ pub(crate) trait BindInsteadOfMap { if !contains_return(inner_expr); if let Some(msg) = Self::lint_msg(cx); then { - let some_inner_snip = if inner_expr.span.from_expansion() { - snippet_with_macro_callsite(cx, inner_expr.span, "_") - } else { - snippet(cx, inner_expr.span, "_") - }; + let mut app = Applicability::MachineApplicable; + let some_inner_snip = snippet_with_context(cx, inner_expr.span, closure_expr.span.ctxt(), "_", &mut app).0; let closure_args_snip = snippet(cx, closure_args_span, ".."); let option_snip = snippet(cx, recv.span, ".."); @@ -92,7 +89,7 @@ pub(crate) trait BindInsteadOfMap { &msg, "try this", note, - Applicability::MachineApplicable, + app, ); true } else { diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index 355f53532e26..5e8ad0861f33 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths; -use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -33,7 +33,9 @@ pub(super) fn check( return; }; - let snippet = snippet_with_macro_callsite(cx, receiver.span, ".."); + // Sometimes unnecessary ::<_> after Rc/Arc/Weak + let mut app = Applicability::Unspecified; + let snippet = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut app).0; span_lint_and_sugg( cx, @@ -42,7 +44,7 @@ pub(super) fn check( "using `.clone()` on a ref-counted pointer", "try this", format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)), - Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak + app, ); } } diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 4460f38fcc18..7ce28ea93e01 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_lazy_eval; -use clippy_utils::source::{snippet, snippet_with_macro_callsite}; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{contains_return, is_trait_item, last_path_segment}; use if_chain::if_chain; @@ -9,7 +9,6 @@ use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Symbol}; -use std::borrow::Cow; use super::OR_FUN_CALL; @@ -111,37 +110,24 @@ pub(super) fn check<'tcx>( if poss.contains(&name); then { + let ctxt = span.ctxt(); + let mut app = Applicability::HasPlaceholders; let sugg = { let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) { (false, Some(fun_span)) => (fun_span, false), _ => (arg.span, true), }; - let format_span = |span: Span| { - let not_macro_argument_snippet = snippet_with_macro_callsite(cx, span, ".."); - let snip = if not_macro_argument_snippet == "vec![]" { - let macro_expanded_snipped = snippet(cx, snippet_span, ".."); - match macro_expanded_snipped.strip_prefix("$crate::vec::") { - Some(stripped) => Cow::Owned(stripped.to_owned()), - None => macro_expanded_snipped, - } - } else { - not_macro_argument_snippet - }; - - snip.to_string() - }; - - let snip = format_span(snippet_span); + let snip = snippet_with_context(cx, snippet_span, ctxt, "..", &mut app).0; let snip = if use_lambda { let l_arg = if fn_has_arguments { "_" } else { "" }; format!("|{l_arg}| {snip}") } else { - snip + snip.into_owned() }; if let Some(f) = second_arg { - let f = format_span(f.span); + let f = snippet_with_context(cx, f.span, ctxt, "..", &mut app).0; format!("{snip}, {f}") } else { snip @@ -155,7 +141,7 @@ pub(super) fn check<'tcx>( &format!("use of `{name}` followed by a function call"), "try this", format!("{name}_{suffix}({sugg})"), - Applicability::HasPlaceholders, + app, ); } } diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 0705029a613b..3752b9a946f8 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_hir_and_then}; -use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::source::{snippet, snippet_opt, snippet_with_context}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; @@ -181,20 +181,17 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind; if let Some(init) = local.init; then { - // use the macro callsite when the init span (but not the whole local span) - // comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];` - let sugg_init = if init.span.from_expansion() && !local.span.from_expansion() { - Sugg::hir_with_macro_callsite(cx, init, "..") - } else { - Sugg::hir(cx, init, "..") - }; + let ctxt = local.span.ctxt(); + let mut app = Applicability::MachineApplicable; + let sugg_init = Sugg::hir_with_context(cx, init, ctxt, "..", &mut app); let (mutopt, initref) = if mutabl == Mutability::Mut { ("mut ", sugg_init.mut_addr()) } else { ("", sugg_init.addr()) }; let tyopt = if let Some(ty) = local.ty { - format!(": &{mutopt}{ty}", ty=snippet(cx, ty.span, "..")) + let ty_snip = snippet_with_context(cx, ty.span, ctxt, "_", &mut app).0; + format!(": &{mutopt}{ty_snip}") } else { String::new() }; @@ -212,7 +209,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { "let {name}{tyopt} = {initref};", name=snippet(cx, name.span, ".."), ), - Applicability::MachineApplicable, + app, ); } ); diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 8aa814b74053..309f67521a3b 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::span_lint; +use clippy_utils::ty::is_interior_mut_ty; use clippy_utils::{def_path_def_ids, trait_ref_of_method}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{Adt, Array, Ref, Slice, Tuple, Ty}; +use rustc_middle::query::Key; +use rustc_middle::ty::{Adt, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; @@ -153,53 +154,18 @@ impl MutableKeyType { let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet] .iter() .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did())); - if is_keyed_type && self.is_interior_mutable_type(cx, substs.type_at(0)) { + if !is_keyed_type { + return; + } + + let subst_ty = substs.type_at(0); + // Determines if a type contains interior mutability which would affect its implementation of + // [`Hash`] or [`Ord`]. + if is_interior_mut_ty(cx, subst_ty) + && !matches!(subst_ty.ty_adt_id(), Some(adt_id) if self.ignore_mut_def_ids.contains(&adt_id)) + { span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type"); } } } - - /// Determines if a type contains interior mutability which would affect its implementation of - /// [`Hash`] or [`Ord`]. - fn is_interior_mutable_type<'tcx>(&self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - match *ty.kind() { - Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || self.is_interior_mutable_type(cx, inner_ty), - Slice(inner_ty) => self.is_interior_mutable_type(cx, inner_ty), - Array(inner_ty, size) => { - size.try_eval_target_usize(cx.tcx, cx.param_env) - .map_or(true, |u| u != 0) - && self.is_interior_mutable_type(cx, inner_ty) - }, - Tuple(fields) => fields.iter().any(|ty| self.is_interior_mutable_type(cx, ty)), - Adt(def, substs) => { - // Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to - // that of their type parameters. Note: we don't include `HashSet` and `HashMap` - // because they have no impl for `Hash` or `Ord`. - let def_id = def.did(); - let is_std_collection = [ - sym::Option, - sym::Result, - sym::LinkedList, - sym::Vec, - sym::VecDeque, - sym::BTreeMap, - sym::BTreeSet, - sym::Rc, - sym::Arc, - ] - .iter() - .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def_id)); - let is_box = Some(def_id) == cx.tcx.lang_items().owned_box(); - if is_std_collection || is_box || self.ignore_mut_def_ids.contains(&def_id) { - // The type is mutable if any of its type parameters are - substs.types().any(|ty| self.is_interior_mutable_type(cx, ty)) - } else { - !ty.has_escaping_bound_vars() - && cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() - && !ty.is_freeze(cx.tcx, cx.param_env) - } - }, - _ => false, - } - } } diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index a4eec95b3715..c87059bf61de 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -340,18 +340,11 @@ fn suggest_bool_comparison<'a, 'tcx>( cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, expr: &Expr<'_>, - mut applicability: Applicability, + mut app: Applicability, message: &str, conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>, ) { - let hint = if expr.span.from_expansion() { - if applicability != Applicability::Unspecified { - applicability = Applicability::MaybeIncorrect; - } - Sugg::hir_with_macro_callsite(cx, expr, "..") - } else { - Sugg::hir_with_applicability(cx, expr, "..", &mut applicability) - }; + let hint = Sugg::hir_with_context(cx, expr, e.span.ctxt(), "..", &mut app); span_lint_and_sugg( cx, BOOL_COMPARISON, @@ -359,7 +352,7 @@ fn suggest_bool_comparison<'a, 'tcx>( message, "try simplifying it as shown", conv_hint(hint).to_string(), - applicability, + app, ); } diff --git a/clippy_lints/src/no_mangle_with_rust_abi.rs b/clippy_lints/src/no_mangle_with_rust_abi.rs index bc64ccb295cb..8fd9ae351a0d 100644 --- a/clippy_lints/src/no_mangle_with_rust_abi.rs +++ b/clippy_lints/src/no_mangle_with_rust_abi.rs @@ -1,9 +1,10 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{BytePos, Pos}; use rustc_target::spec::abi::Abi; declare_clippy_lint! { @@ -38,25 +39,28 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if let ItemKind::Fn(fn_sig, _, _) = &item.kind { let attrs = cx.tcx.hir().attrs(item.hir_id()); - let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, fn_sig.span, "..", &mut applicability); + let mut app = Applicability::MaybeIncorrect; + let snippet = snippet_with_applicability(cx, fn_sig.span, "..", &mut app); for attr in attrs { if let Some(ident) = attr.ident() && ident.name == rustc_span::sym::no_mangle && fn_sig.header.abi == Abi::Rust - && !snippet.contains("extern") { + && let Some((fn_attrs, _)) = snippet.split_once("fn") + && !fn_attrs.contains("extern") + { + let sugg_span = fn_sig.span + .with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len())) + .shrink_to_lo(); - let suggestion = snippet.split_once("fn") - .map_or(String::new(), |(first, second)| format!(r#"{first}extern "C" fn{second}"#)); - - span_lint_and_sugg( + span_lint_and_then( cx, NO_MANGLE_WITH_RUST_ABI, fn_sig.span, - "attribute #[no_mangle] set on a Rust ABI function", - "try", - suggestion, - applicability + "`#[no_mangle]` set on a function with the default (`Rust`) ABI", + |diag| { + diag.span_suggestion(sugg_span, "set an ABI", "extern \"C\" ", app) + .span_suggestion(sugg_span, "or explicitly set the default", "extern \"Rust\" ", app); + }, ); } } diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index c5ea09590d3d..bbbcda069c55 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -12,6 +12,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::SyntaxContext; declare_clippy_lint! { /// ### What it does @@ -95,10 +96,10 @@ struct OptionOccurrence { none_expr: String, } -fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: bool, as_mut: bool) -> String { +fn format_option_in_sugg(cond_sugg: Sugg<'_>, as_ref: bool, as_mut: bool) -> String { format!( "{}{}", - Sugg::hir_with_macro_callsite(cx, cond_expr, "..").maybe_par(), + cond_sugg.maybe_par(), if as_mut { ".as_mut()" } else if as_ref { @@ -111,6 +112,7 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo fn try_get_option_occurrence<'tcx>( cx: &LateContext<'tcx>, + ctxt: SyntaxContext, pat: &Pat<'tcx>, expr: &Expr<'_>, if_then: &'tcx Expr<'_>, @@ -160,11 +162,23 @@ fn try_get_option_occurrence<'tcx>( } } + let mut app = Applicability::Unspecified; return Some(OptionOccurrence { - option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut), + option: format_option_in_sugg( + Sugg::hir_with_context(cx, cond_expr, ctxt, "..", &mut app), + as_ref, + as_mut, + ), method_sugg: method_sugg.to_string(), - some_expr: format!("|{capture_mut}{capture_name}| {}", Sugg::hir_with_macro_callsite(cx, some_body, "..")), - none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir_with_macro_callsite(cx, none_body, "..")), + some_expr: format!( + "|{capture_mut}{capture_name}| {}", + Sugg::hir_with_context(cx, some_body, ctxt, "..", &mut app), + ), + none_expr: format!( + "{}{}", + if method_sugg == "map_or" { "" } else { "|| " }, + Sugg::hir_with_context(cx, none_body, ctxt, "..", &mut app), + ), }); } } @@ -194,7 +208,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> }) = higher::IfLet::hir(cx, expr) { if !is_else_clause(cx.tcx, expr) { - return try_get_option_occurrence(cx, let_pat, let_expr, if_then, if_else); + return try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, let_expr, if_then, if_else); } } None @@ -203,7 +217,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> fn detect_option_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option { if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind { if let Some((let_pat, if_then, if_else)) = try_convert_match(cx, arms) { - return try_get_option_occurrence(cx, let_pat, ex, if_then, if_else); + return try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, ex, if_then, if_else); } } None diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 27ad43086374..2d30e77d55de 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -1,5 +1,5 @@ use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet}; -use rustc_ast::ast::*; +use rustc_ast::ast::{Expr, ExprKind, Stmt, StmtKind}; use rustc_ast::visit::Visitor as AstVisitor; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -32,7 +32,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.69.0"] pub REDUNDANT_ASYNC_BLOCK, - complexity, + nursery, "`async { future.await }` can be replaced by `future`" } declare_lint_pass!(RedundantAsyncBlock => [REDUNDANT_ASYNC_BLOCK]); @@ -48,6 +48,11 @@ impl EarlyLintPass for RedundantAsyncBlock { !future.span.from_expansion() && !await_in_expr(future) { + if captures_value(last) { + // If the async block captures variables then there is no equivalence. + return; + } + span_lint_and_sugg( cx, REDUNDANT_ASYNC_BLOCK, @@ -82,3 +87,33 @@ impl<'ast> AstVisitor<'ast> for AwaitDetector { } } } + +/// Check whether an expression may have captured a local variable. +/// This is done by looking for paths with only one segment, except as +/// a prefix of `.await` since this would be captured by value. +/// +/// This function will sometimes return `true` even tough there are no +/// captures happening: at the AST level, it is impossible to +/// dinstinguish a function call from a call to a closure which comes +/// from the local environment. +fn captures_value(expr: &Expr) -> bool { + let mut detector = CaptureDetector::default(); + detector.visit_expr(expr); + detector.capture_found +} + +#[derive(Default)] +struct CaptureDetector { + capture_found: bool, +} + +impl<'ast> AstVisitor<'ast> for CaptureDetector { + fn visit_expr(&mut self, ex: &'ast Expr) { + match (&ex.kind, self.capture_found) { + (ExprKind::Await(fut), _) if matches!(fut.kind, ExprKind::Path(..)) => (), + (ExprKind::Path(_, path), _) if path.segments.len() == 1 => self.capture_found = true, + (_, false) => rustc_ast::visit::walk_expr(self, ex), + _ => (), + } + } +} diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 66638eed9983..355f907e2577 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -1,7 +1,6 @@ use crate::rustc_lint::LintContext; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_macro_callsite; -use clippy_utils::sugg; +use clippy_utils::source::snippet_with_context; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Block, ExprKind}; @@ -44,7 +43,8 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { if let Some(expr) = block.expr; let t_expr = cx.typeck_results().expr_ty(expr); if t_expr.is_unit(); - if let snippet = snippet_with_macro_callsite(cx, expr.span, "}"); + let mut app = Applicability::MaybeIncorrect; + if let snippet = snippet_with_context(cx, expr.span, block.span.ctxt(), "}", &mut app).0; if !snippet.ends_with('}') && !snippet.ends_with(';'); if cx.sess().source_map().is_multiline(block.span); then { @@ -52,17 +52,14 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { if let ExprKind::DropTemps(..) = &expr.kind { return; } - - let sugg = sugg::Sugg::hir_with_macro_callsite(cx, expr, ".."); - let suggestion = format!("{sugg};"); span_lint_and_sugg( cx, SEMICOLON_IF_NOTHING_RETURNED, expr.span.source_callsite(), "consider adding a `;` to the last statement for consistent formatting", "add a `;` here", - suggestion, - Applicability::MaybeIncorrect, + format!("{snippet};"), + app, ); } } diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index e12681c0a0ca..869358fb1ba7 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -1,9 +1,9 @@ -use crate::FxHashSet; use clippy_utils::{ diagnostics::span_lint_and_then, get_attr, source::{indent_of, snippet}, }; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::{ self as hir, @@ -58,6 +58,7 @@ impl_lint_pass!(SignificantDropTightening<'_> => [SIGNIFICANT_DROP_TIGHTENING]); pub struct SignificantDropTightening<'tcx> { /// Auxiliary structure used to avoid having to verify the same type multiple times. seen_types: FxHashSet>, + type_cache: FxHashMap, bool>, } impl<'tcx> SignificantDropTightening<'tcx> { @@ -118,7 +119,7 @@ impl<'tcx> SignificantDropTightening<'tcx> { stmt: &hir::Stmt<'_>, cb: impl Fn(&mut SigDropAuxParams), ) { - let mut sig_drop_finder = SigDropFinder::new(cx, &mut self.seen_types); + let mut sig_drop_finder = SigDropFinder::new(cx, &mut self.seen_types, &mut self.type_cache); sig_drop_finder.visit_expr(expr); if sig_drop_finder.has_sig_drop { cb(sdap); @@ -296,15 +297,24 @@ impl Default for SigDropAuxParams { struct SigDropChecker<'cx, 'sdt, 'tcx> { cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet>, + type_cache: &'sdt mut FxHashMap, bool>, } impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> { - pub(crate) fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet>) -> Self { + pub(crate) fn new( + cx: &'cx LateContext<'tcx>, + seen_types: &'sdt mut FxHashSet>, + type_cache: &'sdt mut FxHashMap, bool>, + ) -> Self { seen_types.clear(); - Self { cx, seen_types } + Self { + cx, + seen_types, + type_cache, + } } - pub(crate) fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool { + pub(crate) fn has_sig_drop_attr_uncached(&mut self, ty: Ty<'tcx>) -> bool { if let Some(adt) = ty.ty_adt_def() { let mut iter = get_attr( self.cx.sess(), @@ -340,6 +350,16 @@ impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> { } } + pub(crate) fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool { + // The borrow checker prevents us from using something fancier like or_insert_with. + if let Some(ty) = self.type_cache.get(&ty) { + return *ty; + } + let value = self.has_sig_drop_attr_uncached(ty); + self.type_cache.insert(ty, value); + value + } + fn has_seen_ty(&mut self, ty: Ty<'tcx>) -> bool { !self.seen_types.insert(ty) } @@ -353,11 +373,15 @@ struct SigDropFinder<'cx, 'sdt, 'tcx> { } impl<'cx, 'sdt, 'tcx> SigDropFinder<'cx, 'sdt, 'tcx> { - fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet>) -> Self { + fn new( + cx: &'cx LateContext<'tcx>, + seen_types: &'sdt mut FxHashSet>, + type_cache: &'sdt mut FxHashMap, bool>, + ) -> Self { Self { cx, has_sig_drop: false, - sig_drop_checker: SigDropChecker::new(cx, seen_types), + sig_drop_checker: SigDropChecker::new(cx, seen_types, type_cache), } } } diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 1aeac724ab13..f7eef03d1d47 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -6,7 +6,8 @@ use clippy_utils::{can_mut_borrow_both, eq_expr_value, in_constant, std_or_core} use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; @@ -188,8 +189,10 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { if let Some((lhs0, rhs0)) = parse(first) && let Some((lhs1, rhs1)) = parse(second) && first.span.eq_ctxt(second.span) + && !in_external_macro(cx.sess(), first.span) && is_same(cx, lhs0, rhs1) && is_same(cx, lhs1, rhs0) + && !is_same(cx, lhs1, rhs1) // Ignore a = b; a = a (#10421) && let Some(lhs_sugg) = match &lhs0 { ExprOrIdent::Expr(expr) => Sugg::hir_opt(cx, expr), ExprOrIdent::Ident(ident) => Some(Sugg::NonParen(ident.as_str().into())), @@ -257,8 +260,8 @@ fn parse<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(ExprOrIdent<'hir>, &'a Expr< /// Implementation of the xor case for `MANUAL_SWAP` lint. fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) { for [s1, s2, s3] in block.stmts.array_windows::<3>() { + let ctxt = s1.span.ctxt(); if_chain! { - let ctxt = s1.span.ctxt(); if let Some((lhs0, rhs0)) = extract_sides_of_xor_assign(s1, ctxt); if let Some((lhs1, rhs1)) = extract_sides_of_xor_assign(s2, ctxt); if let Some((lhs2, rhs2)) = extract_sides_of_xor_assign(s3, ctxt); diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs index 3430b6e37341..cc7c2b039f2d 100644 --- a/clippy_lints/src/unit_types/let_unit_value.rs +++ b/clippy_lints/src/unit_types/let_unit_value.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::get_parent_node; -use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::source::snippet_with_context; use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -52,12 +52,13 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { "this let-binding has unit value", |diag| { if let Some(expr) = &local.init { - let snip = snippet_with_macro_callsite(cx, expr.span, "()"); + let mut app = Applicability::MachineApplicable; + let snip = snippet_with_context(cx, expr.span, local.span.ctxt(), "()", &mut app).0; diag.span_suggestion( local.span, "omit the `let` binding", format!("{snip};"), - Applicability::MachineApplicable, // snippet + app, ); } }, diff --git a/clippy_lints/src/unnecessary_struct_initialization.rs b/clippy_lints/src/unnecessary_struct_initialization.rs new file mode 100644 index 000000000000..af0b4b1592f4 --- /dev/null +++ b/clippy_lints/src/unnecessary_struct_initialization.rs @@ -0,0 +1,84 @@ +use clippy_utils::{diagnostics::span_lint_and_sugg, get_parent_expr, path_to_local, source::snippet, ty::is_copy}; +use rustc_hir::{BindingAnnotation, Expr, ExprKind, Node, PatKind, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for initialization of a `struct` by copying a base without setting + /// any field. + /// + /// ### Why is this bad? + /// Readibility suffers from unnecessary struct building. + /// + /// ### Example + /// ```rust + /// struct S { s: String } + /// + /// let a = S { s: String::from("Hello, world!") }; + /// let b = S { ..a }; + /// ``` + /// Use instead: + /// ```rust + /// struct S { s: String } + /// + /// let a = S { s: String::from("Hello, world!") }; + /// let b = a; + /// ``` + #[clippy::version = "1.70.0"] + pub UNNECESSARY_STRUCT_INITIALIZATION, + complexity, + "struct built from a base that can be written mode concisely" +} +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; + } + + 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, + ); + } + } +} + +fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(hir_id) = path_to_local(expr) && + let Node::Pat(pat) = cx.tcx.hir().get(hir_id) + { + matches!(pat.kind, PatKind::Binding(BindingAnnotation::MUT, ..)) + } else { + true + } +} diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index fede625f72a8..ddbe6b2c7904 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; -use clippy_utils::source::{snippet, snippet_with_macro_callsite}; +use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, path_to_local, paths}; @@ -68,15 +68,16 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(recv); if same_type_and_consts(a, b) { - let sugg = snippet_with_macro_callsite(cx, recv.span, "").to_string(); + let mut app = Applicability::MachineApplicable; + let sugg = snippet_with_context(cx, recv.span, e.span.ctxt(), "", &mut app).0; span_lint_and_sugg( cx, USELESS_CONVERSION, e.span, &format!("useless conversion to the same type: `{b}`"), "consider removing `.into()`", - sugg, - Applicability::MachineApplicable, // snippet + sugg.into_owned(), + app, ); } } @@ -165,7 +166,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if same_type_and_consts(a, b); then { - let sugg = Sugg::hir_with_macro_callsite(cx, arg, "").maybe_par(); + let mut app = Applicability::MachineApplicable; + let sugg = Sugg::hir_with_context(cx, arg, e.span.ctxt(), "", &mut app).maybe_par(); let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); span_lint_and_sugg( @@ -175,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { &format!("useless conversion to the same type: `{b}`"), &sugg_msg, sugg.to_string(), - Applicability::MachineApplicable, // snippet + app, ); } } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 1c7f3e96db89..8ba252425a3d 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -437,7 +437,7 @@ define_Conf! { /// /// The maximum size of the `Err`-variant in a `Result` returned from a function (large_error_threshold: u64 = 128), - /// Lint: MUTABLE_KEY_TYPE. + /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND. /// /// A list of paths to types that should be treated like `Arc`, i.e. ignored but /// for the generic parameters for determining interior mutability diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index e105452e1c5f..36f910c983f6 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -158,12 +158,10 @@ impl LateLintPass<'_> for WildcardImports { let mut imports = used_imports.items().map(ToString::to_string).into_sorted_stable_ord(false); let imports_string = if imports.len() == 1 { imports.pop().unwrap() + } else if braced_glob { + imports.join(", ") } else { - if braced_glob { - imports.join(", ") - } else { - format!("{{{}}}", imports.join(", ")) - } + format!("{{{}}}", imports.join(", ")) }; let sugg = if braced_glob { diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index bc3d774540a5..b4ad42a50279 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -146,7 +146,7 @@ pub fn get_unique_attr<'a>( /// Return true if the attributes contain any of `proc_macro`, /// `proc_macro_derive` or `proc_macro_attribute`, false otherwise pub fn is_proc_macro(attrs: &[ast::Attribute]) -> bool { - attrs.iter().any(|attr| attr.is_proc_macro_attr()) + attrs.iter().any(rustc_ast::Attribute::is_proc_macro_attr) } /// Return true if the attributes contain `#[doc(hidden)]` diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index babbc7294a17..28c857170613 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -199,10 +199,9 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS }, // Memory allocation, custom operator, loop, or call to an unknown function - ExprKind::Unary(..) - | ExprKind::Binary(..) - | ExprKind::Loop(..) - | ExprKind::Call(..) => self.eagerness = Lazy, + ExprKind::Unary(..) | ExprKind::Binary(..) | ExprKind::Loop(..) | ExprKind::Call(..) => { + self.eagerness = Lazy; + }, ExprKind::ConstBlock(_) | ExprKind::Array(_) diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index dbf9f3b621d7..e05de2dc99c0 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -19,6 +19,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { + 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 4aae0f7284e4..c919575bfe90 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -67,6 +67,7 @@ pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"]; pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"]; pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"]; +pub const PATH_MAIN_SEPARATOR: [&str; 3] = ["std", "path", "MAIN_SEPARATOR"]; pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"]; pub const PEEKABLE: [&str; 5] = ["core", "iter", "adapters", "peekable", "Peekable"]; pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"]; diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 9f6adf3e3fab..d66640ba0b7a 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -176,9 +176,10 @@ fn check_rvalue<'tcx>( // FIXME(dyn-star) unimplemented!() }, - Rvalue::Cast(CastKind::Transmute, _, _) => { - Err((span, "transmute can attempt to turn pointers into integers, so is unstable in const fn".into())) - }, + Rvalue::Cast(CastKind::Transmute, _, _) => Err(( + span, + "transmute can attempt to turn pointers into integers, so is unstable in const fn".into(), + )), // binops are fine on integers Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => { check_operand(tcx, lhs, span, body)?; diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index cd5dcfdaca34..62fa37660fad 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -12,24 +12,21 @@ use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext, DUMMY_SP}; use std::borrow::Cow; /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`. -/// Also takes an `Option` which can be put inside the braces. -pub fn expr_block<'a, T: LintContext>( +pub fn expr_block( cx: &T, expr: &Expr<'_>, - option: Option, - default: &'a str, + outer: SyntaxContext, + default: &str, indent_relative_to: Option, -) -> Cow<'a, str> { - let code = snippet_block(cx, expr.span, default, indent_relative_to); - let string = option.unwrap_or_default(); - if expr.span.from_expansion() { - Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default))) + app: &mut Applicability, +) -> String { + let (code, from_macro) = snippet_block_with_context(cx, expr.span, outer, default, indent_relative_to, app); + if from_macro { + format!("{{ {code} }}") } else if let ExprKind::Block(_, _) = expr.kind { - Cow::Owned(format!("{code}{string}")) - } else if string.is_empty() { - Cow::Owned(format!("{{ {code} }}")) + format!("{code}") } else { - Cow::Owned(format!("{{\n{code};\n{string}\n}}")) + format!("{{ {code} }}") } } @@ -229,12 +226,6 @@ fn snippet_with_applicability_sess<'a>( ) } -/// Same as `snippet`, but should only be used when it's clear that the input span is -/// not a macro argument. -pub fn snippet_with_macro_callsite<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { - snippet(cx, span.source_callsite(), default) -} - /// Converts a span to a code snippet. Returns `None` if not available. pub fn snippet_opt(cx: &impl LintContext, span: Span) -> Option { snippet_opt_sess(cx.sess(), span) @@ -303,6 +294,19 @@ pub fn snippet_block_with_applicability<'a>( reindent_multiline(snip, true, indent) } +pub fn snippet_block_with_context<'a>( + cx: &impl LintContext, + span: Span, + outer: SyntaxContext, + default: &'a str, + indent_relative_to: Option, + app: &mut Applicability, +) -> (Cow<'a, str>, bool) { + let (snip, from_macro) = snippet_with_context(cx, span, outer, default, app); + let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); + (reindent_multiline(snip, true, indent), from_macro) +} + /// Same as `snippet_with_applicability`, but first walks the span up to the given context. This /// will result in the macro call, rather then the expansion, if the span is from a child context. /// If the span is not from a child context, it will be used directly instead. diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 44cb5d5756ad..a5a4a921d94e 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -1,9 +1,7 @@ //! Contains utility functions to generate suggestions. #![deny(clippy::missing_docs_in_private_items)] -use crate::source::{ - snippet, snippet_opt, snippet_with_applicability, snippet_with_context, snippet_with_macro_callsite, -}; +use crate::source::{snippet, snippet_opt, snippet_with_applicability, snippet_with_context}; use crate::ty::expr_sig; use crate::{get_parent_expr_for_hir, higher}; use rustc_ast::util::parser::AssocOp; @@ -89,12 +87,6 @@ impl<'a> Sugg<'a> { }) } - /// Same as `hir`, but will use the pre expansion span if the `expr` was in a macro. - pub fn hir_with_macro_callsite(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self { - let get_snippet = |span| snippet_with_macro_callsite(cx, span, default); - Self::hir_from_snippet(expr, get_snippet) - } - /// Same as `hir`, but first walks the span up to the given context. This will result in the /// macro call, rather then the expansion, if the span is from a child context. If the span is /// not from a child context, it will be used directly instead. diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index e0ea3952785b..0b47234647fb 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -16,9 +16,9 @@ use rustc_infer::infer::{ use rustc_lint::LateContext; use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::{ - self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv, Predicate, PredicateKind, - Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, - UintTy, VariantDef, VariantDiscr, + self, layout::ValidityRequirement, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv, + Predicate, PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr, }; use rustc_middle::ty::{GenericArg, GenericArgKind}; use rustc_span::symbol::Ident; @@ -538,13 +538,12 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { } /// Checks if a given type looks safe to be uninitialized. -pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - match *ty.kind() { - ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component), - ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)), - ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did()), - _ => false, - } +pub fn is_uninit_value_valid_for_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + cx.tcx + .check_validity_requirement((ValidityRequirement::Uninit, cx.param_env.and(ty))) + // For types containing generic parameters we cannot get a layout to check. + // Therefore, we are conservative and assume that they don't allow uninit. + .unwrap_or(false) } /// Gets an iterator over all predicates which apply to the given item. @@ -1121,3 +1120,47 @@ pub fn make_normalized_projection<'tcx>( } helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, substs)?) } + +/// Check if given type has inner mutability such as [`std::cell::Cell`] or [`std::cell::RefCell`] +/// etc. +pub fn is_interior_mut_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + match *ty.kind() { + ty::Ref(_, inner_ty, mutbl) => mutbl == Mutability::Mut || is_interior_mut_ty(cx, inner_ty), + ty::Slice(inner_ty) => is_interior_mut_ty(cx, inner_ty), + ty::Array(inner_ty, size) => { + size.try_eval_target_usize(cx.tcx, cx.param_env) + .map_or(true, |u| u != 0) + && is_interior_mut_ty(cx, inner_ty) + }, + ty::Tuple(fields) => fields.iter().any(|ty| is_interior_mut_ty(cx, ty)), + ty::Adt(def, substs) => { + // Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to + // that of their type parameters. Note: we don't include `HashSet` and `HashMap` + // because they have no impl for `Hash` or `Ord`. + let def_id = def.did(); + let is_std_collection = [ + sym::Option, + sym::Result, + sym::LinkedList, + sym::Vec, + sym::VecDeque, + sym::BTreeMap, + sym::BTreeSet, + sym::Rc, + sym::Arc, + ] + .iter() + .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def_id)); + let is_box = Some(def_id) == cx.tcx.lang_items().owned_box(); + if is_std_collection || is_box { + // The type is mutable if any of its type parameters are + substs.types().any(|ty| is_interior_mut_ty(cx, ty)) + } else { + !ty.has_escaping_bound_vars() + && cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() + && !ty.is_freeze(cx.tcx, cx.param_env) + } + }, + _ => false, + } +} diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 86a93f64fb71..1dc19bac9844 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -599,9 +599,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( | ExprKind::Let(&Let { init: e, .. }) => { helper(typeck, false, e, f)?; }, - ExprKind::Block(&Block { expr: Some(e), .. }, _) - | ExprKind::Cast(e, _) - | ExprKind::Unary(_, e) => { + ExprKind::Block(&Block { expr: Some(e), .. }, _) | ExprKind::Cast(e, _) | ExprKind::Unary(_, e) => { helper(typeck, true, e, f)?; }, ExprKind::Call(callee, args) => { diff --git a/rust-toolchain b/rust-toolchain index d788c6359d7a..0b2458ea0070 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-03-10" +channel = "nightly-2023-03-24" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 9643c2c97070..3a5d478fa314 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -37,10 +37,10 @@ fn dogfood_clippy() { } assert!( - !failed_packages.is_empty(), + failed_packages.is_empty(), "Dogfood failed for packages `{}`", failed_packages.iter().format(", "), - ) + ); } #[test] diff --git a/tests/ui-internal/custom_ice_message.stderr b/tests/ui-internal/custom_ice_message.stderr index 7ed0ef0274fa..b4619e980f30 100644 --- a/tests/ui-internal/custom_ice_message.stderr +++ b/tests/ui-internal/custom_ice_message.stderr @@ -9,3 +9,4 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy note: Clippy version: foo +thread panicked while panicking. aborting. diff --git a/tests/ui-toml/ifs_same_cond/clippy.toml b/tests/ui-toml/ifs_same_cond/clippy.toml new file mode 100644 index 000000000000..90a36ecd9202 --- /dev/null +++ b/tests/ui-toml/ifs_same_cond/clippy.toml @@ -0,0 +1 @@ +ignore-interior-mutability = ["std::cell::Cell"] diff --git a/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs b/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs new file mode 100644 index 000000000000..d623ac7e0200 --- /dev/null +++ b/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs @@ -0,0 +1,18 @@ +#![warn(clippy::ifs_same_cond)] +#![allow(clippy::if_same_then_else, clippy::comparison_chain)] + +fn main() {} + +fn issue10272() { + use std::cell::Cell; + + // Because the `ignore-interior-mutability` configuration + // is set to ignore for `std::cell::Cell`, the following `get()` calls + // should trigger warning + let x = Cell::new(true); + if x.get() { + } else if !x.take() { + } else if x.get() { + } else { + } +} diff --git a/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr b/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr new file mode 100644 index 000000000000..2841f62bc94a --- /dev/null +++ b/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr @@ -0,0 +1,15 @@ +error: this `if` has the same condition as a previous `if` + --> $DIR/ifs_same_cond.rs:15:15 + | +LL | } else if x.get() { + | ^^^^^^^ + | +note: same as this + --> $DIR/ifs_same_cond.rs:13:8 + | +LL | if x.get() { + | ^^^^^^^ + = note: `-D clippy::ifs-same-cond` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/allow_attributes.fixed b/tests/ui/allow_attributes.fixed new file mode 100644 index 000000000000..b8dd0619e6d0 --- /dev/null +++ b/tests/ui/allow_attributes.fixed @@ -0,0 +1,25 @@ +// run-rustfix +#![allow(unused)] +#![warn(clippy::allow_attributes)] +#![feature(lint_reasons)] + +fn main() {} + +// Using clippy::needless_borrow just as a placeholder, it isn't relevant. + +// Should lint +#[expect(dead_code)] +struct T1; + +struct T2; // Should not lint +#[deny(clippy::needless_borrow)] // Should not lint +struct T3; +#[warn(clippy::needless_borrow)] // Should not lint +struct T4; +// `panic = "unwind"` should always be true +#[cfg_attr(panic = "unwind", expect(dead_code))] +struct CfgT; + +fn ignore_inner_attr() { + #![allow(unused)] // Should not lint +} diff --git a/tests/ui/allow_attributes.rs b/tests/ui/allow_attributes.rs new file mode 100644 index 000000000000..295f560906a7 --- /dev/null +++ b/tests/ui/allow_attributes.rs @@ -0,0 +1,25 @@ +// run-rustfix +#![allow(unused)] +#![warn(clippy::allow_attributes)] +#![feature(lint_reasons)] + +fn main() {} + +// Using clippy::needless_borrow just as a placeholder, it isn't relevant. + +// Should lint +#[allow(dead_code)] +struct T1; + +struct T2; // Should not lint +#[deny(clippy::needless_borrow)] // Should not lint +struct T3; +#[warn(clippy::needless_borrow)] // Should not lint +struct T4; +// `panic = "unwind"` should always be true +#[cfg_attr(panic = "unwind", allow(dead_code))] +struct CfgT; + +fn ignore_inner_attr() { + #![allow(unused)] // Should not lint +} diff --git a/tests/ui/allow_attributes.stderr b/tests/ui/allow_attributes.stderr new file mode 100644 index 000000000000..681837e9ed77 --- /dev/null +++ b/tests/ui/allow_attributes.stderr @@ -0,0 +1,16 @@ +error: #[allow] attribute found + --> $DIR/allow_attributes.rs:11:3 + | +LL | #[allow(dead_code)] + | ^^^^^ help: replace it with: `expect` + | + = note: `-D clippy::allow-attributes` implied by `-D warnings` + +error: #[allow] attribute found + --> $DIR/allow_attributes.rs:20:30 + | +LL | #[cfg_attr(panic = "unwind", allow(dead_code))] + | ^^^^^ help: replace it with: `expect` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/almost_complete_range.fixed b/tests/ui/almost_complete_range.fixed index 6046addf7196..a4bf7fe18d5f 100644 --- a/tests/ui/almost_complete_range.fixed +++ b/tests/ui/almost_complete_range.fixed @@ -1,6 +1,6 @@ // run-rustfix // edition:2018 -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![feature(exclusive_range_pattern)] #![feature(stmt_expr_attributes)] @@ -9,33 +9,10 @@ #![allow(clippy::needless_parens_on_range_literals)] #![allow(clippy::double_parens)] -#[macro_use] -extern crate macro_rules; - -macro_rules! a { - () => { - 'a' - }; -} -macro_rules! A { - () => { - 'A' - }; -} -macro_rules! zero { - () => { - '0' - }; -} - -macro_rules! b { - () => { - let _ = 'a'..='z'; - let _ = 'A'..='Z'; - let _ = '0'..='9'; - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { #[rustfmt::skip] { @@ -56,9 +33,9 @@ fn main() { let _ = b'B'..b'Z'; let _ = b'1'..b'9'; - let _ = a!()..='z'; - let _ = A!()..='Z'; - let _ = zero!()..='9'; + let _ = inline!('a')..='z'; + let _ = inline!('A')..='Z'; + let _ = inline!('0')..='9'; let _ = match 0u8 { b'a'..=b'z' if true => 1, @@ -80,8 +57,16 @@ fn main() { _ => 7, }; - almost_complete_range!(); - b!(); + external!( + let _ = 'a'..'z'; + let _ = 'A'..'Z'; + let _ = '0'..'9'; + ); + inline!( + let _ = 'a'..='z'; + let _ = 'A'..='Z'; + let _ = '0'..='9'; + ); } #[clippy::msrv = "1.25"] diff --git a/tests/ui/almost_complete_range.rs b/tests/ui/almost_complete_range.rs index ae7e07ab872b..8237c3a13611 100644 --- a/tests/ui/almost_complete_range.rs +++ b/tests/ui/almost_complete_range.rs @@ -1,6 +1,6 @@ // run-rustfix // edition:2018 -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![feature(exclusive_range_pattern)] #![feature(stmt_expr_attributes)] @@ -9,33 +9,10 @@ #![allow(clippy::needless_parens_on_range_literals)] #![allow(clippy::double_parens)] -#[macro_use] -extern crate macro_rules; - -macro_rules! a { - () => { - 'a' - }; -} -macro_rules! A { - () => { - 'A' - }; -} -macro_rules! zero { - () => { - '0' - }; -} - -macro_rules! b { - () => { - let _ = 'a'..'z'; - let _ = 'A'..'Z'; - let _ = '0'..'9'; - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { #[rustfmt::skip] { @@ -56,9 +33,9 @@ fn main() { let _ = b'B'..b'Z'; let _ = b'1'..b'9'; - let _ = a!()..'z'; - let _ = A!()..'Z'; - let _ = zero!()..'9'; + let _ = inline!('a')..'z'; + let _ = inline!('A')..'Z'; + let _ = inline!('0')..'9'; let _ = match 0u8 { b'a'..b'z' if true => 1, @@ -80,8 +57,16 @@ fn main() { _ => 7, }; - almost_complete_range!(); - b!(); + external!( + let _ = 'a'..'z'; + let _ = 'A'..'Z'; + let _ = '0'..'9'; + ); + inline!( + let _ = 'a'..'z'; + let _ = 'A'..'Z'; + let _ = '0'..'9'; + ); } #[clippy::msrv = "1.25"] diff --git a/tests/ui/almost_complete_range.stderr b/tests/ui/almost_complete_range.stderr index a7a532878502..34521c13ab3e 100644 --- a/tests/ui/almost_complete_range.stderr +++ b/tests/ui/almost_complete_range.stderr @@ -1,5 +1,5 @@ error: almost complete ascii range - --> $DIR/almost_complete_range.rs:42:17 + --> $DIR/almost_complete_range.rs:19:17 | LL | let _ = ('a') ..'z'; | ^^^^^^--^^^ @@ -9,7 +9,7 @@ LL | let _ = ('a') ..'z'; = note: `-D clippy::almost-complete-range` implied by `-D warnings` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:43:17 + --> $DIR/almost_complete_range.rs:20:17 | LL | let _ = 'A' .. ('Z'); | ^^^^--^^^^^^ @@ -17,7 +17,7 @@ LL | let _ = 'A' .. ('Z'); | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:44:17 + --> $DIR/almost_complete_range.rs:21:17 | LL | let _ = ((('0'))) .. ('9'); | ^^^^^^^^^^--^^^^^^ @@ -25,7 +25,7 @@ LL | let _ = ((('0'))) .. ('9'); | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:51:13 + --> $DIR/almost_complete_range.rs:28:13 | LL | let _ = (b'a')..(b'z'); | ^^^^^^--^^^^^^ @@ -33,7 +33,7 @@ LL | let _ = (b'a')..(b'z'); | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:52:13 + --> $DIR/almost_complete_range.rs:29:13 | LL | let _ = b'A'..b'Z'; | ^^^^--^^^^ @@ -41,7 +41,7 @@ LL | let _ = b'A'..b'Z'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:53:13 + --> $DIR/almost_complete_range.rs:30:13 | LL | let _ = b'0'..b'9'; | ^^^^--^^^^ @@ -49,31 +49,31 @@ LL | let _ = b'0'..b'9'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:59:13 + --> $DIR/almost_complete_range.rs:36:13 | -LL | let _ = a!()..'z'; - | ^^^^--^^^ - | | - | help: use an inclusive range: `..=` +LL | let _ = inline!('a')..'z'; + | ^^^^^^^^^^^^--^^^ + | | + | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:60:13 + --> $DIR/almost_complete_range.rs:37:13 | -LL | let _ = A!()..'Z'; - | ^^^^--^^^ - | | - | help: use an inclusive range: `..=` +LL | let _ = inline!('A')..'Z'; + | ^^^^^^^^^^^^--^^^ + | | + | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:61:13 + --> $DIR/almost_complete_range.rs:38:13 | -LL | let _ = zero!()..'9'; - | ^^^^^^^--^^^ - | | - | help: use an inclusive range: `..=` +LL | let _ = inline!('0')..'9'; + | ^^^^^^^^^^^^--^^^ + | | + | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:64:9 + --> $DIR/almost_complete_range.rs:41:9 | LL | b'a'..b'z' if true => 1, | ^^^^--^^^^ @@ -81,7 +81,7 @@ LL | b'a'..b'z' if true => 1, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:65:9 + --> $DIR/almost_complete_range.rs:42:9 | LL | b'A'..b'Z' if true => 2, | ^^^^--^^^^ @@ -89,7 +89,7 @@ LL | b'A'..b'Z' if true => 2, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:66:9 + --> $DIR/almost_complete_range.rs:43:9 | LL | b'0'..b'9' if true => 3, | ^^^^--^^^^ @@ -97,7 +97,7 @@ LL | b'0'..b'9' if true => 3, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:74:9 + --> $DIR/almost_complete_range.rs:51:9 | LL | 'a'..'z' if true => 1, | ^^^--^^^ @@ -105,7 +105,7 @@ LL | 'a'..'z' if true => 1, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:75:9 + --> $DIR/almost_complete_range.rs:52:9 | LL | 'A'..'Z' if true => 2, | ^^^--^^^ @@ -113,7 +113,7 @@ LL | 'A'..'Z' if true => 2, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:76:9 + --> $DIR/almost_complete_range.rs:53:9 | LL | '0'..'9' if true => 3, | ^^^--^^^ @@ -121,46 +121,37 @@ LL | '0'..'9' if true => 3, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:33:17 + --> $DIR/almost_complete_range.rs:66:17 | LL | let _ = 'a'..'z'; | ^^^--^^^ | | | help: use an inclusive range: `..=` -... -LL | b!(); - | ---- in this macro invocation | - = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: almost complete ascii range - --> $DIR/almost_complete_range.rs:34:17 + --> $DIR/almost_complete_range.rs:67:17 | LL | let _ = 'A'..'Z'; | ^^^--^^^ | | | help: use an inclusive range: `..=` -... -LL | b!(); - | ---- in this macro invocation | - = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: almost complete ascii range - --> $DIR/almost_complete_range.rs:35:17 + --> $DIR/almost_complete_range.rs:68:17 | LL | let _ = '0'..'9'; | ^^^--^^^ | | | help: use an inclusive range: `..=` -... -LL | b!(); - | ---- in this macro invocation | - = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: almost complete ascii range - --> $DIR/almost_complete_range.rs:90:9 + --> $DIR/almost_complete_range.rs:75:9 | LL | 'a'..'z' => 1, | ^^^--^^^ @@ -168,7 +159,7 @@ LL | 'a'..'z' => 1, | help: use an inclusive range: `...` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:91:9 + --> $DIR/almost_complete_range.rs:76:9 | LL | 'A'..'Z' => 2, | ^^^--^^^ @@ -176,7 +167,7 @@ LL | 'A'..'Z' => 2, | help: use an inclusive range: `...` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:92:9 + --> $DIR/almost_complete_range.rs:77:9 | LL | '0'..'9' => 3, | ^^^--^^^ @@ -184,7 +175,7 @@ LL | '0'..'9' => 3, | help: use an inclusive range: `...` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:99:13 + --> $DIR/almost_complete_range.rs:84:13 | LL | let _ = 'a'..'z'; | ^^^--^^^ @@ -192,7 +183,7 @@ LL | let _ = 'a'..'z'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:100:13 + --> $DIR/almost_complete_range.rs:85:13 | LL | let _ = 'A'..'Z'; | ^^^--^^^ @@ -200,7 +191,7 @@ LL | let _ = 'A'..'Z'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:101:13 + --> $DIR/almost_complete_range.rs:86:13 | LL | let _ = '0'..'9'; | ^^^--^^^ @@ -208,7 +199,7 @@ LL | let _ = '0'..'9'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:103:9 + --> $DIR/almost_complete_range.rs:88:9 | LL | 'a'..'z' => 1, | ^^^--^^^ @@ -216,7 +207,7 @@ LL | 'a'..'z' => 1, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:104:9 + --> $DIR/almost_complete_range.rs:89:9 | LL | 'A'..'Z' => 1, | ^^^--^^^ @@ -224,7 +215,7 @@ LL | 'A'..'Z' => 1, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:105:9 + --> $DIR/almost_complete_range.rs:90:9 | LL | '0'..'9' => 3, | ^^^--^^^ diff --git a/tests/ui/as_conversions.rs b/tests/ui/as_conversions.rs index ba4394defbf2..c50d4088b5eb 100644 --- a/tests/ui/as_conversions.rs +++ b/tests/ui/as_conversions.rs @@ -1,20 +1,15 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::as_conversions)] #![allow(clippy::borrow_as_ptr)] -#[macro_use] -extern crate macro_rules; - -fn with_external_macro() { - as_conv_with_arg!(0u32 as u64); - as_conv!(); -} +extern crate proc_macros; +use proc_macros::external; fn main() { let i = 0u32 as u64; let j = &i as *const u64 as *mut u64; - with_external_macro(); + external!(0u32 as u64); } diff --git a/tests/ui/as_conversions.stderr b/tests/ui/as_conversions.stderr index f5d59e1e5d83..54037a649978 100644 --- a/tests/ui/as_conversions.stderr +++ b/tests/ui/as_conversions.stderr @@ -1,5 +1,5 @@ error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:15:13 + --> $DIR/as_conversions.rs:10:13 | LL | let i = 0u32 as u64; | ^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let i = 0u32 as u64; = note: `-D clippy::as-conversions` implied by `-D warnings` error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:17:13 + --> $DIR/as_conversions.rs:12:13 | LL | let j = &i as *const u64 as *mut u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let j = &i as *const u64 as *mut u64; = help: consider using a safe wrapper for this conversion error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:17:13 + --> $DIR/as_conversions.rs:12:13 | LL | let j = &i as *const u64 as *mut u64; | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/auxiliary/doc_unsafe_macros.rs b/tests/ui/auxiliary/doc_unsafe_macros.rs deleted file mode 100644 index 3d917e3dc75e..000000000000 --- a/tests/ui/auxiliary/doc_unsafe_macros.rs +++ /dev/null @@ -1,16 +0,0 @@ -#[macro_export] -macro_rules! undocd_unsafe { - () => { - pub unsafe fn oy_vey() { - unimplemented!(); - } - }; -} -#[macro_export] -macro_rules! undocd_safe { - () => { - pub fn vey_oy() { - unimplemented!(); - } - }; -} diff --git a/tests/ui/auxiliary/implicit_hasher_macros.rs b/tests/ui/auxiliary/implicit_hasher_macros.rs deleted file mode 100644 index 1eb77c531835..000000000000 --- a/tests/ui/auxiliary/implicit_hasher_macros.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[macro_export] -macro_rules! implicit_hasher_fn { - () => { - pub fn f(input: &HashMap) {} - }; -} diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs index a13af5652038..a9bb61451dca 100644 --- a/tests/ui/auxiliary/macro_rules.rs +++ b/tests/ui/auxiliary/macro_rules.rs @@ -2,21 +2,6 @@ //! Used to test that certain lints don't trigger in imported external macros -#[macro_export] -macro_rules! foofoo { - () => { - loop {} - }; -} - -#[macro_export] -macro_rules! must_use_unit { - () => { - #[must_use] - fn foo() {} - }; -} - #[macro_export] macro_rules! try_err { () => { @@ -36,84 +21,6 @@ macro_rules! string_add { }; } -#[macro_export] -macro_rules! take_external { - ($s:expr) => { - std::mem::replace($s, Default::default()) - }; -} - -#[macro_export] -macro_rules! option_env_unwrap_external { - ($env: expr) => { - option_env!($env).unwrap() - }; - ($env: expr, $message: expr) => { - option_env!($env).expect($message) - }; -} - -#[macro_export] -macro_rules! ref_arg_binding { - () => { - let ref _y = 42; - }; -} - -#[macro_export] -macro_rules! ref_arg_function { - () => { - fn fun_example(ref _x: usize) {} - }; -} - -#[macro_export] -macro_rules! as_conv_with_arg { - (0u32 as u64) => { - () - }; -} - -#[macro_export] -macro_rules! as_conv { - () => { - 0u32 as u64 - }; -} - -#[macro_export] -macro_rules! large_enum_variant { - () => { - enum LargeEnumInMacro { - A(i32), - B([i32; 8000]), - } - }; -} - -#[macro_export] -macro_rules! field_reassign_with_default { - () => { - #[derive(Default)] - struct A { - pub i: i32, - pub j: i64, - } - fn lint() { - let mut a: A = Default::default(); - a.i = 42; - a; - } - }; -} - -#[macro_export] -macro_rules! default_numeric_fallback { - () => { - let x = 22; - }; -} - #[macro_export] macro_rules! mut_mut { () => { @@ -122,49 +29,11 @@ macro_rules! mut_mut { } #[macro_export] -macro_rules! ptr_as_ptr_cast { - ($ptr: ident) => { - $ptr as *const i32 - }; -} - -#[macro_export] -macro_rules! manual_rem_euclid { +macro_rules! issue_10421 { () => { - let value: i32 = 5; - let _: i32 = ((value % 4) + 4) % 4; - }; -} - -#[macro_export] -macro_rules! equatable_if_let { - ($a:ident) => {{ if let 2 = $a {} }}; -} - -#[macro_export] -macro_rules! almost_complete_range { - () => { - let _ = 'a'..'z'; - let _ = 'A'..'Z'; - let _ = '0'..'9'; - }; -} - -#[macro_export] -macro_rules! unsafe_macro { - () => { - unsafe { - *core::ptr::null::<()>(); - *core::ptr::null::<()>(); - } - }; -} - -#[macro_export] -macro_rules! needless_lifetime { - () => { - fn needless_lifetime<'a>(x: &'a u8) -> &'a u8 { - unimplemented!() - } + let mut a = 1; + let mut b = 2; + a = b; + b = a; }; } diff --git a/tests/ui/auxiliary/macro_use_helper.rs b/tests/ui/auxiliary/macro_use_helper.rs index ecb55d8cb48d..7ed8a28dbd93 100644 --- a/tests/ui/auxiliary/macro_use_helper.rs +++ b/tests/ui/auxiliary/macro_use_helper.rs @@ -13,7 +13,7 @@ pub mod inner { // RE-EXPORT // this will stick in `inner` module - pub use macro_rules::foofoo; + pub use macro_rules::mut_mut; pub use macro_rules::try_err; pub mod nested { diff --git a/tests/ui/auxiliary/proc_macro_with_span.rs b/tests/ui/auxiliary/proc_macro_with_span.rs deleted file mode 100644 index 8ea631f2bbd4..000000000000 --- a/tests/ui/auxiliary/proc_macro_with_span.rs +++ /dev/null @@ -1,32 +0,0 @@ -// compile-flags: --emit=link -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::{token_stream::IntoIter, Group, Span, TokenStream, TokenTree}; - -#[proc_macro] -pub fn with_span(input: TokenStream) -> TokenStream { - let mut iter = input.into_iter(); - let span = iter.next().unwrap().span(); - let mut res = TokenStream::new(); - write_with_span(span, iter, &mut res); - res -} - -fn write_with_span(s: Span, input: IntoIter, out: &mut TokenStream) { - for mut tt in input { - if let TokenTree::Group(g) = tt { - let mut stream = TokenStream::new(); - write_with_span(s, g.stream().into_iter(), &mut stream); - let mut group = Group::new(g.delimiter(), stream); - group.set_span(s); - out.extend([TokenTree::Group(group)]); - } else { - tt.set_span(s); - out.extend([tt]); - } - } -} diff --git a/tests/ui/auxiliary/proc_macros.rs b/tests/ui/auxiliary/proc_macros.rs new file mode 100644 index 000000000000..325be83a0d73 --- /dev/null +++ b/tests/ui/auxiliary/proc_macros.rs @@ -0,0 +1,474 @@ +// compile-flags: --emit=link +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(let_chains)] +#![feature(proc_macro_span)] +#![allow(dead_code)] + +extern crate proc_macro; + +use core::mem; +use proc_macro::{ + token_stream::IntoIter, + Delimiter::{self, Brace, Parenthesis}, + Group, Ident, Literal, Punct, + Spacing::{self, Alone, Joint}, + Span, TokenStream, TokenTree as TT, +}; + +type Result = core::result::Result; + +/// Make a `compile_error!` pointing to the given span. +fn make_error(msg: &str, span: Span) -> TokenStream { + TokenStream::from_iter([ + TT::Ident(Ident::new("compile_error", span)), + TT::Punct(punct_with_span('!', Alone, span)), + TT::Group({ + let mut msg = Literal::string(msg); + msg.set_span(span); + group_with_span(Parenthesis, TokenStream::from_iter([TT::Literal(msg)]), span) + }), + ]) +} + +fn expect_tt(tt: Option, f: impl FnOnce(TT) -> Option, expected: &str, span: Span) -> Result { + match tt { + None => Err(make_error( + &format!("unexpected end of input, expected {expected}"), + span, + )), + Some(tt) => { + let span = tt.span(); + match f(tt) { + Some(x) => Ok(x), + None => Err(make_error(&format!("unexpected token, expected {expected}"), span)), + } + }, + } +} + +fn punct_with_span(c: char, spacing: Spacing, span: Span) -> Punct { + let mut p = Punct::new(c, spacing); + p.set_span(span); + p +} + +fn group_with_span(delimiter: Delimiter, stream: TokenStream, span: Span) -> Group { + let mut g = Group::new(delimiter, stream); + g.set_span(span); + g +} + +/// Token used to escape the following token from the macro's span rules. +const ESCAPE_CHAR: char = '$'; + +/// Takes a single token followed by a sequence tokens. Returns the sequence of tokens with their +/// span set to that of the first token. Tokens may be escaped with either `#ident` or `#(tokens)`. +#[proc_macro] +pub fn with_span(input: TokenStream) -> TokenStream { + let mut iter = input.into_iter(); + let span = iter.next().unwrap().span(); + let mut res = TokenStream::new(); + if let Err(e) = write_with_span(span, iter, &mut res) { + e + } else { + res + } +} + +/// Takes a sequence of tokens and return the tokens with the span set such that they appear to be +/// from an external macro. Tokens may be escaped with either `#ident` or `#(tokens)`. +#[proc_macro] +pub fn external(input: TokenStream) -> TokenStream { + let mut res = TokenStream::new(); + if let Err(e) = write_with_span(Span::mixed_site(), input.into_iter(), &mut res) { + e + } else { + res + } +} + +/// Copies all the tokens, replacing all their spans with the given span. Tokens can be escaped +/// either by `#ident` or `#(tokens)`. +fn write_with_span(s: Span, mut input: IntoIter, out: &mut TokenStream) -> Result<()> { + while let Some(tt) = input.next() { + match tt { + TT::Punct(p) if p.as_char() == ESCAPE_CHAR => { + expect_tt( + input.next(), + |tt| match tt { + tt @ (TT::Ident(_) | TT::Literal(_)) => { + out.extend([tt]); + Some(()) + }, + TT::Punct(mut p) if p.as_char() == ESCAPE_CHAR => { + p.set_span(s); + out.extend([TT::Punct(p)]); + Some(()) + }, + TT::Group(g) if g.delimiter() == Parenthesis => { + out.extend([TT::Group(group_with_span(Delimiter::None, g.stream(), g.span()))]); + Some(()) + }, + _ => None, + }, + "an ident, a literal, or parenthesized tokens", + p.span(), + )?; + }, + TT::Group(g) => { + let mut stream = TokenStream::new(); + write_with_span(s, g.stream().into_iter(), &mut stream)?; + out.extend([TT::Group(group_with_span(g.delimiter(), stream, s))]); + }, + mut tt => { + tt.set_span(s); + out.extend([tt]); + }, + } + } + Ok(()) +} + +/// Within the item this attribute is attached to, an `inline!` macro is available which expands the +/// contained tokens as though they came from a macro expansion. +/// +/// Within the `inline!` macro, any token preceded by `$` is passed as though it were an argument +/// with an automatically chosen fragment specifier. `$ident` will be passed as `ident`, `$1` or +/// `$"literal"` will be passed as `literal`, `$'lt` will be passed as `lifetime`, and `$(...)` will +/// pass the contained tokens as a `tt` sequence (the wrapping parenthesis are removed). If another +/// specifier is required it can be specified within parenthesis like `$(@expr ...)`. This will +/// expand the remaining tokens as a single argument. +/// +/// Multiple `inline!` macros may be nested within each other. This will expand as nested macro +/// calls. However, any arguments will be passed as though they came from the outermost context. +#[proc_macro_attribute] +pub fn inline_macros(args: TokenStream, input: TokenStream) -> TokenStream { + let mut args = args.into_iter(); + let mac_name = match args.next() { + Some(TT::Ident(name)) => Some(name), + Some(tt) => { + return make_error( + "unexpected argument, expected either an ident or no arguments", + tt.span(), + ); + }, + None => None, + }; + if let Some(tt) = args.next() { + return make_error( + "unexpected argument, expected either an ident or no arguments", + tt.span(), + ); + }; + + let mac_name = if let Some(mac_name) = mac_name { + Ident::new(&format!("__inline_mac_{mac_name}"), Span::call_site()) + } else { + let mut input = match LookaheadIter::new(input.clone().into_iter()) { + Some(x) => x, + None => return input, + }; + loop { + match input.next() { + None => break Ident::new("__inline_mac", Span::call_site()), + Some(TT::Ident(kind)) => match &*kind.to_string() { + "impl" => break Ident::new("__inline_mac_impl", Span::call_site()), + kind @ ("struct" | "enum" | "union" | "fn" | "mod" | "trait" | "type" | "const" | "static") => { + if let TT::Ident(name) = &input.tt { + break Ident::new(&format!("__inline_mac_{kind}_{name}"), Span::call_site()); + } else { + break Ident::new(&format!("__inline_mac_{kind}"), Span::call_site()); + } + }, + _ => {}, + }, + _ => {}, + } + } + }; + + let mut expander = Expander::default(); + let mut mac = MacWriter::new(mac_name); + if let Err(e) = expander.expand(input.into_iter(), &mut mac) { + return e; + } + let mut out = TokenStream::new(); + mac.finish(&mut out); + out.extend(expander.expn); + out +} + +/// Wraps a `TokenStream` iterator with a single token lookahead. +struct LookaheadIter { + tt: TT, + iter: IntoIter, +} +impl LookaheadIter { + fn new(mut iter: IntoIter) -> Option { + iter.next().map(|tt| Self { tt, iter }) + } + + /// Get's the lookahead token, replacing it with the next token in the stream. + /// Note: If there isn't a next token, this will not return the lookahead token. + fn next(&mut self) -> Option { + self.iter.next().map(|tt| mem::replace(&mut self.tt, tt)) + } +} + +/// Builds the macro used to implement all the `inline!` macro calls. +struct MacWriter { + name: Ident, + macros: TokenStream, + next_idx: usize, +} +impl MacWriter { + fn new(name: Ident) -> Self { + Self { + name, + macros: TokenStream::new(), + next_idx: 0, + } + } + + /// Inserts a new `inline!` call. + fn insert(&mut self, name_span: Span, bang_span: Span, body: Group, expander: &mut Expander) -> Result<()> { + let idx = self.next_idx; + self.next_idx += 1; + + let mut inner = Expander::for_arm(idx); + inner.expand(body.stream().into_iter(), self)?; + let new_arm = inner.arm.unwrap(); + + self.macros.extend([ + TT::Group(Group::new(Parenthesis, new_arm.args_def)), + TT::Punct(Punct::new('=', Joint)), + TT::Punct(Punct::new('>', Alone)), + TT::Group(Group::new(Parenthesis, inner.expn)), + TT::Punct(Punct::new(';', Alone)), + ]); + + expander.expn.extend([ + TT::Ident({ + let mut name = self.name.clone(); + name.set_span(name_span); + name + }), + TT::Punct(punct_with_span('!', Alone, bang_span)), + ]); + let mut call_body = TokenStream::from_iter([TT::Literal(Literal::usize_unsuffixed(idx))]); + if let Some(arm) = expander.arm.as_mut() { + if !new_arm.args.is_empty() { + arm.add_sub_args(new_arm.args, &mut call_body); + } + } else { + call_body.extend(new_arm.args); + } + let mut g = Group::new(body.delimiter(), call_body); + g.set_span(body.span()); + expander.expn.extend([TT::Group(g)]); + Ok(()) + } + + /// Creates the macro definition. + fn finish(self, out: &mut TokenStream) { + if self.next_idx != 0 { + out.extend([ + TT::Ident(Ident::new("macro_rules", Span::call_site())), + TT::Punct(Punct::new('!', Alone)), + TT::Ident(self.name), + TT::Group(Group::new(Brace, self.macros)), + ]) + } + } +} + +struct MacroArm { + args_def: TokenStream, + args: Vec, +} +impl MacroArm { + fn add_single_arg_def(&mut self, kind: &str, dollar_span: Span, arg_span: Span, out: &mut TokenStream) { + let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site()); + self.args_def.extend([ + TT::Punct(Punct::new('$', Alone)), + TT::Ident(name.clone()), + TT::Punct(Punct::new(':', Alone)), + TT::Ident(Ident::new(kind, Span::call_site())), + ]); + name.set_span(arg_span); + out.extend([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]); + } + + fn add_parenthesized_arg_def(&mut self, kind: Ident, dollar_span: Span, arg_span: Span, out: &mut TokenStream) { + let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site()); + self.args_def.extend([TT::Group(Group::new( + Parenthesis, + TokenStream::from_iter([ + TT::Punct(Punct::new('$', Alone)), + TT::Ident(name.clone()), + TT::Punct(Punct::new(':', Alone)), + TT::Ident(kind), + ]), + ))]); + name.set_span(arg_span); + out.extend([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]); + } + + fn add_multi_arg_def(&mut self, dollar_span: Span, arg_span: Span, out: &mut TokenStream) { + let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site()); + self.args_def.extend([TT::Group(Group::new( + Parenthesis, + TokenStream::from_iter([ + TT::Punct(Punct::new('$', Alone)), + TT::Group(Group::new( + Parenthesis, + TokenStream::from_iter([ + TT::Punct(Punct::new('$', Alone)), + TT::Ident(name.clone()), + TT::Punct(Punct::new(':', Alone)), + TT::Ident(Ident::new("tt", Span::call_site())), + ]), + )), + TT::Punct(Punct::new('*', Alone)), + ]), + ))]); + name.set_span(arg_span); + out.extend([ + TT::Punct(punct_with_span('$', Alone, dollar_span)), + TT::Group(group_with_span( + Parenthesis, + TokenStream::from_iter([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]), + dollar_span, + )), + TT::Punct(punct_with_span('*', Alone, dollar_span)), + ]); + } + + fn add_arg(&mut self, dollar_span: Span, tt: TT, input: &mut IntoIter, out: &mut TokenStream) -> Result<()> { + match tt { + TT::Punct(p) if p.as_char() == ESCAPE_CHAR => out.extend([TT::Punct(p)]), + TT::Punct(p) if p.as_char() == '\'' && p.spacing() == Joint => { + let lt_name = expect_tt( + input.next(), + |tt| match tt { + TT::Ident(x) => Some(x), + _ => None, + }, + "lifetime name", + p.span(), + )?; + let arg_span = p.span().join(lt_name.span()).unwrap_or(p.span()); + self.add_single_arg_def("lifetime", dollar_span, arg_span, out); + self.args.extend([TT::Punct(p), TT::Ident(lt_name)]); + }, + TT::Ident(x) => { + self.add_single_arg_def("ident", dollar_span, x.span(), out); + self.args.push(TT::Ident(x)); + }, + TT::Literal(x) => { + self.add_single_arg_def("literal", dollar_span, x.span(), out); + self.args.push(TT::Literal(x)); + }, + TT::Group(g) if g.delimiter() == Parenthesis => { + let mut inner = g.stream().into_iter(); + if let Some(TT::Punct(p)) = inner.next() + && p.as_char() == '@' + { + let kind = expect_tt( + inner.next(), + |tt| match tt { + TT::Ident(kind) => Some(kind), + _ => None, + }, + "a macro fragment specifier", + p.span(), + )?; + self.add_parenthesized_arg_def(kind, dollar_span, g.span(), out); + self.args.push(TT::Group(group_with_span(Parenthesis, inner.collect(), g.span()))) + } else { + self.add_multi_arg_def(dollar_span, g.span(), out); + self.args.push(TT::Group(g)); + } + }, + tt => return Err(make_error("unsupported escape", tt.span())), + }; + Ok(()) + } + + fn add_sub_args(&mut self, args: Vec, out: &mut TokenStream) { + self.add_multi_arg_def(Span::call_site(), Span::call_site(), out); + self.args + .extend([TT::Group(Group::new(Parenthesis, TokenStream::from_iter(args)))]); + } +} + +#[derive(Default)] +struct Expander { + arm: Option, + expn: TokenStream, +} +impl Expander { + fn for_arm(idx: usize) -> Self { + Self { + arm: Some(MacroArm { + args_def: TokenStream::from_iter([TT::Literal(Literal::usize_unsuffixed(idx))]), + args: Vec::new(), + }), + expn: TokenStream::new(), + } + } + + fn write_tt(&mut self, tt: TT, mac: &mut MacWriter) -> Result<()> { + match tt { + TT::Group(g) => { + let outer = mem::take(&mut self.expn); + self.expand(g.stream().into_iter(), mac)?; + let inner = mem::replace(&mut self.expn, outer); + self.expn + .extend([TT::Group(group_with_span(g.delimiter(), inner, g.span()))]); + }, + tt => self.expn.extend([tt]), + } + Ok(()) + } + + fn expand(&mut self, input: IntoIter, mac: &mut MacWriter) -> Result<()> { + let Some(mut input) = LookaheadIter::new(input) else { + return Ok(()); + }; + while let Some(tt) = input.next() { + if let TT::Punct(p) = &tt + && p.as_char() == ESCAPE_CHAR + && let Some(arm) = self.arm.as_mut() + { + arm.add_arg(p.span(), mem::replace(&mut input.tt, tt), &mut input.iter, &mut self.expn)?; + if input.next().is_none() { + return Ok(()); + } + } else if let TT::Punct(p) = &input.tt + && p.as_char() == '!' + && let TT::Ident(name) = &tt + && name.to_string() == "inline" + { + let g = expect_tt( + input.iter.next(), + |tt| match tt { + TT::Group(g) => Some(g), + _ => None, + }, + "macro arguments", + p.span(), + )?; + mac.insert(name.span(), p.span(), g, self)?; + if input.next().is_none() { + return Ok(()); + } + } else { + self.write_tt(tt, mac)?; + } + } + self.write_tt(input.tt, mac) + } +} diff --git a/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs b/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs index f13733af3d0d..b03c21262c3b 100644 --- a/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs +++ b/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs @@ -1,5 +1,5 @@ // this file solely exists to test constants defined in foreign crates. -// As the most common case is the `http` crate, it replicates `http::HeadewrName`'s structure. +// As the most common case is the `http` crate, it replicates `http::HeaderName`'s structure. #![allow(clippy::declare_interior_mutable_const)] #![allow(unused_tuple_struct_fields)] diff --git a/tests/ui/crashes/ice-10148.rs b/tests/ui/crashes/ice-10148.rs index af33b10c6938..1ab3570c907c 100644 --- a/tests/ui/crashes/ice-10148.rs +++ b/tests/ui/crashes/ice-10148.rs @@ -1,8 +1,8 @@ -// aux-build:../../auxiliary/proc_macro_with_span.rs +// aux-build:../../auxiliary/proc_macros.rs -extern crate proc_macro_with_span; +extern crate proc_macros; -use proc_macro_with_span::with_span; +use proc_macros::with_span; fn main() { println!(with_span!(""something "")); diff --git a/tests/ui/default_numeric_fallback_f64.fixed b/tests/ui/default_numeric_fallback_f64.fixed index a9e5fd159afc..42c15d6a70b8 100644 --- a/tests/ui/default_numeric_fallback_f64.fixed +++ b/tests/ui/default_numeric_fallback_f64.fixed @@ -1,5 +1,5 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::default_numeric_fallback)] #![allow( @@ -13,8 +13,8 @@ clippy::let_with_type_underscore )] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; mod basic_expr { fn test() { @@ -167,20 +167,17 @@ mod method_calls { } mod in_macro { - macro_rules! internal_macro { - () => { - let x = 22.0_f64; - }; - } + use super::*; // Should lint in internal macro. + #[inline_macros] fn internal() { - internal_macro!(); + inline!(let x = 22.0_f64;); } // Should NOT lint in external macro. fn external() { - default_numeric_fallback!(); + external!(let x = 22.;); } } diff --git a/tests/ui/default_numeric_fallback_f64.rs b/tests/ui/default_numeric_fallback_f64.rs index 085f8f452b2e..7da7ea254e98 100644 --- a/tests/ui/default_numeric_fallback_f64.rs +++ b/tests/ui/default_numeric_fallback_f64.rs @@ -1,5 +1,5 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::default_numeric_fallback)] #![allow( @@ -13,8 +13,8 @@ clippy::let_with_type_underscore )] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; mod basic_expr { fn test() { @@ -167,20 +167,17 @@ mod method_calls { } mod in_macro { - macro_rules! internal_macro { - () => { - let x = 22.; - }; - } + use super::*; // Should lint in internal macro. + #[inline_macros] fn internal() { - internal_macro!(); + inline!(let x = 22.;); } // Should NOT lint in external macro. fn external() { - default_numeric_fallback!(); + external!(let x = 22.;); } } diff --git a/tests/ui/default_numeric_fallback_f64.stderr b/tests/ui/default_numeric_fallback_f64.stderr index 44c6f1a9bea9..b949cd1d50b1 100644 --- a/tests/ui/default_numeric_fallback_f64.stderr +++ b/tests/ui/default_numeric_fallback_f64.stderr @@ -139,15 +139,12 @@ LL | s.generic_arg(1.); | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:172:21 + --> $DIR/default_numeric_fallback_f64.rs:175:25 | -LL | let x = 22.; - | ^^^ help: consider adding suffix: `22.0_f64` -... -LL | internal_macro!(); - | ----------------- in this macro invocation +LL | inline!(let x = 22.;); + | ^^^ help: consider adding suffix: `22.0_f64` | - = note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_internal` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 24 previous errors diff --git a/tests/ui/default_numeric_fallback_i32.fixed b/tests/ui/default_numeric_fallback_i32.fixed index 63ac4d5aeb6f..b7485b73dcdd 100644 --- a/tests/ui/default_numeric_fallback_i32.fixed +++ b/tests/ui/default_numeric_fallback_i32.fixed @@ -1,5 +1,5 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![feature(lint_reasons)] #![warn(clippy::default_numeric_fallback)] @@ -13,8 +13,8 @@ clippy::let_with_type_underscore )] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; mod basic_expr { fn test() { @@ -168,20 +168,17 @@ mod method_calls { } mod in_macro { - macro_rules! internal_macro { - () => { - let x = 22_i32; - }; - } + use super::*; // Should lint in internal macro. + #[inline_macros] fn internal() { - internal_macro!(); + inline!(let x = 22_i32;); } // Should NOT lint in external macro. fn external() { - default_numeric_fallback!(); + external!(let x = 22;); } } diff --git a/tests/ui/default_numeric_fallback_i32.rs b/tests/ui/default_numeric_fallback_i32.rs index 28e6eceb80e2..7307d31354eb 100644 --- a/tests/ui/default_numeric_fallback_i32.rs +++ b/tests/ui/default_numeric_fallback_i32.rs @@ -1,5 +1,5 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![feature(lint_reasons)] #![warn(clippy::default_numeric_fallback)] @@ -13,8 +13,8 @@ clippy::let_with_type_underscore )] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; mod basic_expr { fn test() { @@ -168,20 +168,17 @@ mod method_calls { } mod in_macro { - macro_rules! internal_macro { - () => { - let x = 22; - }; - } + use super::*; // Should lint in internal macro. + #[inline_macros] fn internal() { - internal_macro!(); + inline!(let x = 22;); } // Should NOT lint in external macro. fn external() { - default_numeric_fallback!(); + external!(let x = 22;); } } diff --git a/tests/ui/default_numeric_fallback_i32.stderr b/tests/ui/default_numeric_fallback_i32.stderr index dd91574d5b34..48cd28102ce4 100644 --- a/tests/ui/default_numeric_fallback_i32.stderr +++ b/tests/ui/default_numeric_fallback_i32.stderr @@ -151,15 +151,12 @@ LL | s.generic_arg(1); | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:173:21 + --> $DIR/default_numeric_fallback_i32.rs:176:25 | -LL | let x = 22; - | ^^ help: consider adding suffix: `22_i32` -... -LL | internal_macro!(); - | ----------------- in this macro invocation +LL | inline!(let x = 22;); + | ^^ help: consider adding suffix: `22_i32` | - = note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_internal` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 26 previous errors diff --git a/tests/ui/default_trait_access.fixed b/tests/ui/default_trait_access.fixed index 5640599d48ae..7842ef3ec40c 100644 --- a/tests/ui/default_trait_access.fixed +++ b/tests/ui/default_trait_access.fixed @@ -1,12 +1,12 @@ // run-rustfix -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![deny(clippy::default_trait_access)] #![allow(dead_code, unused_imports)] #![allow(clippy::uninlined_format_args)] -extern crate proc_macro_with_span; +extern crate proc_macros; -use proc_macro_with_span::with_span; +use proc_macros::with_span; use std::default; use std::default::Default as D2; use std::string; diff --git a/tests/ui/default_trait_access.rs b/tests/ui/default_trait_access.rs index 11d4bc5c5f02..cbb3e59c970e 100644 --- a/tests/ui/default_trait_access.rs +++ b/tests/ui/default_trait_access.rs @@ -1,12 +1,12 @@ // run-rustfix -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![deny(clippy::default_trait_access)] #![allow(dead_code, unused_imports)] #![allow(clippy::uninlined_format_args)] -extern crate proc_macro_with_span; +extern crate proc_macros; -use proc_macro_with_span::with_span; +use proc_macros::with_span; use std::default; use std::default::Default as D2; use std::string; diff --git a/tests/ui/deref_addrof.fixed b/tests/ui/deref_addrof.fixed index 2f489deb1ee1..ca5c03304c7f 100644 --- a/tests/ui/deref_addrof.fixed +++ b/tests/ui/deref_addrof.fixed @@ -1,7 +1,12 @@ // run-rustfix +// aux-build:proc_macros.rs + #![allow(clippy::return_self_not_must_use)] #![warn(clippy::deref_addrof)] +extern crate proc_macros; +use proc_macros::inline_macros; + fn get_number() -> usize { 10 } @@ -41,28 +46,15 @@ fn main() { let _ = unsafe { *core::ptr::addr_of!(a) }; } -#[rustfmt::skip] -macro_rules! m { - ($visitor: expr) => { - $visitor - }; -} - -#[rustfmt::skip] -macro_rules! m_mut { - ($visitor: expr) => { - $visitor - }; -} - #[derive(Copy, Clone)] pub struct S; +#[inline_macros] impl S { pub fn f(&self) -> &Self { - m!(self) + inline!($(@expr self)) } #[allow(unused_mut)] // mut will be unused, once the macro is fixed pub fn f_mut(mut self) -> Self { - m_mut!(self) + inline!($(@expr self)) } } diff --git a/tests/ui/deref_addrof.rs b/tests/ui/deref_addrof.rs index 49f360b9a7f9..3db5fafe9449 100644 --- a/tests/ui/deref_addrof.rs +++ b/tests/ui/deref_addrof.rs @@ -1,7 +1,12 @@ // run-rustfix +// aux-build:proc_macros.rs + #![allow(clippy::return_self_not_must_use)] #![warn(clippy::deref_addrof)] +extern crate proc_macros; +use proc_macros::inline_macros; + fn get_number() -> usize { 10 } @@ -41,28 +46,15 @@ fn main() { let _ = unsafe { *core::ptr::addr_of!(a) }; } -#[rustfmt::skip] -macro_rules! m { - ($visitor: expr) => { - *& $visitor - }; -} - -#[rustfmt::skip] -macro_rules! m_mut { - ($visitor: expr) => { - *& mut $visitor - }; -} - #[derive(Copy, Clone)] pub struct S; +#[inline_macros] impl S { pub fn f(&self) -> &Self { - m!(self) + inline!(*& $(@expr self)) } #[allow(unused_mut)] // mut will be unused, once the macro is fixed pub fn f_mut(mut self) -> Self { - m_mut!(self) + inline!(*&mut $(@expr self)) } } diff --git a/tests/ui/deref_addrof.stderr b/tests/ui/deref_addrof.stderr index 75371fcdb967..e0287522fc56 100644 --- a/tests/ui/deref_addrof.stderr +++ b/tests/ui/deref_addrof.stderr @@ -1,5 +1,5 @@ error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:19:13 + --> $DIR/deref_addrof.rs:24:13 | LL | let b = *&a; | ^^^ help: try this: `a` @@ -7,68 +7,62 @@ LL | let b = *&a; = note: `-D clippy::deref-addrof` implied by `-D warnings` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:21:13 + --> $DIR/deref_addrof.rs:26:13 | LL | let b = *&get_number(); | ^^^^^^^^^^^^^^ help: try this: `get_number()` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:26:13 + --> $DIR/deref_addrof.rs:31:13 | LL | let b = *&bytes[1..2][0]; | ^^^^^^^^^^^^^^^^ help: try this: `bytes[1..2][0]` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:30:13 + --> $DIR/deref_addrof.rs:35:13 | LL | let b = *&(a); | ^^^^^ help: try this: `(a)` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:32:13 + --> $DIR/deref_addrof.rs:37:13 | LL | let b = *(&a); | ^^^^^ help: try this: `a` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:35:13 + --> $DIR/deref_addrof.rs:40:13 | LL | let b = *((&a)); | ^^^^^^^ help: try this: `a` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:37:13 + --> $DIR/deref_addrof.rs:42:13 | LL | let b = *&&a; | ^^^^ help: try this: `&a` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:39:14 + --> $DIR/deref_addrof.rs:44:14 | LL | let b = **&aref; | ^^^^^^ help: try this: `aref` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:47:9 + --> $DIR/deref_addrof.rs:54:17 | -LL | *& $visitor - | ^^^^^^^^^^^ help: try this: `$visitor` -... -LL | m!(self) - | -------- in this macro invocation +LL | inline!(*& $(@expr self)) + | ^^^^^^^^^^^^^^^^ help: try this: `$(@expr self)` | - = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:54:9 + --> $DIR/deref_addrof.rs:58:17 | -LL | *& mut $visitor - | ^^^^^^^^^^^^^^^ help: try this: `$visitor` -... -LL | m_mut!(self) - | ------------ in this macro invocation +LL | inline!(*&mut $(@expr self)) + | ^^^^^^^^^^^^^^^^^^^ help: try this: `$(@expr self)` | - = note: this error originates in the macro `m_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 10 previous errors diff --git a/tests/ui/deref_addrof_macro.rs b/tests/ui/deref_addrof_macro.rs index dcebd6c6e29c..57c0be3f51e1 100644 --- a/tests/ui/deref_addrof_macro.rs +++ b/tests/ui/deref_addrof_macro.rs @@ -1,10 +1,13 @@ -macro_rules! m { - ($($x:tt),*) => { &[$(($x, stringify!(x)),)*] }; -} +// aux-build:proc_macros.rs -#[warn(clippy::deref_addrof)] -fn f() -> [(i32, &'static str); 3] { - *m![1, 2, 3] // should be fine +#![warn(clippy::deref_addrof)] + +extern crate proc_macros; + +#[proc_macros::inline_macros] +fn f() -> i32 { + // should be fine + *inline!(&$1) } fn main() {} diff --git a/tests/ui/doc_unsafe.rs b/tests/ui/doc_unsafe.rs index b91f7aa0dd8d..30674ce3708e 100644 --- a/tests/ui/doc_unsafe.rs +++ b/tests/ui/doc_unsafe.rs @@ -1,9 +1,9 @@ -// aux-build:doc_unsafe_macros.rs +// aux-build:proc_macros.rs #![allow(clippy::let_unit_value)] -#[macro_use] -extern crate doc_unsafe_macros; +extern crate proc_macros; +use proc_macros::external; /// This is not sufficiently documented pub unsafe fn destroy_the_planet() { @@ -105,7 +105,11 @@ macro_rules! very_unsafe { very_unsafe!(); // we don't lint code from external macros -undocd_unsafe!(); +external! { + pub unsafe fn oy_vey() { + unimplemented!(); + } +} fn main() { unsafe { diff --git a/tests/ui/empty_loop.rs b/tests/ui/empty_loop.rs index 8fd7697eb3b2..6a8e6b550c13 100644 --- a/tests/ui/empty_loop.rs +++ b/tests/ui/empty_loop.rs @@ -1,9 +1,9 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::empty_loop)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; fn should_trigger() { loop {} @@ -16,6 +16,7 @@ fn should_trigger() { } } +#[inline_macros] fn should_not_trigger() { loop { panic!("This is fine") @@ -38,14 +39,10 @@ fn should_not_trigger() { loop {} // We don't lint loops inside macros - macro_rules! foo { - () => { - loop {} - }; - } + inline!(loop {}); // We don't lint external macros - foofoo!() + external!(loop {}); } fn main() {} diff --git a/tests/ui/equatable_if_let.fixed b/tests/ui/equatable_if_let.fixed index 9af2ba962720..007702ab550b 100644 --- a/tests/ui/equatable_if_let.fixed +++ b/tests/ui/equatable_if_let.fixed @@ -1,11 +1,11 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)] #![warn(clippy::equatable_if_let)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; use std::cmp::Ordering; @@ -44,6 +44,7 @@ impl PartialEq for NotStructuralEq { } } +#[inline_macros] fn main() { let a = 2; let b = 3; @@ -78,14 +79,9 @@ fn main() { if Some(g) == Some(NotStructuralEq::A) {} if matches!(h, NoPartialEqStruct { a: 2, b: false }) {} - macro_rules! m1 { - (x) => { - "abc" - }; - } - if "abc" == m1!(x) { + if "abc" == inline!("abc") { println!("OK"); } - equatable_if_let!(a); + external!({ if let 2 = $a {} }); } diff --git a/tests/ui/equatable_if_let.rs b/tests/ui/equatable_if_let.rs index c3626c081dd5..3bda7977645b 100644 --- a/tests/ui/equatable_if_let.rs +++ b/tests/ui/equatable_if_let.rs @@ -1,11 +1,11 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)] #![warn(clippy::equatable_if_let)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; use std::cmp::Ordering; @@ -44,6 +44,7 @@ impl PartialEq for NotStructuralEq { } } +#[inline_macros] fn main() { let a = 2; let b = 3; @@ -78,14 +79,9 @@ fn main() { if let Some(NotStructuralEq::A) = Some(g) {} if let NoPartialEqStruct { a: 2, b: false } = h {} - macro_rules! m1 { - (x) => { - "abc" - }; - } - if let m1!(x) = "abc" { + if let inline!("abc") = "abc" { println!("OK"); } - equatable_if_let!(a); + external!({ if let 2 = $a {} }); } diff --git a/tests/ui/equatable_if_let.stderr b/tests/ui/equatable_if_let.stderr index 40ca75b8da22..a72d87bb7ba9 100644 --- a/tests/ui/equatable_if_let.stderr +++ b/tests/ui/equatable_if_let.stderr @@ -1,5 +1,5 @@ error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:59:8 + --> $DIR/equatable_if_let.rs:60:8 | LL | if let 2 = a {} | ^^^^^^^^^ help: try: `a == 2` @@ -7,82 +7,82 @@ LL | if let 2 = a {} = note: `-D clippy::equatable-if-let` implied by `-D warnings` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:60:8 + --> $DIR/equatable_if_let.rs:61:8 | LL | if let Ordering::Greater = a.cmp(&b) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.cmp(&b) == Ordering::Greater` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:61:8 + --> $DIR/equatable_if_let.rs:62:8 | LL | if let Some(2) = c {} | ^^^^^^^^^^^^^^^ help: try: `c == Some(2)` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:62:8 + --> $DIR/equatable_if_let.rs:63:8 | LL | if let Struct { a: 2, b: false } = d {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `d == (Struct { a: 2, b: false })` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:63:8 + --> $DIR/equatable_if_let.rs:64:8 | LL | if let Enum::TupleVariant(32, 64) = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::TupleVariant(32, 64)` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:64:8 + --> $DIR/equatable_if_let.rs:65:8 | LL | if let Enum::RecordVariant { a: 64, b: 32 } = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == (Enum::RecordVariant { a: 64, b: 32 })` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:65:8 + --> $DIR/equatable_if_let.rs:66:8 | LL | if let Enum::UnitVariant = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::UnitVariant` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:66:8 + --> $DIR/equatable_if_let.rs:67:8 | LL | if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false })` error: this pattern matching can be expressed using `matches!` - --> $DIR/equatable_if_let.rs:75:8 + --> $DIR/equatable_if_let.rs:76:8 | LL | if let NotPartialEq::A = f {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(f, NotPartialEq::A)` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:76:8 + --> $DIR/equatable_if_let.rs:77:8 | LL | if let NotStructuralEq::A = g {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `g == NotStructuralEq::A` error: this pattern matching can be expressed using `matches!` - --> $DIR/equatable_if_let.rs:77:8 + --> $DIR/equatable_if_let.rs:78:8 | LL | if let Some(NotPartialEq::A) = Some(f) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(Some(f), Some(NotPartialEq::A))` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:78:8 + --> $DIR/equatable_if_let.rs:79:8 | LL | if let Some(NotStructuralEq::A) = Some(g) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == Some(NotStructuralEq::A)` error: this pattern matching can be expressed using `matches!` - --> $DIR/equatable_if_let.rs:79:8 + --> $DIR/equatable_if_let.rs:80:8 | LL | if let NoPartialEqStruct { a: 2, b: false } = h {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(h, NoPartialEqStruct { a: 2, b: false })` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:86:8 + --> $DIR/equatable_if_let.rs:82:8 | -LL | if let m1!(x) = "abc" { - | ^^^^^^^^^^^^^^^^^^ help: try: `"abc" == m1!(x)` +LL | if let inline!("abc") = "abc" { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"abc" == inline!("abc")` error: aborting due to 14 previous errors diff --git a/tests/ui/field_reassign_with_default.rs b/tests/ui/field_reassign_with_default.rs index 1f989bb12205..0e208b3ed0e1 100644 --- a/tests/ui/field_reassign_with_default.rs +++ b/tests/ui/field_reassign_with_default.rs @@ -1,12 +1,12 @@ // aux-build:proc_macro_derive.rs -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::field_reassign_with_default)] #[macro_use] extern crate proc_macro_derive; -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; // Don't lint on derives that derive `Default` // See https://github.com/rust-lang/rust-clippy/issues/6545 @@ -36,14 +36,6 @@ struct D { b: Option, } -macro_rules! m { - ($key:ident: $value:tt) => {{ - let mut data = $crate::D::default(); - data.$key = Some($value); - data - }}; -} - /// Implements .next() that returns a different number each time. struct SideEffect(i32); @@ -57,6 +49,7 @@ impl SideEffect { } } +#[inline_macros] fn main() { // wrong, produces first error in stderr let mut a: A = Default::default(); @@ -150,7 +143,18 @@ fn main() { a.i = vec![1]; // Don't lint in external macros - field_reassign_with_default!(); + external! { + #[derive(Default)] + struct A { + pub i: i32, + pub j: i64, + } + fn lint() { + let mut a: A = Default::default(); + a.i = 42; + a; + } + } // be sure suggestion is correct with generics let mut a: Wrapper = Default::default(); @@ -160,9 +164,11 @@ fn main() { a.i = 42; // Don't lint in macros - m! { - a: 42 - }; + inline!( + let mut data = $crate::D::default(); + data.$a = Some($42); + data + ); } mod m { diff --git a/tests/ui/field_reassign_with_default.stderr b/tests/ui/field_reassign_with_default.stderr index 710bb66a48a4..da74f9ef9f7e 100644 --- a/tests/ui/field_reassign_with_default.stderr +++ b/tests/ui/field_reassign_with_default.stderr @@ -1,132 +1,132 @@ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:63:5 + --> $DIR/field_reassign_with_default.rs:56:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:62:5 + --> $DIR/field_reassign_with_default.rs:55:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `-D clippy::field-reassign-with-default` implied by `-D warnings` error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:103:5 + --> $DIR/field_reassign_with_default.rs:96:5 | LL | a.j = 43; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { j: 43, i: 42 }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:102:5 + --> $DIR/field_reassign_with_default.rs:95:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:108:5 + --> $DIR/field_reassign_with_default.rs:101:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { i: 42, j: 44 }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:107:5 + --> $DIR/field_reassign_with_default.rs:100:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:114:5 + --> $DIR/field_reassign_with_default.rs:107:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:113:5 + --> $DIR/field_reassign_with_default.rs:106:5 | LL | let mut a = A::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:124:5 + --> $DIR/field_reassign_with_default.rs:117:5 | LL | a.i = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `main::A { i: Default::default(), ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:123:5 + --> $DIR/field_reassign_with_default.rs:116:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:128:5 + --> $DIR/field_reassign_with_default.rs:121:5 | LL | a.i = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `main::A { i: Default::default(), j: 45 }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:127:5 + --> $DIR/field_reassign_with_default.rs:120:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:150:5 + --> $DIR/field_reassign_with_default.rs:143:5 | LL | a.i = vec![1]; | ^^^^^^^^^^^^^^ | note: consider initializing the variable with `C { i: vec![1], ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:149:5 + --> $DIR/field_reassign_with_default.rs:142:5 | LL | let mut a: C = C::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:157:5 + --> $DIR/field_reassign_with_default.rs:161:5 | LL | a.i = true; | ^^^^^^^^^^^ | note: consider initializing the variable with `Wrapper:: { i: true }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:156:5 + --> $DIR/field_reassign_with_default.rs:160:5 | LL | let mut a: Wrapper = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:160:5 + --> $DIR/field_reassign_with_default.rs:164:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `WrapperMulti:: { i: 42, ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:159:5 + --> $DIR/field_reassign_with_default.rs:163:5 | LL | let mut a: WrapperMulti = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:229:13 + --> $DIR/field_reassign_with_default.rs:235:13 | LL | f.name = name.len(); | ^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `issue6312::ImplDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:228:13 + --> $DIR/field_reassign_with_default.rs:234:13 | LL | let mut f = ImplDropAllCopy::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:245:13 + --> $DIR/field_reassign_with_default.rs:251:13 | LL | f.name = name.len(); | ^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `issue6312::NoDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:244:13 + --> $DIR/field_reassign_with_default.rs:250:13 | LL | let mut f = NoDropAllCopy::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/ifs_same_cond.rs b/tests/ui/ifs_same_cond.rs index 9850fc0919e1..9ce9a87626a7 100644 --- a/tests/ui/ifs_same_cond.rs +++ b/tests/ui/ifs_same_cond.rs @@ -43,4 +43,30 @@ fn ifs_same_cond() { } } +fn issue10272() { + let a = String::from("ha"); + if a.contains("ah") { + } else if a.contains("ah") { + // Trigger this lint + } else if a.contains("ha") { + } else if a == "wow" { + } + + let p: *mut i8 = std::ptr::null_mut(); + if p.is_null() { + } else if p.align_offset(0) == 0 { + } else if p.is_null() { + // ok, p is mutable pointer + } else { + } + + let x = std::cell::Cell::new(true); + if x.get() { + } else if !x.take() { + } else if x.get() { + // ok, x is interior mutable type + } else { + } +} + fn main() {} diff --git a/tests/ui/ifs_same_cond.stderr b/tests/ui/ifs_same_cond.stderr index 4113087327a2..9519f6904cb1 100644 --- a/tests/ui/ifs_same_cond.stderr +++ b/tests/ui/ifs_same_cond.stderr @@ -35,5 +35,17 @@ note: same as this LL | if 2 * a == 1 { | ^^^^^^^^^^ -error: aborting due to 3 previous errors +error: this `if` has the same condition as a previous `if` + --> $DIR/ifs_same_cond.rs:49:15 + | +LL | } else if a.contains("ah") { + | ^^^^^^^^^^^^^^^^ + | +note: same as this + --> $DIR/ifs_same_cond.rs:48:8 + | +LL | if a.contains("ah") { + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors diff --git a/tests/ui/implicit_hasher.rs b/tests/ui/implicit_hasher.rs index fd96ca3f466e..35d08a07bc3f 100644 --- a/tests/ui/implicit_hasher.rs +++ b/tests/ui/implicit_hasher.rs @@ -1,9 +1,11 @@ -// aux-build:implicit_hasher_macros.rs +// aux-build:proc_macros.rs + #![deny(clippy::implicit_hasher)] #![allow(unused)] #[macro_use] -extern crate implicit_hasher_macros; +extern crate proc_macros; +use proc_macros::external; use std::cmp::Eq; use std::collections::{HashMap, HashSet}; @@ -68,22 +70,19 @@ impl Foo for HashSet { pub fn foo(_map: &mut HashMap, _set: &mut HashSet) {} -macro_rules! gen { - (impl) => { +#[proc_macros::inline_macros] +pub mod gen { + use super::*; + inline! { impl Foo for HashMap { fn make() -> (Self, Self) { (HashMap::new(), HashMap::with_capacity(10)) } } - }; - (fn $name:ident) => { - pub fn $name(_map: &mut HashMap, _set: &mut HashSet) {} - }; + pub fn bar(_map: &mut HashMap, _set: &mut HashSet) {} + } } -#[rustfmt::skip] -gen!(impl); -gen!(fn bar); // When the macro is in a different file, the suggestion spans can't be combined properly // and should not cause an ICE @@ -94,7 +93,9 @@ pub mod test_macro; __implicit_hasher_test_macro!(impl for HashMap where V: test_macro::A); // #4260 -implicit_hasher_fn!(); +external! { + pub fn f(input: &HashMap) {} +} // #7712 pub async fn election_vote(_data: HashMap) {} diff --git a/tests/ui/implicit_hasher.stderr b/tests/ui/implicit_hasher.stderr index 59b0fba2a4cf..83b46de2eb5e 100644 --- a/tests/ui/implicit_hasher.stderr +++ b/tests/ui/implicit_hasher.stderr @@ -1,11 +1,11 @@ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:16:35 + --> $DIR/implicit_hasher.rs:18:35 | LL | impl Foo for HashMap { | ^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/implicit_hasher.rs:2:9 + --> $DIR/implicit_hasher.rs:3:9 | LL | #![deny(clippy::implicit_hasher)] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:25:36 + --> $DIR/implicit_hasher.rs:27:36 | LL | impl Foo for (HashMap,) { | ^^^^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Defa | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:30:19 + --> $DIR/implicit_hasher.rs:32:19 | LL | impl Foo for HashMap { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:47:32 + --> $DIR/implicit_hasher.rs:49:32 | LL | impl Foo for HashSet { | ^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:52:19 + --> $DIR/implicit_hasher.rs:54:19 | LL | impl Foo for HashSet { | ^^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ LL | (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:69:23 + --> $DIR/implicit_hasher.rs:71:23 | LL | pub fn foo(_map: &mut HashMap, _set: &mut HashSet) {} | ^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | pub fn foo(_map: &mut HashMap, _s | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:69:53 + --> $DIR/implicit_hasher.rs:71:53 | LL | pub fn foo(_map: &mut HashMap, _set: &mut HashSet) {} | ^^^^^^^^^^^^ @@ -101,15 +101,12 @@ LL | pub fn foo(_map: &mut HashMap, _set: | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:73:43 + --> $DIR/implicit_hasher.rs:77:43 | LL | impl Foo for HashMap { | ^^^^^^^^^^^^^ -... -LL | gen!(impl); - | ---------- in this macro invocation | - = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_mod_gen` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider adding a type parameter | LL | impl Foo for HashMap { @@ -120,37 +117,31 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:81:33 + --> $DIR/implicit_hasher.rs:83:31 | -LL | pub fn $name(_map: &mut HashMap, _set: &mut HashSet) {} - | ^^^^^^^^^^^^^^^^^ -... -LL | gen!(fn bar); - | ------------ in this macro invocation +LL | pub fn bar(_map: &mut HashMap, _set: &mut HashSet) {} + | ^^^^^^^^^^^^^^^^^ | - = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_mod_gen` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider adding a type parameter | -LL | pub fn $name(_map: &mut HashMap, _set: &mut HashSet) {} - | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~ +LL | pub fn bar(_map: &mut HashMap, _set: &mut HashSet) {} + | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:81:63 + --> $DIR/implicit_hasher.rs:83:61 | -LL | pub fn $name(_map: &mut HashMap, _set: &mut HashSet) {} - | ^^^^^^^^^^^^ -... -LL | gen!(fn bar); - | ------------ in this macro invocation +LL | pub fn bar(_map: &mut HashMap, _set: &mut HashSet) {} + | ^^^^^^^^^^^^ | - = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_mod_gen` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider adding a type parameter | -LL | pub fn $name(_map: &mut HashMap, _set: &mut HashSet) {} - | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~ +LL | pub fn bar(_map: &mut HashMap, _set: &mut HashSet) {} + | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:100:35 + --> $DIR/implicit_hasher.rs:101:35 | LL | pub async fn election_vote(_data: HashMap) {} | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/inconsistent_struct_constructor.fixed b/tests/ui/inconsistent_struct_constructor.fixed index 74ba2f1c5e70..5aaa00f85172 100644 --- a/tests/ui/inconsistent_struct_constructor.fixed +++ b/tests/ui/inconsistent_struct_constructor.fixed @@ -1,10 +1,14 @@ // run-rustfix +// aux-build:proc_macros.rs + #![warn(clippy::inconsistent_struct_constructor)] #![allow(clippy::redundant_field_names)] #![allow(clippy::unnecessary_operation)] #![allow(clippy::no_effect)] #![allow(dead_code)] +extern crate proc_macros; + #[derive(Default)] struct Foo { x: i32, @@ -12,18 +16,10 @@ struct Foo { z: i32, } -macro_rules! new_foo { - () => { - let x = 1; - let y = 1; - let z = 1; - Foo { y, x, z } - }; -} - mod without_base { use super::Foo; + #[proc_macros::inline_macros] fn test() { let x = 1; let y = 1; @@ -34,7 +30,12 @@ mod without_base { // Should NOT lint. // issue #7069. - new_foo!(); + inline!({ + let x = 1; + let y = 1; + let z = 1; + Foo { y, x, z } + }); // Should NOT lint because the order is the same as in the definition. Foo { x, y, z }; diff --git a/tests/ui/inconsistent_struct_constructor.rs b/tests/ui/inconsistent_struct_constructor.rs index ba96e1e330f5..2b2dd7f59a4d 100644 --- a/tests/ui/inconsistent_struct_constructor.rs +++ b/tests/ui/inconsistent_struct_constructor.rs @@ -1,10 +1,14 @@ // run-rustfix +// aux-build:proc_macros.rs + #![warn(clippy::inconsistent_struct_constructor)] #![allow(clippy::redundant_field_names)] #![allow(clippy::unnecessary_operation)] #![allow(clippy::no_effect)] #![allow(dead_code)] +extern crate proc_macros; + #[derive(Default)] struct Foo { x: i32, @@ -12,18 +16,10 @@ struct Foo { z: i32, } -macro_rules! new_foo { - () => { - let x = 1; - let y = 1; - let z = 1; - Foo { y, x, z } - }; -} - mod without_base { use super::Foo; + #[proc_macros::inline_macros] fn test() { let x = 1; let y = 1; @@ -34,7 +30,12 @@ mod without_base { // Should NOT lint. // issue #7069. - new_foo!(); + inline!({ + let x = 1; + let y = 1; + let z = 1; + Foo { y, x, z } + }); // Should NOT lint because the order is the same as in the definition. Foo { x, y, z }; diff --git a/tests/ui/inconsistent_struct_constructor.stderr b/tests/ui/inconsistent_struct_constructor.stderr index c90189e964f0..785a6dc9d53a 100644 --- a/tests/ui/inconsistent_struct_constructor.stderr +++ b/tests/ui/inconsistent_struct_constructor.stderr @@ -1,5 +1,5 @@ error: struct constructor field order is inconsistent with struct definition field order - --> $DIR/inconsistent_struct_constructor.rs:33:9 + --> $DIR/inconsistent_struct_constructor.rs:29:9 | LL | Foo { y, x, z }; | ^^^^^^^^^^^^^^^ help: try: `Foo { x, y, z }` @@ -7,7 +7,7 @@ LL | Foo { y, x, z }; = note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings` error: struct constructor field order is inconsistent with struct definition field order - --> $DIR/inconsistent_struct_constructor.rs:55:9 + --> $DIR/inconsistent_struct_constructor.rs:56:9 | LL | / Foo { LL | | z, diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs index 3b96f09d7b1d..f09f8ae0ccc3 100644 --- a/tests/ui/large_enum_variant.rs +++ b/tests/ui/large_enum_variant.rs @@ -1,11 +1,11 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![allow(dead_code)] #![allow(unused_variables)] #![warn(clippy::large_enum_variant)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::external; enum LargeEnum { A(i32), @@ -155,5 +155,10 @@ enum LargeEnumOfConst { } fn main() { - large_enum_variant!(); + external!( + enum LargeEnumInMacro { + A(i32), + B([i32; 8000]), + } + ); } diff --git a/tests/ui/macro_use_imports.fixed b/tests/ui/macro_use_imports.fixed index e612480d264b..15f7a099a7de 100644 --- a/tests/ui/macro_use_imports.fixed +++ b/tests/ui/macro_use_imports.fixed @@ -20,7 +20,7 @@ mod a { use mac; use mini_mac::ClippyMiniMacroTest; use mini_mac; - use mac::{inner::foofoo, inner::try_err}; + use mac::{inner::mut_mut, inner::try_err}; use mac::inner; use mac::inner::nested::string_add; use mac::inner::nested; @@ -36,7 +36,7 @@ mod a { let v: ty_macro!() = Vec::default(); inner::try_err!(); - inner::foofoo!(); + inner::mut_mut!(); nested::string_add!(); } } diff --git a/tests/ui/macro_use_imports.rs b/tests/ui/macro_use_imports.rs index b34817cc3b26..b1a287332949 100644 --- a/tests/ui/macro_use_imports.rs +++ b/tests/ui/macro_use_imports.rs @@ -36,7 +36,7 @@ mod a { let v: ty_macro!() = Vec::default(); inner::try_err!(); - inner::foofoo!(); + inner::mut_mut!(); nested::string_add!(); } } diff --git a/tests/ui/macro_use_imports.stderr b/tests/ui/macro_use_imports.stderr index 61843124ccd9..68d558dede05 100644 --- a/tests/ui/macro_use_imports.stderr +++ b/tests/ui/macro_use_imports.stderr @@ -16,7 +16,7 @@ error: `macro_use` attributes are no longer needed in the Rust 2018 edition --> $DIR/macro_use_imports.rs:23:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::mut_mut, inner::try_err};` error: `macro_use` attributes are no longer needed in the Rust 2018 edition --> $DIR/macro_use_imports.rs:19:5 diff --git a/tests/ui/macro_use_imports_expect.rs b/tests/ui/macro_use_imports_expect.rs index 8a1b05da9efc..5aac5af26db5 100644 --- a/tests/ui/macro_use_imports_expect.rs +++ b/tests/ui/macro_use_imports_expect.rs @@ -39,7 +39,7 @@ mod a { let v: ty_macro!() = Vec::default(); inner::try_err!(); - inner::foofoo!(); + inner::mut_mut!(); nested::string_add!(); } } diff --git a/tests/ui/manual_async_fn.fixed b/tests/ui/manual_async_fn.fixed index b7e46a4a8ccc..5cc4a43af7e3 100644 --- a/tests/ui/manual_async_fn.fixed +++ b/tests/ui/manual_async_fn.fixed @@ -107,4 +107,10 @@ mod issue_5765 { } } +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 b05429da6622..ba504b8a8231 100644 --- a/tests/ui/manual_async_fn.rs +++ b/tests/ui/manual_async_fn.rs @@ -127,4 +127,16 @@ mod issue_5765 { } } +pub fn issue_10450() -> impl Future { + async { 42 } +} + +pub(crate) fn issue_10450_2() -> impl Future { + async { 42 } +} + +pub(self) fn issue_10450_3() -> impl Future { + async { 42 } +} + fn main() {} diff --git a/tests/ui/manual_async_fn.stderr b/tests/ui/manual_async_fn.stderr index 0a903ed6fd43..f5ee3eb7cccb 100644 --- a/tests/ui/manual_async_fn.stderr +++ b/tests/ui/manual_async_fn.stderr @@ -161,5 +161,50 @@ help: move the body of the async block to the enclosing function LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { 42 } | ~~~~~~ -error: aborting due to 10 previous errors +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:130:1 + | +LL | pub fn issue_10450() -> impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and return the output of the future directly + | +LL | pub async fn issue_10450() -> i32 { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: move the body of the async block to the enclosing function + | +LL | pub fn issue_10450() -> impl Future { 42 } + | ~~~~~~ + +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:134:1 + | +LL | pub(crate) fn issue_10450_2() -> impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and return the output of the future directly + | +LL | pub(crate) async fn issue_10450_2() -> i32 { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: move the body of the async block to the enclosing function + | +LL | pub(crate) fn issue_10450_2() -> impl Future { 42 } + | ~~~~~~ + +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:138:1 + | +LL | pub(self) fn issue_10450_3() -> impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and return the output of the future directly + | +LL | pub(self) async fn issue_10450_3() -> i32 { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: move the body of the async block to the enclosing function + | +LL | pub(self) fn issue_10450_3() -> impl Future { 42 } + | ~~~~~~ + +error: aborting due to 13 previous errors diff --git a/tests/ui/manual_clamp.rs b/tests/ui/manual_clamp.rs index f7902e6fd538..cdfd8e4c3fe3 100644 --- a/tests/ui/manual_clamp.rs +++ b/tests/ui/manual_clamp.rs @@ -326,3 +326,22 @@ fn msrv_1_50() { input }; } + +const fn _const() { + let (input, min, max) = (0, -1, 2); + let _ = if input < min { + min + } else if input > max { + max + } else { + input + }; + + let mut x = input; + if max < x { + let x = max; + } + if min > x { + x = min; + } +} diff --git a/tests/ui/manual_main_separator_str.fixed b/tests/ui/manual_main_separator_str.fixed new file mode 100644 index 000000000000..50f46d6b3550 --- /dev/null +++ b/tests/ui/manual_main_separator_str.fixed @@ -0,0 +1,39 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::manual_main_separator_str)] + +use std::path::MAIN_SEPARATOR; + +fn len(s: &str) -> usize { + s.len() +} + +struct U<'a> { + f: &'a str, + g: &'a String, +} + +struct V { + f: T, +} + +fn main() { + // Should lint + let _: &str = std::path::MAIN_SEPARATOR_STR; + let _ = len(std::path::MAIN_SEPARATOR_STR); + let _: Vec = std::path::MAIN_SEPARATOR_STR.encode_utf16().collect(); + + // Should lint for field `f` only + let _ = U { + f: std::path::MAIN_SEPARATOR_STR, + g: &MAIN_SEPARATOR.to_string(), + }; + + // Should not lint + let _: &String = &MAIN_SEPARATOR.to_string(); + let _ = &MAIN_SEPARATOR.to_string(); + let _ = V { + f: &MAIN_SEPARATOR.to_string(), + }; +} diff --git a/tests/ui/manual_main_separator_str.rs b/tests/ui/manual_main_separator_str.rs new file mode 100644 index 000000000000..2dbb9e66151d --- /dev/null +++ b/tests/ui/manual_main_separator_str.rs @@ -0,0 +1,39 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::manual_main_separator_str)] + +use std::path::MAIN_SEPARATOR; + +fn len(s: &str) -> usize { + s.len() +} + +struct U<'a> { + f: &'a str, + g: &'a String, +} + +struct V { + f: T, +} + +fn main() { + // Should lint + let _: &str = &MAIN_SEPARATOR.to_string(); + let _ = len(&MAIN_SEPARATOR.to_string()); + let _: Vec = MAIN_SEPARATOR.to_string().encode_utf16().collect(); + + // Should lint for field `f` only + let _ = U { + f: &MAIN_SEPARATOR.to_string(), + g: &MAIN_SEPARATOR.to_string(), + }; + + // Should not lint + let _: &String = &MAIN_SEPARATOR.to_string(); + let _ = &MAIN_SEPARATOR.to_string(); + let _ = V { + f: &MAIN_SEPARATOR.to_string(), + }; +} diff --git a/tests/ui/manual_main_separator_str.stderr b/tests/ui/manual_main_separator_str.stderr new file mode 100644 index 000000000000..e6cefde66a7d --- /dev/null +++ b/tests/ui/manual_main_separator_str.stderr @@ -0,0 +1,28 @@ +error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String` + --> $DIR/manual_main_separator_str.rs:23:19 + | +LL | let _: &str = &MAIN_SEPARATOR.to_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR` + | + = note: `-D clippy::manual-main-separator-str` implied by `-D warnings` + +error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String` + --> $DIR/manual_main_separator_str.rs:24:17 + | +LL | let _ = len(&MAIN_SEPARATOR.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR` + +error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String` + --> $DIR/manual_main_separator_str.rs:25:23 + | +LL | let _: Vec = MAIN_SEPARATOR.to_string().encode_utf16().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR` + +error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String` + --> $DIR/manual_main_separator_str.rs:29:12 + | +LL | f: &MAIN_SEPARATOR.to_string(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/manual_rem_euclid.fixed b/tests/ui/manual_rem_euclid.fixed index 6916a284a20a..1f6df1b0a865 100644 --- a/tests/ui/manual_rem_euclid.fixed +++ b/tests/ui/manual_rem_euclid.fixed @@ -1,19 +1,13 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::manual_rem_euclid)] #![allow(clippy::let_with_type_underscore)] -#[macro_use] -extern crate macro_rules; - -macro_rules! internal_rem_euclid { - () => { - let value: i32 = 5; - let _: i32 = value.rem_euclid(4); - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { let value: i32 = 5; @@ -39,10 +33,16 @@ fn main() { let _: i32 = ((4 % value) + 4) % 4; // Lint in internal macros - internal_rem_euclid!(); + inline!( + let value: i32 = 5; + let _: i32 = value.rem_euclid(4); + ); // Do not lint in external macros - manual_rem_euclid!(); + external!( + let value: i32 = 5; + let _: i32 = ((value % 4) + 4) % 4; + ); } // Should lint for params too diff --git a/tests/ui/manual_rem_euclid.rs b/tests/ui/manual_rem_euclid.rs index 412dbddb4266..b275e8a38d21 100644 --- a/tests/ui/manual_rem_euclid.rs +++ b/tests/ui/manual_rem_euclid.rs @@ -1,19 +1,13 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::manual_rem_euclid)] #![allow(clippy::let_with_type_underscore)] -#[macro_use] -extern crate macro_rules; - -macro_rules! internal_rem_euclid { - () => { - let value: i32 = 5; - let _: i32 = ((value % 4) + 4) % 4; - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { let value: i32 = 5; @@ -39,10 +33,16 @@ fn main() { let _: i32 = ((4 % value) + 4) % 4; // Lint in internal macros - internal_rem_euclid!(); + inline!( + let value: i32 = 5; + let _: i32 = ((value % 4) + 4) % 4; + ); // Do not lint in external macros - manual_rem_euclid!(); + external!( + let value: i32 = 5; + let _: i32 = ((value % 4) + 4) % 4; + ); } // Should lint for params too diff --git a/tests/ui/manual_rem_euclid.stderr b/tests/ui/manual_rem_euclid.stderr index 6d06654638b3..a43707f89c49 100644 --- a/tests/ui/manual_rem_euclid.stderr +++ b/tests/ui/manual_rem_euclid.stderr @@ -1,5 +1,5 @@ error: manual `rem_euclid` implementation - --> $DIR/manual_rem_euclid.rs:20:18 + --> $DIR/manual_rem_euclid.rs:14:18 | LL | let _: i32 = ((value % 4) + 4) % 4; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` @@ -7,39 +7,36 @@ LL | let _: i32 = ((value % 4) + 4) % 4; = note: `-D clippy::manual-rem-euclid` implied by `-D warnings` error: manual `rem_euclid` implementation - --> $DIR/manual_rem_euclid.rs:21:18 + --> $DIR/manual_rem_euclid.rs:15:18 | LL | let _: i32 = (4 + (value % 4)) % 4; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` error: manual `rem_euclid` implementation - --> $DIR/manual_rem_euclid.rs:22:18 + --> $DIR/manual_rem_euclid.rs:16:18 | LL | let _: i32 = (value % 4 + 4) % 4; | ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` error: manual `rem_euclid` implementation - --> $DIR/manual_rem_euclid.rs:23:18 + --> $DIR/manual_rem_euclid.rs:17:18 | LL | let _: i32 = (4 + value % 4) % 4; | ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` error: manual `rem_euclid` implementation - --> $DIR/manual_rem_euclid.rs:24:22 + --> $DIR/manual_rem_euclid.rs:18:22 | LL | let _: i32 = 1 + (4 + value % 4) % 4; | ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` error: manual `rem_euclid` implementation - --> $DIR/manual_rem_euclid.rs:13:22 + --> $DIR/manual_rem_euclid.rs:38:22 | LL | let _: i32 = ((value % 4) + 4) % 4; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` -... -LL | internal_rem_euclid!(); - | ---------------------- in this macro invocation | - = note: this error originates in the macro `internal_rem_euclid` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: manual `rem_euclid` implementation --> $DIR/manual_rem_euclid.rs:50:5 diff --git a/tests/ui/match_single_binding.fixed b/tests/ui/match_single_binding.fixed index 6cfb6661a039..201301cc9b73 100644 --- a/tests/ui/match_single_binding.fixed +++ b/tests/ui/match_single_binding.fixed @@ -1,7 +1,12 @@ // run-rustfix #![warn(clippy::match_single_binding)] -#![allow(unused_variables)] -#![allow(clippy::toplevel_ref_arg, clippy::uninlined_format_args)] +#![allow( + unused, + clippy::let_unit_value, + clippy::no_effect, + clippy::toplevel_ref_arg, + clippy::uninlined_format_args +)] struct Point { x: i32, @@ -109,10 +114,9 @@ fn main() { // Lint let x = 1; - println!("Not an array index start"); + println!("Not an array index start") } -#[allow(dead_code)] fn issue_8723() { let (mut val, idx) = ("a b", 1); @@ -125,16 +129,15 @@ fn issue_8723() { let _ = val; } -#[allow(dead_code)] +fn side_effects() {} + fn issue_9575() { - fn side_effects() {} let _ = || { side_effects(); - println!("Needs curlies"); + println!("Needs curlies") }; } -#[allow(dead_code)] fn issue_9725(r: Option) { let x = r; match x { @@ -146,3 +149,25 @@ fn issue_9725(r: Option) { }, }; } + +fn issue_10447() -> usize { + (); + + let a = (); + + side_effects(); + + let b = side_effects(); + + println!("1"); + + let c = println!("1"); + + let in_expr = [ + (), + side_effects(), + println!("1"), + ]; + + 2 +} diff --git a/tests/ui/match_single_binding.rs b/tests/ui/match_single_binding.rs index f188aeb5f2ff..8b047b19ce96 100644 --- a/tests/ui/match_single_binding.rs +++ b/tests/ui/match_single_binding.rs @@ -1,7 +1,12 @@ // run-rustfix #![warn(clippy::match_single_binding)] -#![allow(unused_variables)] -#![allow(clippy::toplevel_ref_arg, clippy::uninlined_format_args)] +#![allow( + unused, + clippy::let_unit_value, + clippy::no_effect, + clippy::toplevel_ref_arg, + clippy::uninlined_format_args +)] struct Point { x: i32, @@ -127,7 +132,6 @@ fn main() { } } -#[allow(dead_code)] fn issue_8723() { let (mut val, idx) = ("a b", 1); @@ -141,15 +145,14 @@ fn issue_8723() { let _ = val; } -#[allow(dead_code)] +fn side_effects() {} + fn issue_9575() { - fn side_effects() {} let _ = || match side_effects() { _ => println!("Needs curlies"), }; } -#[allow(dead_code)] fn issue_9725(r: Option) { match r { x => match x { @@ -162,3 +165,43 @@ fn issue_9725(r: Option) { }, }; } + +fn issue_10447() -> usize { + match 1 { + _ => (), + } + + let a = match 1 { + _ => (), + }; + + match 1 { + _ => side_effects(), + } + + let b = match 1 { + _ => side_effects(), + }; + + match 1 { + _ => println!("1"), + } + + let c = match 1 { + _ => println!("1"), + }; + + let in_expr = [ + match 1 { + _ => (), + }, + match 1 { + _ => side_effects(), + }, + match 1 { + _ => println!("1"), + }, + ]; + + 2 +} diff --git a/tests/ui/match_single_binding.stderr b/tests/ui/match_single_binding.stderr index e960d64ad2b0..9d16af76c6af 100644 --- a/tests/ui/match_single_binding.stderr +++ b/tests/ui/match_single_binding.stderr @@ -1,5 +1,5 @@ error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:28:5 + --> $DIR/match_single_binding.rs:33:5 | LL | / match (a, b, c) { LL | | (x, y, z) => { @@ -18,7 +18,7 @@ LL + } | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:34:5 + --> $DIR/match_single_binding.rs:39:5 | LL | / match (a, b, c) { LL | | (x, y, z) => println!("{} {} {}", x, y, z), @@ -32,7 +32,7 @@ LL + println!("{} {} {}", x, y, z); | error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:51:5 + --> $DIR/match_single_binding.rs:56:5 | LL | / match a { LL | | _ => println!("whatever"), @@ -40,7 +40,7 @@ LL | | } | |_____^ help: consider using the match body instead: `println!("whatever");` error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:55:5 + --> $DIR/match_single_binding.rs:60:5 | LL | / match a { LL | | _ => { @@ -59,7 +59,7 @@ LL + } | error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:62:5 + --> $DIR/match_single_binding.rs:67:5 | LL | / match a { LL | | _ => { @@ -81,7 +81,7 @@ LL + } | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:72:5 + --> $DIR/match_single_binding.rs:77:5 | LL | / match p { LL | | Point { x, y } => println!("Coords: ({}, {})", x, y), @@ -95,7 +95,7 @@ LL + println!("Coords: ({}, {})", x, y); | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:76:5 + --> $DIR/match_single_binding.rs:81:5 | LL | / match p { LL | | Point { x: x1, y: y1 } => println!("Coords: ({}, {})", x1, y1), @@ -109,7 +109,7 @@ LL + println!("Coords: ({}, {})", x1, y1); | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:81:5 + --> $DIR/match_single_binding.rs:86:5 | LL | / match x { LL | | ref r => println!("Got a reference to {}", r), @@ -123,7 +123,7 @@ LL + println!("Got a reference to {}", r); | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:86:5 + --> $DIR/match_single_binding.rs:91:5 | LL | / match x { LL | | ref mut mr => println!("Got a mutable reference to {}", mr), @@ -137,7 +137,7 @@ LL + println!("Got a mutable reference to {}", mr); | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:90:5 + --> $DIR/match_single_binding.rs:95:5 | LL | / let product = match coords() { LL | | Point { x, y } => x * y, @@ -151,7 +151,7 @@ LL + let product = x * y; | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:98:18 + --> $DIR/match_single_binding.rs:103:18 | LL | .map(|i| match i.unwrap() { | __________________^ @@ -168,16 +168,16 @@ LL ~ }) | error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:124:5 + --> $DIR/match_single_binding.rs:129:5 | LL | / match x { LL | | // => LL | | _ => println!("Not an array index start"), LL | | } - | |_____^ help: consider using the match body instead: `println!("Not an array index start");` + | |_____^ help: consider using the match body instead: `println!("Not an array index start")` error: this assignment could be simplified - --> $DIR/match_single_binding.rs:134:5 + --> $DIR/match_single_binding.rs:138:5 | LL | / val = match val.split_at(idx) { LL | | (pre, suf) => { @@ -197,7 +197,7 @@ LL ~ }; | error: this match could be replaced by its scrutinee and body - --> $DIR/match_single_binding.rs:147:16 + --> $DIR/match_single_binding.rs:151:16 | LL | let _ = || match side_effects() { | ________________^ @@ -209,12 +209,12 @@ help: consider using the scrutinee and body instead | LL ~ let _ = || { LL + side_effects(); -LL + println!("Needs curlies"); +LL + println!("Needs curlies") LL ~ }; | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:154:5 + --> $DIR/match_single_binding.rs:157:5 | LL | / match r { LL | | x => match x { @@ -238,5 +238,80 @@ LL + }, LL ~ }; | -error: aborting due to 15 previous errors +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:170:5 + | +LL | / match 1 { +LL | | _ => (), +LL | | } + | |_____^ help: consider using the match body instead: `();` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:174:13 + | +LL | let a = match 1 { + | _____________^ +LL | | _ => (), +LL | | }; + | |_____^ help: consider using the match body instead: `()` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:178:5 + | +LL | / match 1 { +LL | | _ => side_effects(), +LL | | } + | |_____^ help: consider using the match body instead: `side_effects();` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:182:13 + | +LL | let b = match 1 { + | _____________^ +LL | | _ => side_effects(), +LL | | }; + | |_____^ help: consider using the match body instead: `side_effects()` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:186:5 + | +LL | / match 1 { +LL | | _ => println!("1"), +LL | | } + | |_____^ help: consider using the match body instead: `println!("1");` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:190:13 + | +LL | let c = match 1 { + | _____________^ +LL | | _ => println!("1"), +LL | | }; + | |_____^ help: consider using the match body instead: `println!("1")` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:195:9 + | +LL | / match 1 { +LL | | _ => (), +LL | | }, + | |_________^ help: consider using the match body instead: `()` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:198:9 + | +LL | / match 1 { +LL | | _ => side_effects(), +LL | | }, + | |_________^ help: consider using the match body instead: `side_effects()` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:201:9 + | +LL | / match 1 { +LL | | _ => println!("1"), +LL | | }, + | |_________^ help: consider using the match body instead: `println!("1")` + +error: aborting due to 24 previous errors diff --git a/tests/ui/match_single_binding2.fixed b/tests/ui/match_single_binding2.fixed index 6a7db67e311a..e3cf56a4293c 100644 --- a/tests/ui/match_single_binding2.fixed +++ b/tests/ui/match_single_binding2.fixed @@ -30,7 +30,7 @@ fn main() { #[rustfmt::skip] Some((first, _second)) => { let (a, b) = get_tup(); - println!("a {:?} and b {:?}", a, b); + println!("a {:?} and b {:?}", a, b) }, None => println!("nothing"), } @@ -49,5 +49,5 @@ fn main() { 0 => 1, _ => 2, }; - println!("Single branch"); + println!("Single branch") } diff --git a/tests/ui/match_single_binding2.stderr b/tests/ui/match_single_binding2.stderr index 22bf7d8be4a2..e180b93e76d7 100644 --- a/tests/ui/match_single_binding2.stderr +++ b/tests/ui/match_single_binding2.stderr @@ -27,7 +27,7 @@ LL | | } help: consider using a `let` statement | LL ~ let (a, b) = get_tup(); -LL + println!("a {:?} and b {:?}", a, b); +LL + println!("a {:?} and b {:?}", a, b) | error: this match could be replaced by its scrutinee and body @@ -61,7 +61,7 @@ LL ~ match x { LL + 0 => 1, LL + _ => 2, LL + }; -LL + println!("Single branch"); +LL + println!("Single branch") | error: aborting due to 4 previous errors diff --git a/tests/ui/mem_replace_macro.rs b/tests/ui/mem_replace_macro.rs index 0c09344b80d1..3932e7d00c19 100644 --- a/tests/ui/mem_replace_macro.rs +++ b/tests/ui/mem_replace_macro.rs @@ -1,21 +1,12 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::mem_replace_with_default)] -#[macro_use] -extern crate macro_rules; - -macro_rules! take { - ($s:expr) => { - std::mem::replace($s, Default::default()) - }; -} - -fn replace_with_default() { - let s = &mut String::from("foo"); - take!(s); - take_external!(s); -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { - replace_with_default(); + let s = &mut String::from("foo"); + inline!(std::mem::replace($s, Default::default())); + external!(std::mem::replace($s, Default::default())); } diff --git a/tests/ui/mem_replace_macro.stderr b/tests/ui/mem_replace_macro.stderr index dd69ab8b5efb..35dda93da3d0 100644 --- a/tests/ui/mem_replace_macro.stderr +++ b/tests/ui/mem_replace_macro.stderr @@ -1,14 +1,11 @@ error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> $DIR/mem_replace_macro.rs:9:9 + --> $DIR/mem_replace_macro.rs:10:13 | -LL | std::mem::replace($s, Default::default()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | take!(s); - | -------- in this macro invocation +LL | inline!(std::mem::replace($s, Default::default())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::mem-replace-with-default` implied by `-D warnings` - = note: this error originates in the macro `take` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error 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 75cace181675..e6f88c6e622c 100644 --- a/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -3,15 +3,15 @@ //! The .stderr output of this test should be empty. Otherwise it's a bug somewhere. // aux-build:helper.rs -// aux-build:../../auxiliary/proc_macro_with_span.rs +// aux-build:../../auxiliary/proc_macros.rs #![warn(clippy::missing_const_for_fn)] #![feature(start)] extern crate helper; -extern crate proc_macro_with_span; +extern crate proc_macros; -use proc_macro_with_span::with_span; +use proc_macros::with_span; struct Game; diff --git a/tests/ui/missing_doc.rs b/tests/ui/missing_doc.rs index 590ad63c90be..5752048949ca 100644 --- a/tests/ui/missing_doc.rs +++ b/tests/ui/missing_doc.rs @@ -1,5 +1,5 @@ // needs-asm-support -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![warn(clippy::missing_docs_in_private_items)] // When denying at the crate level, be sure to not get random warnings from the @@ -8,9 +8,9 @@ //! Some garbage docs for the crate here #![doc = "More garbage"] -extern crate proc_macro_with_span; +extern crate proc_macros; -use proc_macro_with_span::with_span; +use proc_macros::with_span; use std::arch::global_asm; type Typedef = String; diff --git a/tests/ui/missing_doc_impl.rs b/tests/ui/missing_doc_impl.rs index 0396d1193ff5..e2d49b0907d5 100644 --- a/tests/ui/missing_doc_impl.rs +++ b/tests/ui/missing_doc_impl.rs @@ -1,4 +1,4 @@ -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![warn(clippy::missing_docs_in_private_items)] #![allow(dead_code)] @@ -7,8 +7,8 @@ //! Some garbage docs for the crate here #![doc = "More garbage"] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; struct Foo { a: isize, diff --git a/tests/ui/mistyped_literal_suffix.fixed b/tests/ui/mistyped_literal_suffix.fixed index becb9562a849..9a47d7c56ed1 100644 --- a/tests/ui/mistyped_literal_suffix.fixed +++ b/tests/ui/mistyped_literal_suffix.fixed @@ -1,5 +1,5 @@ // run-rustfix -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![allow( dead_code, @@ -10,8 +10,8 @@ clippy::unusual_byte_groupings )] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; fn main() { let fail14 = 2_i32; diff --git a/tests/ui/mistyped_literal_suffix.rs b/tests/ui/mistyped_literal_suffix.rs index ee841bcd7e4e..04261cba55aa 100644 --- a/tests/ui/mistyped_literal_suffix.rs +++ b/tests/ui/mistyped_literal_suffix.rs @@ -1,5 +1,5 @@ // run-rustfix -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![allow( dead_code, @@ -10,8 +10,8 @@ clippy::unusual_byte_groupings )] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; fn main() { let fail14 = 2_32; diff --git a/tests/ui/multiple_unsafe_ops_per_block.rs b/tests/ui/multiple_unsafe_ops_per_block.rs index 5073685c9f06..9082f1675a87 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/tests/ui/multiple_unsafe_ops_per_block.rs @@ -1,12 +1,12 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![allow(unused)] #![allow(deref_nullptr)] #![allow(clippy::unnecessary_operation)] #![allow(clippy::drop_copy)] #![warn(clippy::multiple_unsafe_ops_per_block)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::external; use core::arch::asm; @@ -113,7 +113,10 @@ unsafe fn read_char_good(ptr: *const u8) -> char { // no lint fn issue10259() { - unsafe_macro!(); + external!(unsafe { + *core::ptr::null::<()>(); + *core::ptr::null::<()>(); + }); } fn _fn_ptr(x: unsafe fn()) { diff --git a/tests/ui/multiple_unsafe_ops_per_block.stderr b/tests/ui/multiple_unsafe_ops_per_block.stderr index e0c1d3801f7c..badc284ec423 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.stderr +++ b/tests/ui/multiple_unsafe_ops_per_block.stderr @@ -126,7 +126,7 @@ LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> $DIR/multiple_unsafe_ops_per_block.rs:120:5 + --> $DIR/multiple_unsafe_ops_per_block.rs:123:5 | LL | / unsafe { LL | | x(); @@ -135,18 +135,18 @@ LL | | } | |_____^ | note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:121:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:124:9 | LL | x(); | ^^^ note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:122:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:125:9 | LL | x(); | ^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> $DIR/multiple_unsafe_ops_per_block.rs:131:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:134:9 | LL | / unsafe { LL | | T::X(); @@ -155,18 +155,18 @@ LL | | } | |_________^ | note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:132:13 + --> $DIR/multiple_unsafe_ops_per_block.rs:135:13 | LL | T::X(); | ^^^^^^ note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:133:13 + --> $DIR/multiple_unsafe_ops_per_block.rs:136:13 | LL | T::X(); | ^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> $DIR/multiple_unsafe_ops_per_block.rs:141:5 + --> $DIR/multiple_unsafe_ops_per_block.rs:144:5 | LL | / unsafe { LL | | x.0(); @@ -175,12 +175,12 @@ LL | | } | |_____^ | note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:142:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:145:9 | LL | x.0(); | ^^^^^ note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:143:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:146:9 | LL | x.0(); | ^^^^^ diff --git a/tests/ui/must_use_unit.fixed b/tests/ui/must_use_unit.fixed index 6c9aa434ac01..b7d375ff80e1 100644 --- a/tests/ui/must_use_unit.fixed +++ b/tests/ui/must_use_unit.fixed @@ -1,11 +1,11 @@ //run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::must_use_unit)] #![allow(clippy::unused_unit)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::external; pub fn must_use_default() {} @@ -22,5 +22,8 @@ fn main() { must_use_with_note(); // We should not lint in external macros - must_use_unit!(); + external!( + #[must_use] + fn foo() {} + ); } diff --git a/tests/ui/must_use_unit.rs b/tests/ui/must_use_unit.rs index 8a395dc284db..74d6b4ca865c 100644 --- a/tests/ui/must_use_unit.rs +++ b/tests/ui/must_use_unit.rs @@ -1,11 +1,11 @@ //run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::must_use_unit)] #![allow(clippy::unused_unit)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::external; #[must_use] pub fn must_use_default() {} @@ -22,5 +22,8 @@ fn main() { must_use_with_note(); // We should not lint in external macros - must_use_unit!(); + external!( + #[must_use] + fn foo() {} + ); } diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs index ee3a856566cc..06bb085442a7 100644 --- a/tests/ui/mut_mut.rs +++ b/tests/ui/mut_mut.rs @@ -1,10 +1,10 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::mut_mut)] #![allow(unused)] #![allow(clippy::no_effect, clippy::uninlined_format_args, clippy::unnecessary_operation)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; fn fun(x: &mut &mut u32) -> bool { **x > 0 @@ -21,6 +21,7 @@ macro_rules! mut_ptr { } #[allow(unused_mut, unused_variables)] +#[inline_macros] fn main() { let mut x = &mut &mut 1u32; { @@ -37,7 +38,7 @@ fn main() { ***y + **x; } - let mut z = mut_ptr!(&mut 3u32); + let mut z = inline!(&mut $(&mut 3u32)); } fn issue939() { @@ -55,7 +56,7 @@ fn issue939() { fn issue6922() { // do not lint from an external macro - mut_mut!(); + external!(let mut_mut_ty: &mut &mut u32 = &mut &mut 1u32;); } mod issue9035 { diff --git a/tests/ui/mut_mut.stderr b/tests/ui/mut_mut.stderr index 6820a85aa543..93b857eb2074 100644 --- a/tests/ui/mut_mut.stderr +++ b/tests/ui/mut_mut.stderr @@ -7,54 +7,51 @@ LL | fn fun(x: &mut &mut u32) -> bool { = note: `-D clippy::mut-mut` implied by `-D warnings` error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:25:17 + --> $DIR/mut_mut.rs:26:17 | LL | let mut x = &mut &mut 1u32; | ^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:19:9 + --> $DIR/mut_mut.rs:41:25 | -LL | &mut $p - | ^^^^^^^ -... -LL | let mut z = mut_ptr!(&mut 3u32); - | ------------------- in this macro invocation +LL | let mut z = inline!(&mut $(&mut 3u32)); + | ^ | - = note: this error originates in the macro `mut_ptr` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: this expression mutably borrows a mutable reference. Consider reborrowing - --> $DIR/mut_mut.rs:27:21 + --> $DIR/mut_mut.rs:28:21 | LL | let mut y = &mut x; | ^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:31:32 + --> $DIR/mut_mut.rs:32:32 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:31:16 + --> $DIR/mut_mut.rs:32:16 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:36:37 + --> $DIR/mut_mut.rs:37:37 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:36:16 + --> $DIR/mut_mut.rs:37:16 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:36:21 + --> $DIR/mut_mut.rs:37:21 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^ diff --git a/tests/ui/needless_late_init.fixed b/tests/ui/needless_late_init.fixed index 17f2227ba91c..86d899bb46c3 100644 --- a/tests/ui/needless_late_init.fixed +++ b/tests/ui/needless_late_init.fixed @@ -1,4 +1,5 @@ // run-rustfix +// aux-build:proc_macros.rs #![feature(let_chains)] #![allow(unused)] #![allow( @@ -10,6 +11,8 @@ clippy::uninlined_format_args )] +extern crate proc_macros; + use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::rc::Rc; @@ -138,6 +141,7 @@ const fn in_const() -> &'static str { a } +#[proc_macros::inline_macros] fn does_not_lint() { let z; if false { @@ -195,35 +199,27 @@ fn does_not_lint() { } y = 3; - macro_rules! assign { - ($i:ident) => { - $i = 1; - }; - } let x; - assign!(x); + inline!($x = 1;); let x; if true { - assign!(x); + inline!($x = 1;); } else { x = 2; } - macro_rules! in_macro { - () => { - let x; - x = 1; + inline!({ + let x; + x = 1; - let x; - if true { - x = 1; - } else { - x = 2; - } - }; - } - in_macro!(); + let x; + if true { + x = 1; + } else { + x = 2; + } + }); // ignore if-lets - https://github.com/rust-lang/rust-clippy/issues/8613 let x; diff --git a/tests/ui/needless_late_init.rs b/tests/ui/needless_late_init.rs index d84457a29875..969afb38edf2 100644 --- a/tests/ui/needless_late_init.rs +++ b/tests/ui/needless_late_init.rs @@ -1,4 +1,5 @@ // run-rustfix +// aux-build:proc_macros.rs #![feature(let_chains)] #![allow(unused)] #![allow( @@ -10,6 +11,8 @@ clippy::uninlined_format_args )] +extern crate proc_macros; + use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::rc::Rc; @@ -138,6 +141,7 @@ const fn in_const() -> &'static str { a } +#[proc_macros::inline_macros] fn does_not_lint() { let z; if false { @@ -195,35 +199,27 @@ fn does_not_lint() { } y = 3; - macro_rules! assign { - ($i:ident) => { - $i = 1; - }; - } let x; - assign!(x); + inline!($x = 1;); let x; if true { - assign!(x); + inline!($x = 1;); } else { x = 2; } - macro_rules! in_macro { - () => { - let x; - x = 1; + inline!({ + let x; + x = 1; - let x; - if true { - x = 1; - } else { - x = 2; - } - }; - } - in_macro!(); + let x; + if true { + x = 1; + } else { + x = 2; + } + }); // ignore if-lets - https://github.com/rust-lang/rust-clippy/issues/8613 let x; diff --git a/tests/ui/needless_late_init.stderr b/tests/ui/needless_late_init.stderr index 0a256fb4a131..eff782f8bf10 100644 --- a/tests/ui/needless_late_init.stderr +++ b/tests/ui/needless_late_init.stderr @@ -1,5 +1,5 @@ error: unneeded late initialization - --> $DIR/needless_late_init.rs:24:5 + --> $DIR/needless_late_init.rs:27:5 | LL | let a; | ^^^^^^ created here @@ -13,7 +13,7 @@ LL | let a = "zero"; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:27:5 + --> $DIR/needless_late_init.rs:30:5 | LL | let b; | ^^^^^^ created here @@ -27,7 +27,7 @@ LL | let b = 1; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:28:5 + --> $DIR/needless_late_init.rs:31:5 | LL | let c; | ^^^^^^ created here @@ -41,7 +41,7 @@ LL | let c = 2; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:32:5 + --> $DIR/needless_late_init.rs:35:5 | LL | let d: usize; | ^^^^^^^^^^^^^ created here @@ -54,7 +54,7 @@ LL | let d: usize = 1; | ~~~~~~~~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:35:5 + --> $DIR/needless_late_init.rs:38:5 | LL | let e; | ^^^^^^ created here @@ -67,7 +67,7 @@ LL | let e = format!("{}", d); | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:40:5 + --> $DIR/needless_late_init.rs:43:5 | LL | let a; | ^^^^^^ @@ -88,7 +88,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:49:5 + --> $DIR/needless_late_init.rs:52:5 | LL | let b; | ^^^^^^ @@ -109,7 +109,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:56:5 + --> $DIR/needless_late_init.rs:59:5 | LL | let d; | ^^^^^^ @@ -130,7 +130,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:64:5 + --> $DIR/needless_late_init.rs:67:5 | LL | let e; | ^^^^^^ @@ -151,7 +151,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:71:5 + --> $DIR/needless_late_init.rs:74:5 | LL | let f; | ^^^^^^ @@ -167,7 +167,7 @@ LL + 1 => "three", | error: unneeded late initialization - --> $DIR/needless_late_init.rs:77:5 + --> $DIR/needless_late_init.rs:80:5 | LL | let g: usize; | ^^^^^^^^^^^^^ @@ -187,7 +187,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:85:5 + --> $DIR/needless_late_init.rs:88:5 | LL | let x; | ^^^^^^ created here @@ -201,7 +201,7 @@ LL | let x = 1; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:89:5 + --> $DIR/needless_late_init.rs:92:5 | LL | let x; | ^^^^^^ created here @@ -215,7 +215,7 @@ LL | let x = SignificantDrop; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:93:5 + --> $DIR/needless_late_init.rs:96:5 | LL | let x; | ^^^^^^ created here @@ -229,7 +229,7 @@ LL | let x = SignificantDrop; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:112:5 + --> $DIR/needless_late_init.rs:115:5 | LL | let a; | ^^^^^^ @@ -250,7 +250,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:129:5 + --> $DIR/needless_late_init.rs:132:5 | LL | let a; | ^^^^^^ diff --git a/tests/ui/needless_lifetimes.fixed b/tests/ui/needless_lifetimes.fixed index f0f1f9298ac6..e6ead69d148e 100644 --- a/tests/ui/needless_lifetimes.fixed +++ b/tests/ui/needless_lifetimes.fixed @@ -1,5 +1,5 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::needless_lifetimes)] #![allow( @@ -12,8 +12,8 @@ clippy::get_first )] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::inline_macros; fn distinct_lifetimes(_x: &u8, _y: &u8, _z: u8) {} @@ -502,30 +502,29 @@ mod pr_9743_output_lifetime_checks { } } +#[inline_macros] mod in_macro { - macro_rules! local_one_input_macro { - () => { - fn one_input(x: &u8) -> &u8 { - unimplemented!() - } - }; - } + use proc_macros::external; // lint local macro expands to function with needless lifetimes - local_one_input_macro!(); - - // no lint on external macro - macro_rules::needless_lifetime!(); - - macro_rules! expanded_lifetime { - ($l:lifetime) => { - fn f<$l>(arg: &$l str) -> &$l str { - arg - } + inline! { + fn one_input(x: &u8) -> &u8 { + unimplemented!() } } - expanded_lifetime!('a); + // no lint on external macro + external! { + fn needless_lifetime<'a>(x: &'a u8) -> &'a u8 { + unimplemented!() + } + } + + inline! { + fn f<$'a>(arg: &$'a str) -> &$'a str { + arg + } + } } mod issue5787 { diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index ddfd10430038..06eb430506f9 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -1,5 +1,5 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::needless_lifetimes)] #![allow( @@ -12,8 +12,8 @@ clippy::get_first )] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::inline_macros; fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} @@ -502,30 +502,29 @@ mod pr_9743_output_lifetime_checks { } } +#[inline_macros] mod in_macro { - macro_rules! local_one_input_macro { - () => { - fn one_input<'a>(x: &'a u8) -> &'a u8 { - unimplemented!() - } - }; - } + use proc_macros::external; // lint local macro expands to function with needless lifetimes - local_one_input_macro!(); - - // no lint on external macro - macro_rules::needless_lifetime!(); - - macro_rules! expanded_lifetime { - ($l:lifetime) => { - fn f<$l>(arg: &$l str) -> &$l str { - arg - } + inline! { + fn one_input<'a>(x: &'a u8) -> &'a u8 { + unimplemented!() } } - expanded_lifetime!('a); + // no lint on external macro + external! { + fn needless_lifetime<'a>(x: &'a u8) -> &'a u8 { + unimplemented!() + } + } + + inline! { + fn f<$'a>(arg: &$'a str) -> &$'a str { + arg + } + } } mod issue5787 { diff --git a/tests/ui/needless_lifetimes.stderr b/tests/ui/needless_lifetimes.stderr index 4e3c8f20d8c5..86acc4e00469 100644 --- a/tests/ui/needless_lifetimes.stderr +++ b/tests/ui/needless_lifetimes.stderr @@ -540,19 +540,16 @@ LL + fn multiple_inputs_output_not_elided<'b>(x: &u8, y: &'b u8, z: &'b u8) | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:508:13 + --> $DIR/needless_lifetimes.rs:511:9 | -LL | fn one_input<'a>(x: &'a u8) -> &'a u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | local_one_input_macro!(); - | ------------------------ in this macro invocation +LL | fn one_input<'a>(x: &'a u8) -> &'a u8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: this error originates in the macro `local_one_input_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_mod_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info) help: elide the lifetimes | -LL - fn one_input<'a>(x: &'a u8) -> &'a u8 { -LL + fn one_input(x: &u8) -> &u8 { +LL - fn one_input<'a>(x: &'a u8) -> &'a u8 { +LL + fn one_input(x: &u8) -> &u8 { | error: aborting due to 46 previous errors diff --git a/tests/ui/needless_update.rs b/tests/ui/needless_update.rs index b93ff048a62f..4e8517cad100 100644 --- a/tests/ui/needless_update.rs +++ b/tests/ui/needless_update.rs @@ -1,5 +1,5 @@ #![warn(clippy::needless_update)] -#![allow(clippy::no_effect)] +#![allow(clippy::no_effect, clippy::unnecessary_struct_initialization)] struct S { pub a: i32, diff --git a/tests/ui/no_effect.rs b/tests/ui/no_effect.rs index ec8a5aa28c59..1e42e1fbabfe 100644 --- a/tests/ui/no_effect.rs +++ b/tests/ui/no_effect.rs @@ -1,7 +1,12 @@ #![feature(fn_traits, unboxed_closures)] #![warn(clippy::no_effect_underscore_binding)] #![allow(dead_code, path_statements)] -#![allow(clippy::deref_addrof, clippy::redundant_field_names, clippy::uninlined_format_args)] +#![allow( + clippy::deref_addrof, + clippy::redundant_field_names, + clippy::uninlined_format_args, + clippy::unnecessary_struct_initialization +)] struct Unit; struct Tuple(i32); diff --git a/tests/ui/no_effect.stderr b/tests/ui/no_effect.stderr index 92f6dbfbdba1..f10f2bcf2a8a 100644 --- a/tests/ui/no_effect.stderr +++ b/tests/ui/no_effect.stderr @@ -1,5 +1,5 @@ error: statement with no effect - --> $DIR/no_effect.rs:92:5 + --> $DIR/no_effect.rs:97:5 | LL | 0; | ^^ @@ -7,151 +7,151 @@ LL | 0; = note: `-D clippy::no-effect` implied by `-D warnings` error: statement with no effect - --> $DIR/no_effect.rs:93:5 + --> $DIR/no_effect.rs:98:5 | LL | s2; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:94:5 + --> $DIR/no_effect.rs:99:5 | LL | Unit; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:95:5 + --> $DIR/no_effect.rs:100:5 | LL | Tuple(0); | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:96:5 + --> $DIR/no_effect.rs:101:5 | LL | Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:97:5 + --> $DIR/no_effect.rs:102:5 | LL | Struct { ..s }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:98:5 + --> $DIR/no_effect.rs:103:5 | LL | Union { a: 0 }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:99:5 + --> $DIR/no_effect.rs:104:5 | LL | Enum::Tuple(0); | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:100:5 + --> $DIR/no_effect.rs:105:5 | LL | Enum::Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:101:5 + --> $DIR/no_effect.rs:106:5 | LL | 5 + 6; | ^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:102:5 + --> $DIR/no_effect.rs:107:5 | LL | *&42; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:103:5 + --> $DIR/no_effect.rs:108:5 | LL | &6; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:104:5 + --> $DIR/no_effect.rs:109:5 | LL | (5, 6, 7); | ^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:105:5 + --> $DIR/no_effect.rs:110:5 | LL | ..; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:106:5 + --> $DIR/no_effect.rs:111:5 | LL | 5..; | ^^^^ error: statement with no effect - --> $DIR/no_effect.rs:107:5 + --> $DIR/no_effect.rs:112:5 | LL | ..5; | ^^^^ error: statement with no effect - --> $DIR/no_effect.rs:108:5 + --> $DIR/no_effect.rs:113:5 | LL | 5..6; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:109:5 + --> $DIR/no_effect.rs:114:5 | LL | 5..=6; | ^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:110:5 + --> $DIR/no_effect.rs:115:5 | LL | [42, 55]; | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:111:5 + --> $DIR/no_effect.rs:116:5 | LL | [42, 55][1]; | ^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:112:5 + --> $DIR/no_effect.rs:117:5 | LL | (42, 55).1; | ^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:113:5 + --> $DIR/no_effect.rs:118:5 | LL | [42; 55]; | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:114:5 + --> $DIR/no_effect.rs:119:5 | LL | [42; 55][13]; | ^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:116:5 + --> $DIR/no_effect.rs:121:5 | LL | || x += 5; | ^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:118:5 + --> $DIR/no_effect.rs:123:5 | LL | FooString { s: s }; | ^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:119:5 + --> $DIR/no_effect.rs:124:5 | LL | let _unused = 1; | ^^^^^^^^^^^^^^^^ @@ -159,19 +159,19 @@ LL | let _unused = 1; = note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings` error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:120:5 + --> $DIR/no_effect.rs:125:5 | LL | let _penguin = || println!("Some helpful closure"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:121:5 + --> $DIR/no_effect.rs:126:5 | LL | let _duck = Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:122:5 + --> $DIR/no_effect.rs:127:5 | LL | let _cat = [2, 4, 6, 8][2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/no_mangle_with_rust_abi.fixed b/tests/ui/no_mangle_with_rust_abi.fixed deleted file mode 100644 index d18dec22a8bb..000000000000 --- a/tests/ui/no_mangle_with_rust_abi.fixed +++ /dev/null @@ -1,48 +0,0 @@ -// run-rustfix - -#![allow(unused)] -#![warn(clippy::no_mangle_with_rust_abi)] - -#[no_mangle] -extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} - -#[no_mangle] -pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} - -/// # Safety -/// This function shouldn't be called unless the horsemen are ready -#[no_mangle] -pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} - -/// # Safety -/// This function shouldn't be called unless the horsemen are ready -#[no_mangle] -unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} - -#[no_mangle] -extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( - arg_one: u32, - arg_two: usize, -) -> u32 { - 0 -} - -// Must not run on functions that explicitly opt in to Rust ABI with `extern "Rust"` -#[no_mangle] -#[rustfmt::skip] -extern "Rust" fn rust_abi_fn_explicit_opt_in(arg_one: u32, arg_two: usize) {} - -fn rust_abi_fn_again(arg_one: u32, arg_two: usize) {} - -#[no_mangle] -extern "C" fn c_abi_fn(arg_one: u32, arg_two: usize) {} - -extern "C" fn c_abi_fn_again(arg_one: u32, arg_two: usize) {} - -extern "C" { - fn c_abi_in_block(arg_one: u32, arg_two: usize); -} - -fn main() { - // test code goes here -} diff --git a/tests/ui/no_mangle_with_rust_abi.rs b/tests/ui/no_mangle_with_rust_abi.rs index 481e1b6d9619..b32e721110e0 100644 --- a/tests/ui/no_mangle_with_rust_abi.rs +++ b/tests/ui/no_mangle_with_rust_abi.rs @@ -1,5 +1,3 @@ -// run-rustfix - #![allow(unused)] #![warn(clippy::no_mangle_with_rust_abi)] diff --git a/tests/ui/no_mangle_with_rust_abi.stderr b/tests/ui/no_mangle_with_rust_abi.stderr index 71517d318095..da5d31d8f2d4 100644 --- a/tests/ui/no_mangle_with_rust_abi.stderr +++ b/tests/ui/no_mangle_with_rust_abi.stderr @@ -1,31 +1,66 @@ -error: attribute #[no_mangle] set on a Rust ABI function - --> $DIR/no_mangle_with_rust_abi.rs:7:1 +error: `#[no_mangle]` set on a function with the default (`Rust`) ABI + --> $DIR/no_mangle_with_rust_abi.rs:5:1 | LL | fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::no-mangle-with-rust-abi` implied by `-D warnings` +help: set an ABI + | +LL | extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} + | ++++++++++ +help: or explicitly set the default + | +LL | extern "Rust" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} + | +++++++++++++ -error: attribute #[no_mangle] set on a Rust ABI function - --> $DIR/no_mangle_with_rust_abi.rs:10:1 +error: `#[no_mangle]` set on a function with the default (`Rust`) ABI + --> $DIR/no_mangle_with_rust_abi.rs:8:1 | LL | pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: set an ABI + | +LL | pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} + | ++++++++++ +help: or explicitly set the default + | +LL | pub extern "Rust" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} + | +++++++++++++ -error: attribute #[no_mangle] set on a Rust ABI function - --> $DIR/no_mangle_with_rust_abi.rs:15:1 +error: `#[no_mangle]` set on a function with the default (`Rust`) ABI + --> $DIR/no_mangle_with_rust_abi.rs:13:1 | LL | pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: set an ABI + | +LL | pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} + | ++++++++++ +help: or explicitly set the default + | +LL | pub unsafe extern "Rust" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} + | +++++++++++++ -error: attribute #[no_mangle] set on a Rust ABI function - --> $DIR/no_mangle_with_rust_abi.rs:20:1 +error: `#[no_mangle]` set on a function with the default (`Rust`) ABI + --> $DIR/no_mangle_with_rust_abi.rs:18:1 | LL | unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: set an ABI + | +LL | unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} + | ++++++++++ +help: or explicitly set the default + | +LL | unsafe extern "Rust" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} + | +++++++++++++ -error: attribute #[no_mangle] set on a Rust ABI function - --> $DIR/no_mangle_with_rust_abi.rs:23:1 +error: `#[no_mangle]` set on a function with the default (`Rust`) ABI + --> $DIR/no_mangle_with_rust_abi.rs:21:1 | LL | / fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( LL | | arg_one: u32, @@ -33,13 +68,14 @@ LL | | arg_two: usize, LL | | ) -> u32 { | |________^ | -help: try +help: set an ABI | -LL + extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( -LL + arg_one: u32, -LL + arg_two: usize, -LL ~ ) -> u32 { +LL | extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( + | ++++++++++ +help: or explicitly set the default | +LL | extern "Rust" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( + | +++++++++++++ error: aborting due to 5 previous errors diff --git a/tests/ui/nonminimal_bool.rs b/tests/ui/nonminimal_bool.rs index e9b4367ca653..3b5a374b4a7b 100644 --- a/tests/ui/nonminimal_bool.rs +++ b/tests/ui/nonminimal_bool.rs @@ -63,3 +63,32 @@ fn issue9428() { println!("foo"); } } + +fn issue_10523() { + macro_rules! a { + ($v:expr) => { + $v.is_some() + }; + } + let x: Option = None; + if !a!(x) {} +} + +fn issue_10523_1() { + macro_rules! a { + ($v:expr) => { + !$v.is_some() + }; + } + let x: Option = None; + if a!(x) {} +} + +fn issue_10523_2() { + macro_rules! a { + () => { + !None::.is_some() + }; + } + if a!() {} +} diff --git a/tests/ui/option_env_unwrap.rs b/tests/ui/option_env_unwrap.rs index 0141fb7856d0..9a56cf40d8a7 100644 --- a/tests/ui/option_env_unwrap.rs +++ b/tests/ui/option_env_unwrap.rs @@ -1,24 +1,16 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::option_env_unwrap)] #![allow(clippy::map_flatten)] -#[macro_use] -extern crate macro_rules; - -macro_rules! option_env_unwrap { - ($env: expr) => { - option_env!($env).unwrap() - }; - ($env: expr, $message: expr) => { - option_env!($env).expect($message) - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { let _ = option_env!("PATH").unwrap(); let _ = option_env!("PATH").expect("environment variable PATH isn't set"); - let _ = option_env_unwrap!("PATH"); - let _ = option_env_unwrap!("PATH", "environment variable PATH isn't set"); - let _ = option_env_unwrap_external!("PATH"); - let _ = option_env_unwrap_external!("PATH", "environment variable PATH isn't set"); + let _ = inline!(option_env!($"PATH").unwrap()); + let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set")); + let _ = external!(option_env!($"PATH").unwrap()); + let _ = external!(option_env!($"PATH").expect($"environment variable PATH isn't set")); } diff --git a/tests/ui/option_env_unwrap.stderr b/tests/ui/option_env_unwrap.stderr index bc188a07e9e0..7bba62686eec 100644 --- a/tests/ui/option_env_unwrap.stderr +++ b/tests/ui/option_env_unwrap.stderr @@ -1,5 +1,5 @@ error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:18:13 + --> $DIR/option_env_unwrap.rs:10:13 | LL | let _ = option_env!("PATH").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let _ = option_env!("PATH").unwrap(); = note: `-D clippy::option-env-unwrap` implied by `-D warnings` error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:19:13 + --> $DIR/option_env_unwrap.rs:11:13 | LL | let _ = option_env!("PATH").expect("environment variable PATH isn't set"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,46 +16,40 @@ LL | let _ = option_env!("PATH").expect("environment variable PATH isn't set = help: consider using the `env!` macro instead error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:10:9 + --> $DIR/option_env_unwrap.rs:12:21 | -LL | option_env!($env).unwrap() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | let _ = option_env_unwrap!("PATH"); - | -------------------------- in this macro invocation +LL | let _ = inline!(option_env!($"PATH").unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using the `env!` macro instead - = note: this error originates in the macro `option_env_unwrap` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:13:9 + --> $DIR/option_env_unwrap.rs:13:21 | -LL | option_env!($env).expect($message) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | let _ = option_env_unwrap!("PATH", "environment variable PATH isn't set"); - | ----------------------------------------------------------------- in this macro invocation +LL | let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using the `env!` macro instead - = note: this error originates in the macro `option_env_unwrap` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:22:13 + --> $DIR/option_env_unwrap.rs:14:13 | -LL | let _ = option_env_unwrap_external!("PATH"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _ = external!(option_env!($"PATH").unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using the `env!` macro instead - = note: this error originates in the macro `option_env_unwrap_external` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info) error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:23:13 + --> $DIR/option_env_unwrap.rs:15:13 | -LL | let _ = option_env_unwrap_external!("PATH", "environment variable PATH isn't set"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _ = external!(option_env!($"PATH").expect($"environment variable PATH isn't set")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using the `env!` macro instead - = note: this error originates in the macro `option_env_unwrap_external` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 6 previous errors diff --git a/tests/ui/ptr_as_ptr.fixed b/tests/ui/ptr_as_ptr.fixed index df36a9b842bf..ee7b998a0b2f 100644 --- a/tests/ui/ptr_as_ptr.fixed +++ b/tests/ui/ptr_as_ptr.fixed @@ -1,16 +1,12 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::ptr_as_ptr)] -extern crate macro_rules; - -macro_rules! cast_it { - ($ptr: ident) => { - $ptr.cast::() - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { let ptr: *const u32 = &42_u32; let mut_ptr: *mut u32 = &mut 42_u32; @@ -38,10 +34,10 @@ fn main() { let _: *mut i32 = mut_ptr.cast(); // Make sure the lint is triggered inside a macro - let _ = cast_it!(ptr); + let _ = inline!($ptr.cast::()); // Do not lint inside macros from external crates - let _ = macro_rules::ptr_as_ptr_cast!(ptr); + let _ = external!($ptr as *const i32); } #[clippy::msrv = "1.37"] diff --git a/tests/ui/ptr_as_ptr.rs b/tests/ui/ptr_as_ptr.rs index 302c66462d9b..c88329ce4ecc 100644 --- a/tests/ui/ptr_as_ptr.rs +++ b/tests/ui/ptr_as_ptr.rs @@ -1,16 +1,12 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::ptr_as_ptr)] -extern crate macro_rules; - -macro_rules! cast_it { - ($ptr: ident) => { - $ptr as *const i32 - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { let ptr: *const u32 = &42_u32; let mut_ptr: *mut u32 = &mut 42_u32; @@ -38,10 +34,10 @@ fn main() { let _: *mut i32 = mut_ptr as _; // Make sure the lint is triggered inside a macro - let _ = cast_it!(ptr); + let _ = inline!($ptr as *const i32); // Do not lint inside macros from external crates - let _ = macro_rules::ptr_as_ptr_cast!(ptr); + let _ = external!($ptr as *const i32); } #[clippy::msrv = "1.37"] diff --git a/tests/ui/ptr_as_ptr.stderr b/tests/ui/ptr_as_ptr.stderr index a68e1cab6d35..78d733994ac6 100644 --- a/tests/ui/ptr_as_ptr.stderr +++ b/tests/ui/ptr_as_ptr.stderr @@ -1,5 +1,5 @@ error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:18:13 + --> $DIR/ptr_as_ptr.rs:14:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` @@ -7,48 +7,45 @@ LL | let _ = ptr as *const i32; = note: `-D clippy::ptr-as-ptr` implied by `-D warnings` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:19:13 + --> $DIR/ptr_as_ptr.rs:15: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 - --> $DIR/ptr_as_ptr.rs:24:17 + --> $DIR/ptr_as_ptr.rs:20: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 - --> $DIR/ptr_as_ptr.rs:37:25 + --> $DIR/ptr_as_ptr.rs:33: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 - --> $DIR/ptr_as_ptr.rs:38:23 + --> $DIR/ptr_as_ptr.rs:34: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 - --> $DIR/ptr_as_ptr.rs:10:9 + --> $DIR/ptr_as_ptr.rs:37:21 | -LL | $ptr as *const i32 - | ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::()` -... -LL | let _ = cast_it!(ptr); - | ------------- in this macro invocation +LL | let _ = inline!($ptr as *const i32); + | ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::()` | - = note: this error originates in the macro `cast_it` (in Nightly builds, run with -Z macro-backtrace for more info) + = 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 - --> $DIR/ptr_as_ptr.rs:62:13 + --> $DIR/ptr_as_ptr.rs:58: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 - --> $DIR/ptr_as_ptr.rs:63:13 + --> $DIR/ptr_as_ptr.rs:59:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` diff --git a/tests/ui/redundant_async_block.fixed b/tests/ui/redundant_async_block.fixed index 5f9931df45e9..d26b7a332cbb 100644 --- a/tests/ui/redundant_async_block.fixed +++ b/tests/ui/redundant_async_block.fixed @@ -3,6 +3,8 @@ #![allow(unused)] #![warn(clippy::redundant_async_block)] +use std::future::Future; + async fn func1(n: usize) -> usize { n + 1 } @@ -62,3 +64,48 @@ fn main() { let fut = async_await_parameter_in_macro!(func2()); let fut = async_await_in_macro!(std::convert::identity); } + +#[allow(clippy::let_and_return)] +fn capture_local() -> impl Future { + // Lint + let fut = async { 17 }; + fut +} + +fn capture_local_closure(s: &str) -> impl Future { + let f = move || std::future::ready(s); + // Do not lint: `f` would not live long enough + async move { f().await } +} + +#[allow(clippy::let_and_return)] +fn capture_arg(s: &str) -> impl Future { + // Lint + let fut = async move { s }; + fut +} + +#[derive(Debug, Clone)] +struct F {} + +impl F { + async fn run(&self) {} +} + +pub async fn run() { + let f = F {}; + let c = f.clone(); + // Do not lint: `c` would not live long enough + spawn(async move { c.run().await }); + let _f = f; +} + +fn spawn(_: F) {} + +async fn work(_: &str) {} + +fn capture() { + let val = "Hello World".to_owned(); + // Do not lint: `val` would not live long enough + spawn(async { work(&{ val }).await }); +} diff --git a/tests/ui/redundant_async_block.rs b/tests/ui/redundant_async_block.rs index de3c9970c65f..04726e628050 100644 --- a/tests/ui/redundant_async_block.rs +++ b/tests/ui/redundant_async_block.rs @@ -3,6 +3,8 @@ #![allow(unused)] #![warn(clippy::redundant_async_block)] +use std::future::Future; + async fn func1(n: usize) -> usize { n + 1 } @@ -62,3 +64,48 @@ fn main() { let fut = async_await_parameter_in_macro!(func2()); let fut = async_await_in_macro!(std::convert::identity); } + +#[allow(clippy::let_and_return)] +fn capture_local() -> impl Future { + // Lint + let fut = async { 17 }; + async move { fut.await } +} + +fn capture_local_closure(s: &str) -> impl Future { + let f = move || std::future::ready(s); + // Do not lint: `f` would not live long enough + async move { f().await } +} + +#[allow(clippy::let_and_return)] +fn capture_arg(s: &str) -> impl Future { + // Lint + let fut = async move { s }; + async move { fut.await } +} + +#[derive(Debug, Clone)] +struct F {} + +impl F { + async fn run(&self) {} +} + +pub async fn run() { + let f = F {}; + let c = f.clone(); + // Do not lint: `c` would not live long enough + spawn(async move { c.run().await }); + let _f = f; +} + +fn spawn(_: F) {} + +async fn work(_: &str) {} + +fn capture() { + let val = "Hello World".to_owned(); + // Do not lint: `val` would not live long enough + spawn(async { work(&{ val }).await }); +} diff --git a/tests/ui/redundant_async_block.stderr b/tests/ui/redundant_async_block.stderr index b16d96dce84e..1a1c1603e080 100644 --- a/tests/ui/redundant_async_block.stderr +++ b/tests/ui/redundant_async_block.stderr @@ -1,5 +1,5 @@ error: this async expression only awaits a single future - --> $DIR/redundant_async_block.rs:13:13 + --> $DIR/redundant_async_block.rs:15:13 | LL | let x = async { f.await }; | ^^^^^^^^^^^^^^^^^ help: you can reduce it to: `f` @@ -7,22 +7,34 @@ LL | let x = async { f.await }; = note: `-D clippy::redundant-async-block` implied by `-D warnings` error: this async expression only awaits a single future - --> $DIR/redundant_async_block.rs:46:16 + --> $DIR/redundant_async_block.rs:48:16 | LL | let fut2 = async { fut1.await }; | ^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut1` error: this async expression only awaits a single future - --> $DIR/redundant_async_block.rs:49:16 + --> $DIR/redundant_async_block.rs:51:16 | LL | let fut2 = async move { fut1.await }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut1` error: this async expression only awaits a single future - --> $DIR/redundant_async_block.rs:51:15 + --> $DIR/redundant_async_block.rs:53:15 | LL | let fut = async { async { 42 }.await }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `async { 42 }` -error: aborting due to 4 previous errors +error: this async expression only awaits a single future + --> $DIR/redundant_async_block.rs:72:5 + | +LL | async move { fut.await } + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut` + +error: this async expression only awaits a single future + --> $DIR/redundant_async_block.rs:85:5 + | +LL | async move { fut.await } + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut` + +error: aborting due to 6 previous errors diff --git a/tests/ui/redundant_pattern_matching_result.fixed b/tests/ui/redundant_pattern_matching_result.fixed index b88c5d0bec82..42348df4480b 100644 --- a/tests/ui/redundant_pattern_matching_result.fixed +++ b/tests/ui/redundant_pattern_matching_result.fixed @@ -69,8 +69,8 @@ fn issue5504() { } fn try_result_opt() -> Result { - while (r#try!(result_opt())).is_some() {} - if (r#try!(result_opt())).is_some() {} + while r#try!(result_opt()).is_some() {} + if r#try!(result_opt()).is_some() {} Ok(42) } diff --git a/tests/ui/redundant_pattern_matching_result.stderr b/tests/ui/redundant_pattern_matching_result.stderr index e6afe9eb78ea..d6a46babb779 100644 --- a/tests/ui/redundant_pattern_matching_result.stderr +++ b/tests/ui/redundant_pattern_matching_result.stderr @@ -88,13 +88,13 @@ error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:84:19 | LL | while let Some(_) = r#try!(result_opt()) {} - | ----------^^^^^^^----------------------- help: try this: `while (r#try!(result_opt())).is_some()` + | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:85:16 | LL | if let Some(_) = r#try!(result_opt()) {} - | -------^^^^^^^----------------------- help: try this: `if (r#try!(result_opt())).is_some()` + | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:91:12 diff --git a/tests/ui/single_match_else.rs b/tests/ui/single_match_else.rs index 5d03f77e9326..3c86f41f3a6e 100644 --- a/tests/ui/single_match_else.rs +++ b/tests/ui/single_match_else.rs @@ -1,9 +1,9 @@ -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![warn(clippy::single_match_else)] #![allow(clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; enum ExprNode { ExprAddrOf, diff --git a/tests/ui/string_add.rs b/tests/ui/string_add.rs index 16673c01e630..20edbe31fa9e 100644 --- a/tests/ui/string_add.rs +++ b/tests/ui/string_add.rs @@ -1,7 +1,7 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::external; #[warn(clippy::string_add)] #[allow(clippy::string_add_assign, unused)] @@ -22,5 +22,8 @@ fn main() { x = x + 1; assert_eq!(2, x); - string_add!(); + external!({ + let y = "".to_owned(); + let z = y + "..."; + }); } diff --git a/tests/ui/swap.fixed b/tests/ui/swap.fixed index 04008c0d9b31..9703674d1a4e 100644 --- a/tests/ui/swap.fixed +++ b/tests/ui/swap.fixed @@ -1,4 +1,5 @@ // run-rustfix +// aux-build: macro_rules.rs #![warn(clippy::all)] #![allow( @@ -8,7 +9,8 @@ redundant_semicolons, dead_code, unused_assignments, - unused_variables + unused_variables, + clippy::let_and_return )] struct Foo(u32); @@ -186,3 +188,14 @@ const fn issue_9864(mut u: u32) -> u32 { v = temp; u + v } + +#[macro_use] +extern crate macro_rules; + +const fn issue_10421(x: u32) -> u32 { + issue_10421!(); + let a = x; + let a = a; + let a = a; + a +} diff --git a/tests/ui/swap.rs b/tests/ui/swap.rs index ef8a81c8341b..a0228065e46b 100644 --- a/tests/ui/swap.rs +++ b/tests/ui/swap.rs @@ -1,4 +1,5 @@ // run-rustfix +// aux-build: macro_rules.rs #![warn(clippy::all)] #![allow( @@ -8,7 +9,8 @@ redundant_semicolons, dead_code, unused_assignments, - unused_variables + unused_variables, + clippy::let_and_return )] struct Foo(u32); @@ -215,3 +217,14 @@ const fn issue_9864(mut u: u32) -> u32 { v = temp; u + v } + +#[macro_use] +extern crate macro_rules; + +const fn issue_10421(x: u32) -> u32 { + issue_10421!(); + let a = x; + let a = a; + let a = a; + a +} diff --git a/tests/ui/swap.stderr b/tests/ui/swap.stderr index 825c9261e198..0c246268499d 100644 --- a/tests/ui/swap.stderr +++ b/tests/ui/swap.stderr @@ -1,5 +1,5 @@ error: this looks like you are swapping `bar.a` and `bar.b` manually - --> $DIR/swap.rs:25:5 + --> $DIR/swap.rs:27:5 | LL | / let temp = bar.a; LL | | bar.a = bar.b; @@ -10,7 +10,7 @@ LL | | bar.b = temp; = note: `-D clippy::manual-swap` implied by `-D warnings` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:37:5 + --> $DIR/swap.rs:39:5 | LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; @@ -18,7 +18,7 @@ LL | | foo[1] = temp; | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:46:5 + --> $DIR/swap.rs:48:5 | LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; @@ -26,7 +26,7 @@ LL | | foo[1] = temp; | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:65:5 + --> $DIR/swap.rs:67:5 | LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; @@ -34,7 +34,7 @@ LL | | foo[1] = temp; | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping `a` and `b` manually - --> $DIR/swap.rs:76:5 + --> $DIR/swap.rs:78:5 | LL | / a ^= b; LL | | b ^= a; @@ -42,7 +42,7 @@ LL | | a ^= b; | |___________^ help: try: `std::mem::swap(&mut a, &mut b);` error: this looks like you are swapping `bar.a` and `bar.b` manually - --> $DIR/swap.rs:84:5 + --> $DIR/swap.rs:86:5 | LL | / bar.a ^= bar.b; LL | | bar.b ^= bar.a; @@ -50,7 +50,7 @@ LL | | bar.a ^= bar.b; | |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b);` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:92:5 + --> $DIR/swap.rs:94:5 | LL | / foo[0] ^= foo[1]; LL | | foo[1] ^= foo[0]; @@ -58,7 +58,7 @@ LL | | foo[0] ^= foo[1]; | |_____________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually - --> $DIR/swap.rs:121:5 + --> $DIR/swap.rs:123:5 | LL | / let temp = foo[0][1]; LL | | foo[0][1] = bar[1][0]; @@ -68,7 +68,7 @@ LL | | bar[1][0] = temp; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `a` and `b` manually - --> $DIR/swap.rs:135:7 + --> $DIR/swap.rs:137:7 | LL | ; let t = a; | _______^ @@ -79,7 +79,7 @@ LL | | b = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `c.0` and `a` manually - --> $DIR/swap.rs:144:7 + --> $DIR/swap.rs:146:7 | LL | ; let t = c.0; | _______^ @@ -90,7 +90,7 @@ LL | | a = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `b` and `a` manually - --> $DIR/swap.rs:170:5 + --> $DIR/swap.rs:172:5 | LL | / let t = b; LL | | b = a; @@ -100,7 +100,7 @@ LL | | a = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> $DIR/swap.rs:132:5 + --> $DIR/swap.rs:134:5 | LL | / a = b; LL | | b = a; @@ -110,7 +110,7 @@ LL | | b = a; = note: `-D clippy::almost-swapped` implied by `-D warnings` error: this looks like you are trying to swap `c.0` and `a` - --> $DIR/swap.rs:141:5 + --> $DIR/swap.rs:143:5 | LL | / c.0 = a; LL | | a = c.0; @@ -119,7 +119,7 @@ LL | | a = c.0; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> $DIR/swap.rs:148:5 + --> $DIR/swap.rs:150:5 | LL | / let a = b; LL | | let b = a; @@ -128,7 +128,7 @@ LL | | let b = a; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `d` and `c` - --> $DIR/swap.rs:153:5 + --> $DIR/swap.rs:155:5 | LL | / d = c; LL | | c = d; @@ -137,7 +137,7 @@ LL | | c = d; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> $DIR/swap.rs:157:5 + --> $DIR/swap.rs:159:5 | LL | / let a = b; LL | | b = a; @@ -146,7 +146,7 @@ LL | | b = a; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `s.0.x` and `s.0.y` manually - --> $DIR/swap.rs:205:5 + --> $DIR/swap.rs:207:5 | LL | / let t = s.0.x; LL | | s.0.x = s.0.y; diff --git a/tests/ui/toplevel_ref_arg.fixed b/tests/ui/toplevel_ref_arg.fixed index 09fb66ca37e0..174c858a47d1 100644 --- a/tests/ui/toplevel_ref_arg.fixed +++ b/tests/ui/toplevel_ref_arg.fixed @@ -1,17 +1,12 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::toplevel_ref_arg)] -#![allow(clippy::uninlined_format_args)] +#![allow(clippy::uninlined_format_args, unused)] -#[macro_use] -extern crate macro_rules; - -macro_rules! gen_binding { - () => { - let _y = &42; - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { // Closures should not warn let y = |ref x| println!("{:?}", x); @@ -38,13 +33,8 @@ fn main() { for ref _x in 0..10 {} // lint in macro - #[allow(unused)] - { - gen_binding!(); - } + inline!(let _y = &42;); // do not lint in external macro - { - ref_arg_binding!(); - } + external!(let ref _y = 42;); } diff --git a/tests/ui/toplevel_ref_arg.rs b/tests/ui/toplevel_ref_arg.rs index 9d1f2f810983..4b81a06112fe 100644 --- a/tests/ui/toplevel_ref_arg.rs +++ b/tests/ui/toplevel_ref_arg.rs @@ -1,17 +1,12 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::toplevel_ref_arg)] -#![allow(clippy::uninlined_format_args)] +#![allow(clippy::uninlined_format_args, unused)] -#[macro_use] -extern crate macro_rules; - -macro_rules! gen_binding { - () => { - let ref _y = 42; - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { // Closures should not warn let y = |ref x| println!("{:?}", x); @@ -38,13 +33,8 @@ fn main() { for ref _x in 0..10 {} // lint in macro - #[allow(unused)] - { - gen_binding!(); - } + inline!(let ref _y = 42;); // do not lint in external macro - { - ref_arg_binding!(); - } + external!(let ref _y = 42;); } diff --git a/tests/ui/toplevel_ref_arg.stderr b/tests/ui/toplevel_ref_arg.stderr index 9c853020ab01..407c2d9fcd33 100644 --- a/tests/ui/toplevel_ref_arg.stderr +++ b/tests/ui/toplevel_ref_arg.stderr @@ -1,5 +1,5 @@ error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:20:9 + --> $DIR/toplevel_ref_arg.rs:15:9 | LL | let ref _x = 1; | ----^^^^^^----- help: try: `let _x = &1;` @@ -7,39 +7,36 @@ LL | let ref _x = 1; = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:22:9 + --> $DIR/toplevel_ref_arg.rs:17:9 | LL | let ref _y: (&_, u8) = (&1, 2); | ----^^^^^^--------------------- help: try: `let _y: &(&_, u8) = &(&1, 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:24:9 + --> $DIR/toplevel_ref_arg.rs:19:9 | LL | let ref _z = 1 + 2; | ----^^^^^^--------- help: try: `let _z = &(1 + 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:26:9 + --> $DIR/toplevel_ref_arg.rs:21:9 | LL | let ref mut _z = 1 + 2; | ----^^^^^^^^^^--------- help: try: `let _z = &mut (1 + 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:31:9 + --> $DIR/toplevel_ref_arg.rs:26:9 | LL | let ref _x = vec![1, 2, 3]; | ----^^^^^^----------------- help: try: `let _x = &vec![1, 2, 3];` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:11:13 + --> $DIR/toplevel_ref_arg.rs:36:17 | -LL | let ref _y = 42; - | ----^^^^^^------ help: try: `let _y = &42;` -... -LL | gen_binding!(); - | -------------- in this macro invocation +LL | inline!(let ref _y = 42;); + | ----^^^^^^------ help: try: `let _y = &42;` | - = note: this error originates in the macro `gen_binding` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 6 previous errors diff --git a/tests/ui/toplevel_ref_arg_non_rustfix.rs b/tests/ui/toplevel_ref_arg_non_rustfix.rs index 1a493fbce0ef..2047593e7e4b 100644 --- a/tests/ui/toplevel_ref_arg_non_rustfix.rs +++ b/tests/ui/toplevel_ref_arg_non_rustfix.rs @@ -1,33 +1,27 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::toplevel_ref_arg)] #![allow(unused)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; fn the_answer(ref mut x: u8) { *x = 42; } -macro_rules! gen_function { - () => { - fn fun_example(ref _x: usize) {} - }; -} - +#[inline_macros] fn main() { let mut x = 0; the_answer(x); // lint in macro - #[allow(unused)] - { - gen_function!(); + inline! { + fn fun_example(ref _x: usize) {} } // do not lint in external macro - { - ref_arg_function!(); + external! { + fn fun_example2(ref _x: usize) {} } } diff --git a/tests/ui/toplevel_ref_arg_non_rustfix.stderr b/tests/ui/toplevel_ref_arg_non_rustfix.stderr index e97011c7fd51..7307bd599d9b 100644 --- a/tests/ui/toplevel_ref_arg_non_rustfix.stderr +++ b/tests/ui/toplevel_ref_arg_non_rustfix.stderr @@ -7,15 +7,12 @@ LL | fn the_answer(ref mut x: u8) { = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings` error: `ref` directly on a function argument is ignored. Consider using a reference type instead - --> $DIR/toplevel_ref_arg_non_rustfix.rs:15:24 + --> $DIR/toplevel_ref_arg_non_rustfix.rs:20:24 | LL | fn fun_example(ref _x: usize) {} | ^^^^^^ -... -LL | gen_function!(); - | --------------- in this macro invocation | - = note: this error originates in the macro `gen_function` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/try_err.fixed b/tests/ui/try_err.fixed index 264194419c73..dc497b1690f5 100644 --- a/tests/ui/try_err.fixed +++ b/tests/ui/try_err.fixed @@ -1,11 +1,11 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![deny(clippy::try_err)] #![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; use std::io; use std::task::Poll; @@ -79,36 +79,22 @@ fn nested_error() -> Result { Ok(1) } -// Bad suggestion when in macro (see #6242) -macro_rules! try_validation { - ($e: expr) => {{ - match $e { +#[inline_macros] +fn calling_macro() -> Result { + // macro + inline!( + match $(Ok::<_, i32>(5)) { Ok(_) => 0, Err(_) => return Err(1), } - }}; -} - -macro_rules! ret_one { - () => { - 1 - }; -} - -macro_rules! try_validation_in_macro { - ($e: expr) => {{ - match $e { - Ok(_) => 0, - Err(_) => return Err(ret_one!()), - } - }}; -} - -fn calling_macro() -> Result { - // macro - try_validation!(Ok::<_, i32>(5)); + ); // `Err` arg is another macro - try_validation_in_macro!(Ok::<_, i32>(5)); + inline!( + match $(Ok::<_, i32>(5)) { + Ok(_) => 0, + Err(_) => return Err(inline!(1)), + } + ); Ok(5) } @@ -121,24 +107,19 @@ fn main() { calling_macro().unwrap(); // We don't want to lint in external macros - try_err!(); -} - -macro_rules! bar { - () => { - String::from("aasdfasdfasdfa") - }; -} - -macro_rules! foo { - () => { - bar!() - }; + external! { + pub fn try_err_fn() -> Result { + let err: i32 = 1; + // To avoid warnings during rustfix + if true { Err(err)? } else { Ok(2) } + } + } } +#[inline_macros] pub fn macro_inside(fail: bool) -> Result { if fail { - return Err(foo!()); + return Err(inline!(inline!(String::from("aasdfasdfasdfa")))); } Ok(0) } diff --git a/tests/ui/try_err.rs b/tests/ui/try_err.rs index bc6979bf4571..86aeb75cd96a 100644 --- a/tests/ui/try_err.rs +++ b/tests/ui/try_err.rs @@ -1,11 +1,11 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![deny(clippy::try_err)] #![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; use std::io; use std::task::Poll; @@ -79,36 +79,22 @@ fn nested_error() -> Result { Ok(1) } -// Bad suggestion when in macro (see #6242) -macro_rules! try_validation { - ($e: expr) => {{ - match $e { +#[inline_macros] +fn calling_macro() -> Result { + // macro + inline!( + match $(Ok::<_, i32>(5)) { Ok(_) => 0, Err(_) => Err(1)?, } - }}; -} - -macro_rules! ret_one { - () => { - 1 - }; -} - -macro_rules! try_validation_in_macro { - ($e: expr) => {{ - match $e { - Ok(_) => 0, - Err(_) => Err(ret_one!())?, - } - }}; -} - -fn calling_macro() -> Result { - // macro - try_validation!(Ok::<_, i32>(5)); + ); // `Err` arg is another macro - try_validation_in_macro!(Ok::<_, i32>(5)); + inline!( + match $(Ok::<_, i32>(5)) { + Ok(_) => 0, + Err(_) => Err(inline!(1))?, + } + ); Ok(5) } @@ -121,24 +107,19 @@ fn main() { calling_macro().unwrap(); // We don't want to lint in external macros - try_err!(); -} - -macro_rules! bar { - () => { - String::from("aasdfasdfasdfa") - }; -} - -macro_rules! foo { - () => { - bar!() - }; + external! { + pub fn try_err_fn() -> Result { + let err: i32 = 1; + // To avoid warnings during rustfix + if true { Err(err)? } else { Ok(2) } + } + } } +#[inline_macros] pub fn macro_inside(fail: bool) -> Result { if fail { - Err(foo!())?; + Err(inline!(inline!(String::from("aasdfasdfasdfa"))))?; } Ok(0) } diff --git a/tests/ui/try_err.stderr b/tests/ui/try_err.stderr index 0cb1328fbfcf..4ad0e2e56a4d 100644 --- a/tests/ui/try_err.stderr +++ b/tests/ui/try_err.stderr @@ -29,53 +29,47 @@ LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err.into())` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:87:23 + --> $DIR/try_err.rs:88:23 | LL | Err(_) => Err(1)?, | ^^^^^^^ help: try this: `return Err(1)` -... -LL | try_validation!(Ok::<_, i32>(5)); - | -------------------------------- in this macro invocation | - = note: this error originates in the macro `try_validation` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:102:23 + --> $DIR/try_err.rs:95:23 | -LL | Err(_) => Err(ret_one!())?, - | ^^^^^^^^^^^^^^^^ help: try this: `return Err(ret_one!())` -... -LL | try_validation_in_macro!(Ok::<_, i32>(5)); - | ----------------------------------------- in this macro invocation +LL | Err(_) => Err(inline!(1))?, + | ^^^^^^^^^^^^^^^^ help: try this: `return Err(inline!(1))` | - = note: this error originates in the macro `try_validation_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:141:9 + --> $DIR/try_err.rs:122:9 | -LL | Err(foo!())?; - | ^^^^^^^^^^^^ help: try this: `return Err(foo!())` +LL | Err(inline!(inline!(String::from("aasdfasdfasdfa"))))?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Err(inline!(inline!(String::from("aasdfasdfasdfa"))))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:148:9 + --> $DIR/try_err.rs:129:9 | LL | Err(io::ErrorKind::WriteZero)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:150:9 + --> $DIR/try_err.rs:131:9 | LL | Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:158:9 + --> $DIR/try_err.rs:139:9 | LL | Err(io::ErrorKind::NotFound)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:167:16 + --> $DIR/try_err.rs:148:16 | LL | return Err(42)?; | ^^^^^^^^ help: try this: `Err(42)` diff --git a/tests/ui/uninit.rs b/tests/ui/uninit.rs index 211317317086..412b36b4ee8f 100644 --- a/tests/ui/uninit.rs +++ b/tests/ui/uninit.rs @@ -3,13 +3,15 @@ use std::mem::{self, MaybeUninit}; +union MyOwnMaybeUninit { + value: u8, + uninit: (), +} + fn main() { let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; - // edge case: For now we lint on empty arrays - let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() }; - - // edge case: For now we accept unit tuples + // This is OK, because ZSTs do not contain data. let _: () = unsafe { MaybeUninit::uninit().assume_init() }; // This is OK, because `MaybeUninit` allows uninitialized data. @@ -21,6 +23,19 @@ fn main() { // This is OK, because all constitutent types are uninit-compatible. let _: (MaybeUninit, [MaybeUninit; 2]) = unsafe { MaybeUninit::uninit().assume_init() }; + // This is OK, because our own MaybeUninit is just as fine as the one from core. + let _: MyOwnMaybeUninit = unsafe { MaybeUninit::uninit().assume_init() }; + + // This is OK, because empty arrays don't contain data. + let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() }; + // Was a false negative. let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() }; + + polymorphic::<()>(); + + fn polymorphic() { + // We are conservative around polymorphic types. + let _: T = unsafe { mem::MaybeUninit::uninit().assume_init() }; + } } diff --git a/tests/ui/uninit.stderr b/tests/ui/uninit.stderr index 15ef2349489f..9e01b9a4aa81 100644 --- a/tests/ui/uninit.stderr +++ b/tests/ui/uninit.stderr @@ -1,5 +1,5 @@ error: this call for this type may be undefined behavior - --> $DIR/uninit.rs:7:29 + --> $DIR/uninit.rs:12:29 | LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,16 +7,16 @@ LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; = note: `#[deny(clippy::uninit_assumed_init)]` on by default error: this call for this type may be undefined behavior - --> $DIR/uninit.rs:10:31 - | -LL | let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: this call for this type may be undefined behavior - --> $DIR/uninit.rs:25:29 + --> $DIR/uninit.rs:33:29 | LL | let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: this call for this type may be undefined behavior + --> $DIR/uninit.rs:39:29 + | +LL | let _: T = unsafe { mem::MaybeUninit::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: aborting due to 3 previous errors diff --git a/tests/ui/uninit_vec.rs b/tests/ui/uninit_vec.rs index 194e4fc157ef..59ec64a7ab1b 100644 --- a/tests/ui/uninit_vec.rs +++ b/tests/ui/uninit_vec.rs @@ -7,6 +7,11 @@ struct MyVec { vec: Vec, } +union MyOwnMaybeUninit { + value: u8, + uninit: (), +} + fn main() { // with_capacity() -> set_len() should be detected let mut vec: Vec = Vec::with_capacity(1000); @@ -97,4 +102,26 @@ fn main() { unsafe { vec.set_len(0); } + + // ZSTs should not be detected + let mut vec: Vec<()> = Vec::with_capacity(1000); + unsafe { + vec.set_len(10); + } + + // unions should not be detected + let mut vec: Vec = Vec::with_capacity(1000); + unsafe { + vec.set_len(10); + } + + polymorphic::<()>(); + + fn polymorphic() { + // We are conservative around polymorphic types. + let mut vec: Vec = Vec::with_capacity(1000); + unsafe { + vec.set_len(10); + } + } } diff --git a/tests/ui/uninit_vec.stderr b/tests/ui/uninit_vec.stderr index 77fc689f0763..9cdf0c95ad9f 100644 --- a/tests/ui/uninit_vec.stderr +++ b/tests/ui/uninit_vec.stderr @@ -1,5 +1,5 @@ error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:12:5 + --> $DIR/uninit_vec.rs:17:5 | LL | let mut vec: Vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | vec.set_len(200); = note: `-D clippy::uninit-vec` implied by `-D warnings` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:18:5 + --> $DIR/uninit_vec.rs:23:5 | LL | vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` on empty `Vec` creates out-of-bound values - --> $DIR/uninit_vec.rs:24:5 + --> $DIR/uninit_vec.rs:29:5 | LL | let mut vec: Vec = Vec::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ error: calling `set_len()` on empty `Vec` creates out-of-bound values - --> $DIR/uninit_vec.rs:30:5 + --> $DIR/uninit_vec.rs:35:5 | LL | let mut vec: Vec = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ error: calling `set_len()` on empty `Vec` creates out-of-bound values - --> $DIR/uninit_vec.rs:35:5 + --> $DIR/uninit_vec.rs:40:5 | LL | let mut vec: Vec = Vec::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:49:5 + --> $DIR/uninit_vec.rs:54:5 | LL | let mut vec: Vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:58:5 + --> $DIR/uninit_vec.rs:63:5 | LL | my_vec.vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | my_vec.vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:63:5 + --> $DIR/uninit_vec.rs:68:5 | LL | my_vec.vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -82,7 +82,7 @@ LL | my_vec.vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:42:9 + --> $DIR/uninit_vec.rs:47:9 | LL | let mut vec: Vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:45:9 + --> $DIR/uninit_vec.rs:50:9 | LL | vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^ @@ -101,5 +101,16 @@ LL | vec.set_len(200); | = help: initialize the buffer or wrap the content in `MaybeUninit` -error: aborting due to 10 previous errors +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:122:9 + | +LL | let mut vec: Vec = Vec::with_capacity(1000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe { +LL | vec.set_len(10); + | ^^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: aborting due to 11 previous errors diff --git a/tests/ui/uninlined_format_args.fixed b/tests/ui/uninlined_format_args.fixed index cbd5cc5fceef..1475d781c673 100644 --- a/tests/ui/uninlined_format_args.fixed +++ b/tests/ui/uninlined_format_args.fixed @@ -1,11 +1,11 @@ -// aux-build:proc_macro_with_span.rs +// aux-build:proc_macros.rs // run-rustfix #![warn(clippy::uninlined_format_args)] #![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)] #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; macro_rules! no_param_str { () => { diff --git a/tests/ui/uninlined_format_args.rs b/tests/ui/uninlined_format_args.rs index cf0ea5be4813..835afac393fa 100644 --- a/tests/ui/uninlined_format_args.rs +++ b/tests/ui/uninlined_format_args.rs @@ -1,11 +1,11 @@ -// aux-build:proc_macro_with_span.rs +// aux-build:proc_macros.rs // run-rustfix #![warn(clippy::uninlined_format_args)] #![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)] #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; macro_rules! no_param_str { () => { diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index 07e70873a813..674ae4f1df97 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,4 +1,4 @@ -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![warn(clippy::unit_arg)] #![allow(unused_must_use, unused_variables)] #![allow( @@ -13,9 +13,9 @@ clippy::unused_unit )] -extern crate proc_macro_with_span; +extern crate proc_macros; -use proc_macro_with_span::with_span; +use proc_macros::with_span; use std::fmt::Debug; fn foo(t: T) { diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index 22e9bd8bdc51..3b93800f8b75 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -1,12 +1,12 @@ // run-rustfix -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::map_identity)] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; struct Deep(Option); diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index 8726d84a23fc..2851c0c51904 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -1,12 +1,12 @@ // run-rustfix -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::map_identity)] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; struct Deep(Option); diff --git a/tests/ui/unnecessary_operation.fixed b/tests/ui/unnecessary_operation.fixed index 65d9c910b828..b046694f8c6f 100644 --- a/tests/ui/unnecessary_operation.fixed +++ b/tests/ui/unnecessary_operation.fixed @@ -1,6 +1,12 @@ // run-rustfix -#![allow(clippy::deref_addrof, dead_code, unused, clippy::no_effect)] +#![allow( + clippy::deref_addrof, + dead_code, + unused, + clippy::no_effect, + clippy::unnecessary_struct_initialization +)] #![warn(clippy::unnecessary_operation)] struct Tuple(i32); diff --git a/tests/ui/unnecessary_operation.rs b/tests/ui/unnecessary_operation.rs index 4e2acd59f04a..9ed9679e938b 100644 --- a/tests/ui/unnecessary_operation.rs +++ b/tests/ui/unnecessary_operation.rs @@ -1,6 +1,12 @@ // run-rustfix -#![allow(clippy::deref_addrof, dead_code, unused, clippy::no_effect)] +#![allow( + clippy::deref_addrof, + dead_code, + unused, + clippy::no_effect, + clippy::unnecessary_struct_initialization +)] #![warn(clippy::unnecessary_operation)] struct Tuple(i32); diff --git a/tests/ui/unnecessary_operation.stderr b/tests/ui/unnecessary_operation.stderr index 44cf2e01ff73..a1d0d93998a6 100644 --- a/tests/ui/unnecessary_operation.stderr +++ b/tests/ui/unnecessary_operation.stderr @@ -1,5 +1,5 @@ error: unnecessary operation - --> $DIR/unnecessary_operation.rs:50:5 + --> $DIR/unnecessary_operation.rs:56:5 | LL | Tuple(get_number()); | ^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` @@ -7,103 +7,103 @@ LL | Tuple(get_number()); = note: `-D clippy::unnecessary-operation` implied by `-D warnings` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:51:5 + --> $DIR/unnecessary_operation.rs:57:5 | LL | Struct { field: get_number() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:52:5 + --> $DIR/unnecessary_operation.rs:58:5 | LL | Struct { ..get_struct() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_struct();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:53:5 + --> $DIR/unnecessary_operation.rs:59:5 | LL | Enum::Tuple(get_number()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:54:5 + --> $DIR/unnecessary_operation.rs:60:5 | LL | Enum::Struct { field: get_number() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:55:5 + --> $DIR/unnecessary_operation.rs:61:5 | LL | 5 + get_number(); | ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:56:5 + --> $DIR/unnecessary_operation.rs:62:5 | LL | *&get_number(); | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:57:5 + --> $DIR/unnecessary_operation.rs:63:5 | LL | &get_number(); | ^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:58:5 + --> $DIR/unnecessary_operation.rs:64:5 | LL | (5, 6, get_number()); | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;6;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:59:5 + --> $DIR/unnecessary_operation.rs:65:5 | LL | get_number()..; | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:60:5 + --> $DIR/unnecessary_operation.rs:66:5 | LL | ..get_number(); | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:61:5 + --> $DIR/unnecessary_operation.rs:67:5 | LL | 5..get_number(); | ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:62:5 + --> $DIR/unnecessary_operation.rs:68:5 | LL | [42, get_number()]; | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:63:5 + --> $DIR/unnecessary_operation.rs:69:5 | LL | [42, 55][get_usize()]; | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:64:5 + --> $DIR/unnecessary_operation.rs:70:5 | LL | (42, get_number()).1; | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:65:5 + --> $DIR/unnecessary_operation.rs:71:5 | LL | [get_number(); 55]; | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:66:5 + --> $DIR/unnecessary_operation.rs:72:5 | LL | [42; 55][get_usize()]; | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42; 55].len() > get_usize());` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:67:5 + --> $DIR/unnecessary_operation.rs:73:5 | LL | / { LL | | get_number() @@ -111,7 +111,7 @@ LL | | }; | |______^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:70:5 + --> $DIR/unnecessary_operation.rs:76:5 | LL | / FooString { LL | | s: String::from("blah"), diff --git a/tests/ui/unnecessary_struct_initialization.fixed b/tests/ui/unnecessary_struct_initialization.fixed new file mode 100644 index 000000000000..b47129e4a36a --- /dev/null +++ b/tests/ui/unnecessary_struct_initialization.fixed @@ -0,0 +1,73 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::unnecessary_struct_initialization)] + +struct S { + f: String, +} + +#[derive(Clone, Copy)] +struct T { + f: u32, +} + +struct U { + f: u32, +} + +impl Clone for U { + fn clone(&self) -> Self { + // Do not lint: `Self` does not implement `Copy` + Self { ..*self } + } +} + +#[derive(Copy)] +struct V { + f: u32, +} + +impl Clone for V { + fn clone(&self) -> Self { + // Lint: `Self` implements `Copy` + *self + } +} + +fn main() { + // Should lint: `a` would be consumed anyway + let a = S { f: String::from("foo") }; + let mut b = a; + + // Should lint: `b` would be consumed, and is mutable + let c = &mut b; + + // Should not lint as `d` is not mutable + let d = S { f: String::from("foo") }; + let e = &mut S { ..d }; + + // Should lint as `f` would be consumed anyway + let f = S { f: String::from("foo") }; + let g = &f; + + // Should lint: the result of an expression is mutable + let h = &mut *Box::new(S { f: String::from("foo") }); + + // Should not lint: `m` would be both alive and borrowed + let m = T { f: 17 }; + let n = &T { ..m }; + + // Should not lint: `m` should not be modified + let o = &mut T { ..m }; + o.f = 32; + assert_eq!(m.f, 17); + + // Should not lint: `m` should not be modified + let o = &mut T { ..m } as *mut T; + unsafe { &mut *o }.f = 32; + assert_eq!(m.f, 17); + + // Should lint: the result of an expression is mutable and temporary + let p = &mut *Box::new(T { f: 5 }); +} diff --git a/tests/ui/unnecessary_struct_initialization.rs b/tests/ui/unnecessary_struct_initialization.rs new file mode 100644 index 000000000000..63b11c626e5b --- /dev/null +++ b/tests/ui/unnecessary_struct_initialization.rs @@ -0,0 +1,77 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::unnecessary_struct_initialization)] + +struct S { + f: String, +} + +#[derive(Clone, Copy)] +struct T { + f: u32, +} + +struct U { + f: u32, +} + +impl Clone for U { + fn clone(&self) -> Self { + // Do not lint: `Self` does not implement `Copy` + Self { ..*self } + } +} + +#[derive(Copy)] +struct V { + f: u32, +} + +impl Clone for V { + fn clone(&self) -> Self { + // Lint: `Self` implements `Copy` + Self { ..*self } + } +} + +fn main() { + // Should lint: `a` would be consumed anyway + let a = S { f: String::from("foo") }; + let mut b = S { ..a }; + + // Should lint: `b` would be consumed, and is mutable + let c = &mut S { ..b }; + + // Should not lint as `d` is not mutable + let d = S { f: String::from("foo") }; + let e = &mut S { ..d }; + + // Should lint as `f` would be consumed anyway + let f = S { f: String::from("foo") }; + let g = &S { ..f }; + + // Should lint: the result of an expression is mutable + let h = &mut S { + ..*Box::new(S { f: String::from("foo") }) + }; + + // Should not lint: `m` would be both alive and borrowed + let m = T { f: 17 }; + let n = &T { ..m }; + + // Should not lint: `m` should not be modified + let o = &mut T { ..m }; + o.f = 32; + assert_eq!(m.f, 17); + + // Should not lint: `m` should not be modified + let o = &mut T { ..m } as *mut T; + unsafe { &mut *o }.f = 32; + assert_eq!(m.f, 17); + + // Should lint: the result of an expression is mutable and temporary + let p = &mut T { + ..*Box::new(T { f: 5 }) + }; +} diff --git a/tests/ui/unnecessary_struct_initialization.stderr b/tests/ui/unnecessary_struct_initialization.stderr new file mode 100644 index 000000000000..ca497057702f --- /dev/null +++ b/tests/ui/unnecessary_struct_initialization.stderr @@ -0,0 +1,46 @@ +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:34:9 + | +LL | Self { ..*self } + | ^^^^^^^^^^^^^^^^ help: replace with: `*self` + | + = note: `-D clippy::unnecessary-struct-initialization` implied by `-D warnings` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:41:17 + | +LL | let mut b = S { ..a }; + | ^^^^^^^^^ help: replace with: `a` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:44:18 + | +LL | let c = &mut S { ..b }; + | ^^^^^^^^^ help: replace with: `b` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:52:14 + | +LL | let g = &S { ..f }; + | ^^^^^^^^^ help: replace with: `f` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:55:18 + | +LL | let h = &mut S { + | __________________^ +LL | | ..*Box::new(S { f: String::from("foo") }) +LL | | }; + | |_____^ help: replace with: `*Box::new(S { f: String::from("foo") })` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:74:18 + | +LL | let p = &mut T { + | __________________^ +LL | | ..*Box::new(T { f: 5 }) +LL | | }; + | |_____^ help: replace with: `*Box::new(T { f: 5 })` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/unnecessary_unsafety_doc.rs b/tests/ui/unnecessary_unsafety_doc.rs index c160e31afd33..431093ab3696 100644 --- a/tests/ui/unnecessary_unsafety_doc.rs +++ b/tests/ui/unnecessary_unsafety_doc.rs @@ -1,10 +1,10 @@ -// aux-build:doc_unsafe_macros.rs +// aux-build:proc_macros.rs #![allow(clippy::let_unit_value)] #![warn(clippy::unnecessary_safety_doc)] -#[macro_use] -extern crate doc_unsafe_macros; +extern crate proc_macros; +use proc_macros::external; /// This is has no safety section, and does not need one either pub fn destroy_the_planet() { @@ -129,7 +129,11 @@ macro_rules! very_safe { very_safe!(); // we don't lint code from external macros -undocd_safe!(); +external!( + pub fn vey_oy() { + unimplemented!(); + } +); fn main() {} diff --git a/tests/ui/unnecessary_unsafety_doc.stderr b/tests/ui/unnecessary_unsafety_doc.stderr index 72898c93fa11..b0f20fdac5fa 100644 --- a/tests/ui/unnecessary_unsafety_doc.stderr +++ b/tests/ui/unnecessary_unsafety_doc.stderr @@ -42,7 +42,7 @@ LL | very_safe!(); = note: this error originates in the macro `very_safe` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for safe trait have unnecessary `# Safety` section - --> $DIR/unnecessary_unsafety_doc.rs:147:1 + --> $DIR/unnecessary_unsafety_doc.rs:151:1 | LL | pub trait DocumentedSafeTraitWithImplementationHeader { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/triagebot.toml b/triagebot.toml index 6f50ef932e11..3f8f6a7b98c2 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -17,6 +17,7 @@ contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIB [assign.owners] "/.github" = ["@flip1995"] +"/util/gh-pages" = ["@xFrednet"] "*" = [ "@flip1995", "@Manishearth", From 982c81ad2847f2736bc907b806b620ec2ac8fd11 Mon Sep 17 00:00:00 2001 From: FixedThink <41233185+FixedThink@users.noreply.github.com> Date: Fri, 24 Mar 2023 16:08:27 +0100 Subject: [PATCH 025/272] docs fix: unknown field `allowed-locales` changelog: fix: Replace the nonexistent `allowed-locales` in the `DISALLOWED_SCRIPT_IDENTS` docs with `allowed-scripts`. --- clippy_lints/src/disallowed_script_idents.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index 084190f00132..c9fad98e4373 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// ### Example /// ```rust /// // Assuming that `clippy.toml` contains the following line: - /// // allowed-locales = ["Latin", "Cyrillic"] + /// // allowed-scripts = ["Latin", "Cyrillic"] /// let counter = 10; // OK, latin is allowed. /// let счётчик = 10; // OK, cyrillic is allowed. /// let zähler = 10; // OK, it's still latin. From b13f99c7e75e8769865dfe896b8ac3d2bb28cfb1 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 24 Mar 2023 15:29:30 +0000 Subject: [PATCH 026/272] Fix allow attribute, items from macros in `items_after_statements` --- clippy_lints/src/items_after_statements.rs | 31 ++++++++++--------- clippy_lints/src/lib.rs | 2 +- ..._statement.rs => items_after_statement.rs} | 17 ++++++++++ ...nt.stderr => items_after_statement.stderr} | 6 ++-- 4 files changed, 37 insertions(+), 19 deletions(-) rename tests/ui/{item_after_statement.rs => items_after_statement.rs} (69%) rename tests/ui/{item_after_statement.stderr => items_after_statement.stderr} (87%) diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index 46d439b4497e..a7ec57e28505 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -1,8 +1,8 @@ //! lint when items are used after statements -use clippy_utils::diagnostics::span_lint; -use rustc_ast::ast::{Block, ItemKind, StmtKind}; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use clippy_utils::diagnostics::span_lint_hir; +use rustc_hir::{Block, ItemKind, StmtKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -52,33 +52,34 @@ declare_clippy_lint! { declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]); -impl EarlyLintPass for ItemsAfterStatements { - fn check_block(&mut self, cx: &EarlyContext<'_>, item: &Block) { - if in_external_macro(cx.sess(), item.span) { +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 and trailing semicolons - let stmts = item + // skip initial items + let stmts = block .stmts .iter() - .map(|stmt| &stmt.kind) - .skip_while(|s| matches!(**s, StmtKind::Item(..) | StmtKind::Empty)); + .skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..))); // lint on all further items for stmt in stmts { - if let StmtKind::Item(ref it) = *stmt { - if in_external_macro(cx.sess(), it.span) { + if 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::MacroDef(..) = it.kind { + if let ItemKind::Macro(..) = item.kind { // do not lint `macro_rules`, but continue processing further statements continue; } - span_lint( + span_lint_hir( cx, ITEMS_AFTER_STATEMENTS, - it.span, + 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/lib.rs b/clippy_lints/src/lib.rs index c9210bf73f89..f6cea7e2daf6 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -747,7 +747,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::new(unused_unit::UnusedUnit)); store.register_late_pass(|_| Box::new(returns::Return)); store.register_early_pass(|| Box::new(collapsible_if::CollapsibleIf)); - store.register_early_pass(|| Box::new(items_after_statements::ItemsAfterStatements)); + store.register_late_pass(|_| Box::new(items_after_statements::ItemsAfterStatements)); store.register_early_pass(|| Box::new(precedence::Precedence)); store.register_late_pass(|_| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals)); store.register_early_pass(|| Box::new(needless_continue::NeedlessContinue)); diff --git a/tests/ui/item_after_statement.rs b/tests/ui/items_after_statement.rs similarity index 69% rename from tests/ui/item_after_statement.rs rename to tests/ui/items_after_statement.rs index 5e92dcab1f5a..f12cb8f22e27 100644 --- a/tests/ui/item_after_statement.rs +++ b/tests/ui/items_after_statement.rs @@ -51,3 +51,20 @@ fn semicolon() { let _ = S::new(3); } + +fn item_from_macro() { + macro_rules! static_assert_size { + ($ty:ty, $size:expr) => { + const _: [(); $size] = [(); ::std::mem::size_of::<$ty>()]; + }; + } + + let _ = 1; + static_assert_size!(u32, 4); +} + +fn allow_attribute() { + let _ = 1; + #[allow(clippy::items_after_statements)] + const _: usize = 1; +} diff --git a/tests/ui/item_after_statement.stderr b/tests/ui/items_after_statement.stderr similarity index 87% rename from tests/ui/item_after_statement.stderr rename to tests/ui/items_after_statement.stderr index 2523c53ac53a..f69635a977bd 100644 --- a/tests/ui/item_after_statement.stderr +++ b/tests/ui/items_after_statement.stderr @@ -1,5 +1,5 @@ error: adding items after statements is confusing, since items exist from the start of the scope - --> $DIR/item_after_statement.rs:13:5 + --> $DIR/items_after_statement.rs:13:5 | LL | / fn foo() { LL | | println!("foo"); @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::items-after-statements` implied by `-D warnings` error: adding items after statements is confusing, since items exist from the start of the scope - --> $DIR/item_after_statement.rs:20:5 + --> $DIR/items_after_statement.rs:20:5 | LL | / fn foo() { LL | | println!("foo"); @@ -17,7 +17,7 @@ LL | | } | |_____^ error: adding items after statements is confusing, since items exist from the start of the scope - --> $DIR/item_after_statement.rs:33:13 + --> $DIR/items_after_statement.rs:33:13 | LL | / fn say_something() { LL | | println!("something"); From b782a071ad06bbf52168c34f4c51912fd039d912 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 22 Mar 2023 20:13:57 +0100 Subject: [PATCH 027/272] Add explanation on how to run `cargo-clippy` and `clippy-driver` --- book/src/development/adding_lints.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index f57dc627dce4..0f5ee7103de1 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -18,6 +18,7 @@ because that's clearly a non-descriptive name. - [Cargo lints](#cargo-lints) - [Rustfix tests](#rustfix-tests) - [Testing manually](#testing-manually) + - [Running directly](#running-directly) - [Lint declaration](#lint-declaration) - [Lint registration](#lint-registration) - [Lint passes](#lint-passes) @@ -186,6 +187,15 @@ cargo dev lint input.rs from the working copy root. With tests in place, let's have a look at implementing our lint now. +## Running directly + +While it's easier to just use `cargo dev lint`, it might be desirable to get +`target/release/cargo-clippy` and `target/release/clippy-driver` to work as well in some cases. +By default, they don't work because clippy dynamically links rustc. To help them find rustc, +add the path printed by`rustc --print target-libdir` (ran inside this workspace so that the rustc version matches) +to your library search path. +On linux, this can be done by setting the `LD_LIBRARY_PATH` environment variable to that path. + ## Lint declaration Let's start by opening the new file created in the `clippy_lints` crate at From 52c4dc65d942efd2c74e8c9b3334ee268a8522ae Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Tue, 14 Mar 2023 09:15:23 +0800 Subject: [PATCH 028/272] fix [`cast_possible_truncation`] offering wrong suggestion when casting from float suggest `try_into` when casting to wildcard type; fix [`cast_possible_truncation`] suggesting useless parenthesis; remove suggesting for float to float conversion in [`cast_possible_truncation`] style nit --- .../src/casts/cast_possible_truncation.rs | 42 +++++-- tests/ui/cast.rs | 6 + tests/ui/cast.stderr | 112 ++++++++++-------- 3 files changed, 100 insertions(+), 60 deletions(-) diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 823970e35abb..95c2ecbf791b 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -2,8 +2,9 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::expr_or_init; use clippy_utils::source::snippet; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize}; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::{Applicability, Diagnostic, SuggestionStyle}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -163,19 +164,34 @@ pub(super) fn check( _ => return, }; - let name_of_cast_from = snippet(cx, cast_expr.span, ".."); - let cast_to_snip = snippet(cx, cast_to_span, ".."); - let suggestion = format!("{cast_to_snip}::try_from({name_of_cast_from})"); - span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg, |diag| { diag.help("if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ..."); - diag.span_suggestion_with_style( - expr.span, - "... or use `try_from` and handle the error accordingly", - suggestion, - Applicability::Unspecified, - // always show the suggestion in a separate line - SuggestionStyle::ShowAlways, - ); + if !cast_from.is_floating_point() { + offer_suggestion(cx, expr, cast_expr, cast_to_span, diag); + } }); } + +fn offer_suggestion( + cx: &LateContext<'_>, + expr: &Expr<'_>, + cast_expr: &Expr<'_>, + cast_to_span: Span, + diag: &mut Diagnostic, +) { + let cast_to_snip = snippet(cx, cast_to_span, ".."); + let suggestion = if cast_to_snip == "_" { + format!("{}.try_into()", Sugg::hir(cx, cast_expr, "..").maybe_par()) + } else { + format!("{cast_to_snip}::try_from({})", Sugg::hir(cx, cast_expr, "..")) + }; + + diag.span_suggestion_with_style( + expr.span, + "... or use `try_from` and handle the error accordingly", + suggestion, + Applicability::Unspecified, + // always show the suggestion in a separate line + SuggestionStyle::ShowAlways, + ); +} diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index 8b2673c2a7fd..a86b85706a34 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -29,6 +29,12 @@ fn main() { 1f64 as isize; 1f64 as usize; 1f32 as u32 as u16; + { + let _x: i8 = 1i32 as _; + 1f32 as i32; + 1f64 as i32; + 1f32 as u8; + } // Test clippy::cast_possible_wrap 1u8 as i8; 1u16 as i16; diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 451078de23b2..65ecf1aa37aa 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -44,10 +44,6 @@ LL | 1f32 as i32; | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` -help: ... or use `try_from` and handle the error accordingly - | -LL | i32::try_from(1f32); - | ~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may truncate the value --> $DIR/cast.rs:25:5 @@ -56,10 +52,6 @@ LL | 1f32 as u32; | ^^^^^^^^^^^ | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... -help: ... or use `try_from` and handle the error accordingly - | -LL | u32::try_from(1f32); - | ~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may lose the sign of the value --> $DIR/cast.rs:25:5 @@ -76,10 +68,6 @@ LL | 1f64 as f32; | ^^^^^^^^^^^ | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... -help: ... or use `try_from` and handle the error accordingly - | -LL | f32::try_from(1f64); - | ~~~~~~~~~~~~~~~~~~~ error: casting `i32` to `i8` may truncate the value --> $DIR/cast.rs:27:5 @@ -112,10 +100,6 @@ LL | 1f64 as isize; | ^^^^^^^^^^^^^ | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... -help: ... or use `try_from` and handle the error accordingly - | -LL | isize::try_from(1f64); - | ~~~~~~~~~~~~~~~~~~~~~ error: casting `f64` to `usize` may truncate the value --> $DIR/cast.rs:30:5 @@ -124,10 +108,6 @@ LL | 1f64 as usize; | ^^^^^^^^^^^^^ | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... -help: ... or use `try_from` and handle the error accordingly - | -LL | usize::try_from(1f64); - | ~~~~~~~~~~~~~~~~~~~~~ error: casting `f64` to `usize` may lose the sign of the value --> $DIR/cast.rs:30:5 @@ -154,10 +134,6 @@ LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... -help: ... or use `try_from` and handle the error accordingly - | -LL | u32::try_from(1f32) as u16; - | ~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may lose the sign of the value --> $DIR/cast.rs:31:5 @@ -165,8 +141,50 @@ error: casting `f32` to `u32` may lose the sign of the value LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ +error: casting `i32` to `i8` may truncate the value + --> $DIR/cast.rs:33:22 + | +LL | let _x: i8 = 1i32 as _; + | ^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | let _x: i8 = 1i32.try_into(); + | ~~~~~~~~~~~~~~~ + +error: casting `f32` to `i32` may truncate the value + --> $DIR/cast.rs:34:9 + | +LL | 1f32 as i32; + | ^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... + +error: casting `f64` to `i32` may truncate the value + --> $DIR/cast.rs:35:9 + | +LL | 1f64 as i32; + | ^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... + +error: casting `f32` to `u8` may truncate the value + --> $DIR/cast.rs:36:9 + | +LL | 1f32 as u8; + | ^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... + +error: casting `f32` to `u8` may lose the sign of the value + --> $DIR/cast.rs:36:9 + | +LL | 1f32 as u8; + | ^^^^^^^^^^ + error: casting `u8` to `i8` may wrap around the value - --> $DIR/cast.rs:33:5 + --> $DIR/cast.rs:39:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -174,43 +192,43 @@ LL | 1u8 as i8; = note: `-D clippy::cast-possible-wrap` implied by `-D warnings` error: casting `u16` to `i16` may wrap around the value - --> $DIR/cast.rs:34:5 + --> $DIR/cast.rs:40:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> $DIR/cast.rs:35:5 + --> $DIR/cast.rs:41:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> $DIR/cast.rs:36:5 + --> $DIR/cast.rs:42:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> $DIR/cast.rs:37:5 + --> $DIR/cast.rs:43:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> $DIR/cast.rs:40:5 + --> $DIR/cast.rs:46:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> $DIR/cast.rs:42:5 + --> $DIR/cast.rs:48:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> $DIR/cast.rs:109:5 + --> $DIR/cast.rs:115:5 | LL | (-99999999999i64).min(1) as i8; // should be linted because signed | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -222,7 +240,7 @@ LL | i8::try_from((-99999999999i64).min(1)); // should be linted because sig | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> $DIR/cast.rs:121:5 + --> $DIR/cast.rs:127:5 | LL | 999999u64.clamp(0, 256) as u8; // should still be linted | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -234,7 +252,7 @@ LL | u8::try_from(999999u64.clamp(0, 256)); // should still be linted | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E2` to `u8` may truncate the value - --> $DIR/cast.rs:142:21 + --> $DIR/cast.rs:148:21 | LL | let _ = self as u8; | ^^^^^^^^^^ @@ -246,7 +264,7 @@ LL | let _ = u8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E2::B` to `u8` will truncate the value - --> $DIR/cast.rs:143:21 + --> $DIR/cast.rs:149:21 | LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ @@ -254,7 +272,7 @@ LL | let _ = Self::B as u8; = note: `-D clippy::cast-enum-truncation` implied by `-D warnings` error: casting `main::E5` to `i8` may truncate the value - --> $DIR/cast.rs:179:21 + --> $DIR/cast.rs:185:21 | LL | let _ = self as i8; | ^^^^^^^^^^ @@ -266,13 +284,13 @@ LL | let _ = i8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E5::A` to `i8` will truncate the value - --> $DIR/cast.rs:180:21 + --> $DIR/cast.rs:186:21 | LL | let _ = Self::A as i8; | ^^^^^^^^^^^^^ error: casting `main::E6` to `i16` may truncate the value - --> $DIR/cast.rs:194:21 + --> $DIR/cast.rs:200:21 | LL | let _ = self as i16; | ^^^^^^^^^^^ @@ -284,7 +302,7 @@ LL | let _ = i16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers - --> $DIR/cast.rs:209:21 + --> $DIR/cast.rs:215:21 | LL | let _ = self as usize; | ^^^^^^^^^^^^^ @@ -296,7 +314,7 @@ LL | let _ = usize::try_from(self); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E10` to `u16` may truncate the value - --> $DIR/cast.rs:250:21 + --> $DIR/cast.rs:256:21 | LL | let _ = self as u16; | ^^^^^^^^^^^ @@ -308,7 +326,7 @@ LL | let _ = u16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> $DIR/cast.rs:258:13 + --> $DIR/cast.rs:264:13 | LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ @@ -316,11 +334,11 @@ LL | let c = (q >> 16) as u8; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | -LL | let c = u8::try_from((q >> 16)); - | ~~~~~~~~~~~~~~~~~~~~~~~ +LL | let c = u8::try_from(q >> 16); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> $DIR/cast.rs:261:13 + --> $DIR/cast.rs:267:13 | LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ @@ -328,8 +346,8 @@ LL | let c = (q / 1000) as u8; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | -LL | let c = u8::try_from((q / 1000)); - | ~~~~~~~~~~~~~~~~~~~~~~~~ +LL | let c = u8::try_from(q / 1000); + | ~~~~~~~~~~~~~~~~~~~~~~ -error: aborting due to 36 previous errors +error: aborting due to 41 previous errors From a6f56cbdbaa6c65019278676a136299838ced65f Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sun, 26 Mar 2023 14:16:38 +0000 Subject: [PATCH 029/272] Move unnecessary_struct_initialization to nursery --- clippy_lints/src/unnecessary_struct_initialization.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/unnecessary_struct_initialization.rs b/clippy_lints/src/unnecessary_struct_initialization.rs index af0b4b1592f4..084b031982d8 100644 --- a/clippy_lints/src/unnecessary_struct_initialization.rs +++ b/clippy_lints/src/unnecessary_struct_initialization.rs @@ -9,7 +9,7 @@ declare_clippy_lint! { /// any field. /// /// ### Why is this bad? - /// Readibility suffers from unnecessary struct building. + /// Readability suffers from unnecessary struct building. /// /// ### Example /// ```rust @@ -25,9 +25,13 @@ declare_clippy_lint! { /// let a = S { s: String::from("Hello, world!") }; /// let b = 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). #[clippy::version = "1.70.0"] pub UNNECESSARY_STRUCT_INITIALIZATION, - complexity, + nursery, "struct built from a base that can be written mode concisely" } declare_lint_pass!(UnnecessaryStruct => [UNNECESSARY_STRUCT_INITIALIZATION]); From 42f2be8a8c655695ecf2b56eebf023faf7d62463 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Sun, 26 Mar 2023 15:59:45 +0100 Subject: [PATCH 030/272] Add suggestion to remove derive() if invoked macro is non-derive --- compiler/rustc_resolve/src/macros.rs | 22 ++++++++++++++----- .../macros/macro-path-prelude-fail-4.stderr | 6 +++++ .../macro-namespace-reserved-2.stderr | 12 ++++++++++ .../tool-attributes-misplaced-2.stderr | 6 +++++ 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 48707d37a101..38e8cf8cd2f1 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -544,11 +544,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if let Some((article, expected)) = unexpected_res { let path_str = pprust::path_to_string(path); let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path_str); - self.tcx - .sess - .struct_span_err(path.span, &msg) - .span_label(path.span, format!("not {} {}", article, expected)) - .emit(); + let mut err = self.tcx.sess.struct_span_err(path.span, &msg); + + err.span_label(path.span, format!("not {} {}", article, expected)); + + if kind == MacroKind::Derive && ext.macro_kind() != MacroKind::Derive { + // Suggest removing the derive() as the macro isn't Derive + let opening_span = + path.span.shrink_to_lo().with_lo(path.span.lo() - rustc_span::BytePos(7)); + let closing_span = + path.span.shrink_to_hi().with_hi(path.span.hi() + rustc_span::BytePos(1)); + err.span_help( + vec![opening_span, closing_span], + "remove the surrounding \"derive()\":", + ); + } + + err.emit(); return Ok((self.dummy_ext(kind), Res::Err)); } diff --git a/tests/ui/macros/macro-path-prelude-fail-4.stderr b/tests/ui/macros/macro-path-prelude-fail-4.stderr index dfd6818b6785..fb4e19d85651 100644 --- a/tests/ui/macros/macro-path-prelude-fail-4.stderr +++ b/tests/ui/macros/macro-path-prelude-fail-4.stderr @@ -3,6 +3,12 @@ error: expected derive macro, found built-in attribute `inline` | LL | #[derive(inline)] | ^^^^^^ not a derive macro + | +help: remove the surrounding "derive()": + --> $DIR/macro-path-prelude-fail-4.rs:1:3 + | +LL | #[derive(inline)] + | ^^^^^^^ ^ error: aborting due to previous error diff --git a/tests/ui/proc-macro/macro-namespace-reserved-2.stderr b/tests/ui/proc-macro/macro-namespace-reserved-2.stderr index 633a6c6a0d3c..6e7adc2e3b12 100644 --- a/tests/ui/proc-macro/macro-namespace-reserved-2.stderr +++ b/tests/ui/proc-macro/macro-namespace-reserved-2.stderr @@ -57,6 +57,12 @@ error: expected derive macro, found attribute macro `my_macro_attr` | LL | #[derive(my_macro_attr)] | ^^^^^^^^^^^^^ not a derive macro + | +help: remove the surrounding "derive()": + --> $DIR/macro-namespace-reserved-2.rs:53:3 + | +LL | #[derive(my_macro_attr)] + | ^^^^^^^ ^ error: can't use a procedural macro from the same crate that defines it --> $DIR/macro-namespace-reserved-2.rs:56:10 @@ -87,6 +93,12 @@ error: expected derive macro, found macro `crate::my_macro` | LL | #[derive(crate::my_macro)] | ^^^^^^^^^^^^^^^ not a derive macro + | +help: remove the surrounding "derive()": + --> $DIR/macro-namespace-reserved-2.rs:50:3 + | +LL | #[derive(crate::my_macro)] + | ^^^^^^^ ^ error: cannot find macro `my_macro_attr` in this scope --> $DIR/macro-namespace-reserved-2.rs:28:5 diff --git a/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr b/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr index 6d0f826e621c..6befa99f5835 100644 --- a/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr +++ b/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr @@ -3,6 +3,12 @@ error: expected derive macro, found tool attribute `rustfmt::skip` | LL | #[derive(rustfmt::skip)] | ^^^^^^^^^^^^^ not a derive macro + | +help: remove the surrounding "derive()": + --> $DIR/tool-attributes-misplaced-2.rs:1:3 + | +LL | #[derive(rustfmt::skip)] + | ^^^^^^^ ^ error: expected macro, found tool attribute `rustfmt::skip` --> $DIR/tool-attributes-misplaced-2.rs:5:5 From ee0de538d4196596986328311bb097a07f473273 Mon Sep 17 00:00:00 2001 From: bluthej Date: Thu, 23 Mar 2023 22:29:30 +0100 Subject: [PATCH 031/272] Add some tests --- tests/ui/clear_with_drain.fixed | 48 ++++++++++++++++++++++++++------ tests/ui/clear_with_drain.rs | 48 ++++++++++++++++++++++++++------ tests/ui/clear_with_drain.stderr | 8 +++--- 3 files changed, 84 insertions(+), 20 deletions(-) diff --git a/tests/ui/clear_with_drain.fixed b/tests/ui/clear_with_drain.fixed index 62b0af08eeae..6ab05d9baca3 100644 --- a/tests/ui/clear_with_drain.fixed +++ b/tests/ui/clear_with_drain.fixed @@ -3,38 +3,70 @@ #![warn(clippy::clear_with_drain)] fn range() { - let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); - let iter = u.drain(0..u.len()); // Yay + let mut v = vec![1, 2, 3]; + let iter = v.drain(0..v.len()); // Yay + + let mut v = vec![1, 2, 3]; + let n = v.drain(0..v.len()).count(); // Yay + + let mut v = vec![1, 2, 3]; v.clear(); // Nay } fn range_from() { - let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); - let iter = u.drain(0..); // Yay + let mut v = vec![1, 2, 3]; + let iter = v.drain(0..); // Yay + + let mut v = vec![1, 2, 3]; + let next = v.drain(0..).next(); // Yay + + let mut v = vec![1, 2, 3]; v.clear(); // Nay } fn range_full() { - let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); - let iter = u.drain(..); // Yay + let mut v = vec![1, 2, 3]; + let iter = v.drain(..); // Yay + + let mut v = vec![1, 2, 3]; + // Yay + for x in v.drain(..) { + let y = format!("x = {x}"); + } + + let mut v = vec![1, 2, 3]; v.clear(); // Nay } fn range_to() { - let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); - let iter = u.drain(..u.len()); // Yay + let mut v = vec![1, 2, 3]; + let iter = v.drain(..v.len()); // Yay + + let mut v = vec![1, 2, 3]; + // Yay + for x in v.drain(..v.len()) { + let y = format!("x = {x}"); + } + + let mut v = vec![1, 2, 3]; v.clear(); // Nay } fn partial_drains() { let mut v = vec![1, 2, 3]; v.drain(1..); // Yay + let mut v = vec![1, 2, 3]; + v.drain(1..).max(); // Yay let mut v = vec![1, 2, 3]; v.drain(..v.len() - 1); // Yay + let mut v = vec![1, 2, 3]; + v.drain(..v.len() - 1).min(); // Yay let mut v = vec![1, 2, 3]; v.drain(1..v.len() - 1); // Yay + let mut v = vec![1, 2, 3]; + let w: Vec = v.drain(1..v.len() - 1).collect(); // Yay } fn main() {} diff --git a/tests/ui/clear_with_drain.rs b/tests/ui/clear_with_drain.rs index 721af7d2ea7e..6926a4b60e84 100644 --- a/tests/ui/clear_with_drain.rs +++ b/tests/ui/clear_with_drain.rs @@ -3,38 +3,70 @@ #![warn(clippy::clear_with_drain)] fn range() { - let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); - let iter = u.drain(0..u.len()); // Yay + let mut v = vec![1, 2, 3]; + let iter = v.drain(0..v.len()); // Yay + + let mut v = vec![1, 2, 3]; + let n = v.drain(0..v.len()).count(); // Yay + + let mut v = vec![1, 2, 3]; v.drain(0..v.len()); // Nay } fn range_from() { - let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); - let iter = u.drain(0..); // Yay + let mut v = vec![1, 2, 3]; + let iter = v.drain(0..); // Yay + + let mut v = vec![1, 2, 3]; + let next = v.drain(0..).next(); // Yay + + let mut v = vec![1, 2, 3]; v.drain(0..); // Nay } fn range_full() { - let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); - let iter = u.drain(..); // Yay + let mut v = vec![1, 2, 3]; + let iter = v.drain(..); // Yay + + let mut v = vec![1, 2, 3]; + // Yay + for x in v.drain(..) { + let y = format!("x = {x}"); + } + + let mut v = vec![1, 2, 3]; v.drain(..); // Nay } fn range_to() { - let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); - let iter = u.drain(..u.len()); // Yay + let mut v = vec![1, 2, 3]; + let iter = v.drain(..v.len()); // Yay + + let mut v = vec![1, 2, 3]; + // Yay + for x in v.drain(..v.len()) { + let y = format!("x = {x}"); + } + + let mut v = vec![1, 2, 3]; v.drain(..v.len()); // Nay } fn partial_drains() { let mut v = vec![1, 2, 3]; v.drain(1..); // Yay + let mut v = vec![1, 2, 3]; + v.drain(1..).max(); // Yay let mut v = vec![1, 2, 3]; v.drain(..v.len() - 1); // Yay + let mut v = vec![1, 2, 3]; + v.drain(..v.len() - 1).min(); // Yay let mut v = vec![1, 2, 3]; v.drain(1..v.len() - 1); // Yay + let mut v = vec![1, 2, 3]; + let w: Vec = v.drain(1..v.len() - 1).collect(); // Yay } fn main() {} diff --git a/tests/ui/clear_with_drain.stderr b/tests/ui/clear_with_drain.stderr index 0d6d8263e10d..b7206cd9007d 100644 --- a/tests/ui/clear_with_drain.stderr +++ b/tests/ui/clear_with_drain.stderr @@ -1,5 +1,5 @@ error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:8:7 + --> $DIR/clear_with_drain.rs:13:7 | LL | v.drain(0..v.len()); // Nay | ^^^^^^^^^^^^^^^^^ help: try: `clear()` @@ -7,19 +7,19 @@ LL | v.drain(0..v.len()); // Nay = note: `-D clippy::clear-with-drain` implied by `-D warnings` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:14:7 + --> $DIR/clear_with_drain.rs:24:7 | LL | v.drain(0..); // Nay | ^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:20:7 + --> $DIR/clear_with_drain.rs:38:7 | LL | v.drain(..); // Nay | ^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:26:7 + --> $DIR/clear_with_drain.rs:52:7 | LL | v.drain(..v.len()); // Nay | ^^^^^^^^^^^^^^^^ help: try: `clear()` From 2493be2196f6ba16eaea25915c25d93f1c2664b5 Mon Sep 17 00:00:00 2001 From: bluthej Date: Sun, 26 Mar 2023 18:25:15 +0200 Subject: [PATCH 032/272] Improve `is_range_full` implementation Make this function work with signed integer types by extracting the underlying type and finding the min and max values. Change the signature to make it more consistent: - The range is now given as an `Expr` in order to extract the type - The container's path is now passed, and only as an `Option` so that the function can be called in the general case without a container --- clippy_lints/src/methods/clear_with_drain.rs | 7 +- clippy_lints/src/methods/iter_with_drain.rs | 7 +- clippy_utils/src/lib.rs | 71 ++++++++++++++++---- 3 files changed, 65 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs index bf7e7d124051..24496bd4689f 100644 --- a/clippy_lints/src/methods/clear_with_drain.rs +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -1,9 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher::Range; use clippy_utils::is_range_full; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; -use rustc_hir::Expr; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; use rustc_span::Span; @@ -12,7 +11,9 @@ use super::CLEAR_WITH_DRAIN; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: &Expr<'_>) { let ty = cx.typeck_results().expr_ty(recv); - if is_type_diagnostic_item(cx, ty, sym::Vec) && let Some(range) = Range::hir(arg) && is_range_full(cx, recv, range) + if is_type_diagnostic_item(cx, ty, sym::Vec) + && let ExprKind::Path(QPath::Resolved(None, container_path)) = recv.kind + && is_range_full(cx, arg, Some(container_path)) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/iter_with_drain.rs b/clippy_lints/src/methods/iter_with_drain.rs index ea92e3a549f4..f6772c5c6b36 100644 --- a/clippy_lints/src/methods/iter_with_drain.rs +++ b/clippy_lints/src/methods/iter_with_drain.rs @@ -1,8 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher::Range; use clippy_utils::is_range_full; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; use rustc_span::Span; @@ -14,8 +13,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span && let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def() && let Some(ty_name) = cx.tcx.get_diagnostic_name(adt.did()) && matches!(ty_name, sym::Vec | sym::VecDeque) - && let Some(range) = Range::hir(arg) - && is_range_full(cx, recv, range) + && let ExprKind::Path(QPath::Resolved(None, container_path)) = recv.kind + && is_range_full(cx, arg, Some(container_path)) { span_lint_and_sugg( cx, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index e8225feb33d8..2e839fdf4728 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -96,6 +96,7 @@ use rustc_hir::{ use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::place::PlaceBase; +use rustc_middle::mir::ConstantKind; use rustc_middle::ty as rustc_ty; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::binding::BindingMode; @@ -114,7 +115,7 @@ use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; use rustc_target::abi::Integer; -use crate::consts::{constant, Constant}; +use crate::consts::{constant, miri_to_const, Constant}; use crate::higher::Range; use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param}; use crate::visitors::for_each_expr; @@ -1492,22 +1493,66 @@ pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { } } -/// Checks whether the given `Range` is equivalent to a `RangeFull`. -/// Inclusive ranges are not considered because they already constitute a lint. -pub fn is_range_full(cx: &LateContext<'_>, container: &Expr<'_>, range: Range<'_>) -> bool { - range.start.map_or(true, |e| is_integer_const(cx, e, 0)) - && range.end.map_or(true, |e| { - if range.limits == RangeLimits::HalfOpen - && let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind - && let ExprKind::MethodCall(name, self_arg, [], _) = e.kind - && name.ident.name == sym::len - && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind +/// Checks whether the given `Expr` is a range equivalent to a `RangeFull`. +/// For the lower bound, this means that: +/// - either there is none +/// - or it is the smallest value that can be represented by the range's integer type +/// For the upper bound, this means that: +/// - either there is none +/// - or it is the largest value that can be represented by the range's integer type and is +/// inclusive +/// - or it is a call to some container's `len` method and is exclusive, and the range is passed to +/// a method call on that same container (e.g. `v.drain(..v.len())`) +/// If the given `Expr` is not some kind of range, the function returns `false`. +pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Option<&Path<'_>>) -> bool { + let ty = cx.typeck_results().expr_ty(expr); + if let Some(Range { start, end, limits }) = Range::hir(expr) { + let start_is_none_or_min = start.map_or(true, |start| { + if let rustc_ty::Adt(_, subst) = ty.kind() + && let bnd_ty = subst.type_at(0) + && let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx) + && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree())) + && let min_const_kind = ConstantKind::from_value(const_val, bnd_ty) + && let Some(min_const) = miri_to_const(cx.tcx, min_const_kind) + && let Some((start_const, _)) = constant(cx, cx.typeck_results(), start) { - container_path.res == path.res + start_const == min_const } else { false } - }) + }); + let end_is_none_or_max = end.map_or(true, |end| { + match limits { + RangeLimits::Closed => { + if let rustc_ty::Adt(_, subst) = ty.kind() + && let bnd_ty = subst.type_at(0) + && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx) + && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree())) + && let max_const_kind = ConstantKind::from_value(const_val, bnd_ty) + && let Some(max_const) = miri_to_const(cx.tcx, max_const_kind) + && let Some((end_const, _)) = constant(cx, cx.typeck_results(), end) + { + end_const == max_const + } else { + false + } + }, + RangeLimits::HalfOpen => { + if let Some(container_path) = container_path + && let ExprKind::MethodCall(name, self_arg, [], _) = end.kind + && name.ident.name == sym::len + && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind + { + container_path.res == path.res + } else { + false + } + }, + } + }); + return start_is_none_or_min && end_is_none_or_max; + } + false } /// Checks whether the given expression is a constant integer of the given value. From 3966580c9d146b6938e691c8a1abefc89e0aa7b7 Mon Sep 17 00:00:00 2001 From: bluthej Date: Sun, 26 Mar 2023 18:59:20 +0200 Subject: [PATCH 033/272] Add tests with `usize::MIN` --- tests/ui/clear_with_drain.fixed | 12 ++++++++++++ tests/ui/clear_with_drain.rs | 12 ++++++++++++ tests/ui/clear_with_drain.stderr | 22 +++++++++++++++++----- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/tests/ui/clear_with_drain.fixed b/tests/ui/clear_with_drain.fixed index 6ab05d9baca3..0a15463ddf79 100644 --- a/tests/ui/clear_with_drain.fixed +++ b/tests/ui/clear_with_drain.fixed @@ -9,6 +9,12 @@ fn range() { let mut v = vec![1, 2, 3]; let n = v.drain(0..v.len()).count(); // Yay + let mut v = vec![1, 2, 3]; + let n = v.drain(usize::MIN..v.len()).count(); // Yay + + let mut v = vec![1, 2, 3]; + v.clear(); // Nay + let mut v = vec![1, 2, 3]; v.clear(); // Nay } @@ -20,6 +26,12 @@ fn range_from() { let mut v = vec![1, 2, 3]; let next = v.drain(0..).next(); // Yay + let mut v = vec![1, 2, 3]; + let next = v.drain(usize::MIN..).next(); // Yay + + let mut v = vec![1, 2, 3]; + v.clear(); // Nay + let mut v = vec![1, 2, 3]; v.clear(); // Nay } diff --git a/tests/ui/clear_with_drain.rs b/tests/ui/clear_with_drain.rs index 6926a4b60e84..40201d9cc4df 100644 --- a/tests/ui/clear_with_drain.rs +++ b/tests/ui/clear_with_drain.rs @@ -9,8 +9,14 @@ fn range() { let mut v = vec![1, 2, 3]; let n = v.drain(0..v.len()).count(); // Yay + let mut v = vec![1, 2, 3]; + let n = v.drain(usize::MIN..v.len()).count(); // Yay + let mut v = vec![1, 2, 3]; v.drain(0..v.len()); // Nay + + let mut v = vec![1, 2, 3]; + v.drain(usize::MIN..v.len()); // Nay } fn range_from() { @@ -20,8 +26,14 @@ fn range_from() { let mut v = vec![1, 2, 3]; let next = v.drain(0..).next(); // Yay + let mut v = vec![1, 2, 3]; + let next = v.drain(usize::MIN..).next(); // Yay + let mut v = vec![1, 2, 3]; v.drain(0..); // Nay + + let mut v = vec![1, 2, 3]; + v.drain(usize::MIN..); // Nay } fn range_full() { diff --git a/tests/ui/clear_with_drain.stderr b/tests/ui/clear_with_drain.stderr index b7206cd9007d..e7152a1cb687 100644 --- a/tests/ui/clear_with_drain.stderr +++ b/tests/ui/clear_with_drain.stderr @@ -1,5 +1,5 @@ error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:13:7 + --> $DIR/clear_with_drain.rs:16:7 | LL | v.drain(0..v.len()); // Nay | ^^^^^^^^^^^^^^^^^ help: try: `clear()` @@ -7,22 +7,34 @@ LL | v.drain(0..v.len()); // Nay = note: `-D clippy::clear-with-drain` implied by `-D warnings` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:24:7 + --> $DIR/clear_with_drain.rs:19:7 + | +LL | v.drain(usize::MIN..v.len()); // Nay + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `Vec` + --> $DIR/clear_with_drain.rs:33:7 | LL | v.drain(0..); // Nay | ^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:38:7 + --> $DIR/clear_with_drain.rs:36:7 + | +LL | v.drain(usize::MIN..); // Nay + | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `Vec` + --> $DIR/clear_with_drain.rs:50:7 | LL | v.drain(..); // Nay | ^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:52:7 + --> $DIR/clear_with_drain.rs:64:7 | LL | v.drain(..v.len()); // Nay | ^^^^^^^^^^^^^^^^ help: try: `clear()` -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors From db4e4afce8f87eb73db3808981215cd28e97095d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 26 Mar 2023 20:33:54 +0000 Subject: [PATCH 034/272] Don't elaborate non-obligations into obligations --- clippy_lints/src/needless_pass_by_value.rs | 4 ++-- clippy_utils/src/lib.rs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 1ab81aee7b8d..327e090d38be 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -124,9 +124,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds().iter()) .filter(|p| !p.is_global()) - .filter_map(|obligation| { + .filter_map(|pred| { // Note that we do not want to deal with qualified predicates here. - match obligation.predicate.kind().no_bound_vars() { + match pred.kind().no_bound_vars() { Some(ty::PredicateKind::Clause(ty::Clause::Trait(pred))) if pred.def_id() != sized_trait => { Some(pred) }, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 29830557a445..fd06c0b86775 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2106,7 +2106,6 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool { traits::impossible_predicates( cx.tcx, traits::elaborate_predicates(cx.tcx, predicates) - .map(|o| o.predicate) .collect::>(), ) } From 022f76d432f3e3289af68845d9169c1866c14d70 Mon Sep 17 00:00:00 2001 From: Micha White Date: Sat, 2 Jul 2022 18:42:08 -0400 Subject: [PATCH 035/272] Added the new lint with some docs and tests --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/unnecessary_box_returns.rs | 88 +++++++++++++++++++++ tests/ui/unnecessary_box_returns.rs | 31 ++++++++ tests/ui/unnecessary_box_returns.stderr | 19 +++++ 6 files changed, 142 insertions(+) create mode 100644 clippy_lints/src/unnecessary_box_returns.rs create mode 100644 tests/ui/unnecessary_box_returns.rs create mode 100644 tests/ui/unnecessary_box_returns.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 1323f973ccfd..1a37ff2e171d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4974,6 +4974,7 @@ Released 2018-09-13 [`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash [`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord [`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints +[`unnecessary_box_returns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns [`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map [`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 8ca91301472e..89076e5d294f 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -616,6 +616,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::unit_types::UNIT_CMP_INFO, crate::unnamed_address::FN_ADDRESS_COMPARISONS_INFO, crate::unnamed_address::VTABLE_ADDRESS_COMPARISONS_INFO, + crate::unnecessary_box_returns::UNNECESSARY_BOX_RETURNS_INFO, crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO, crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO, crate::unnecessary_struct_initialization::UNNECESSARY_STRUCT_INITIALIZATION_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c9210bf73f89..c172ee263c6a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -300,6 +300,7 @@ mod uninit_vec; mod unit_return_expecting_ord; mod unit_types; mod unnamed_address; +mod unnecessary_box_returns; mod unnecessary_owned_empty_strings; mod unnecessary_self_imports; mod unnecessary_struct_initialization; @@ -940,6 +941,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute)); store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(msrv()))); store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct)); + store.register_late_pass(|_| Box::new(unnecessary_box_returns::UnnecessaryBoxReturns)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs new file mode 100644 index 000000000000..533ee026500e --- /dev/null +++ b/clippy_lints/src/unnecessary_box_returns.rs @@ -0,0 +1,88 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_errors::Applicability; +use rustc_hir::{def_id::LocalDefId, intravisit::FnKind, Body, FnDecl, FnRetTy}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for a return type containing a `Box` where `T` implements `Sized` + /// + /// ### Why is this bad? + /// + /// It's better to just return `T` in these cases. The caller may not need + /// the value to be boxed, and it's expensive to free the memory once the + /// `Box` been dropped. + /// + /// ### Example + /// ```rust + /// fn foo() -> Box { + /// Box::new(String::from("Hello, world!")) + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn foo() -> String { + /// String::from("Hello, world!") + /// } + /// ``` + #[clippy::version = "1.70.0"] + pub UNNECESSARY_BOX_RETURNS, + pedantic, + "Needlessly returning a Box" +} +declare_lint_pass!(UnnecessaryBoxReturns => [UNNECESSARY_BOX_RETURNS]); + +impl LateLintPass<'_> for UnnecessaryBoxReturns { + fn check_fn( + &mut self, + cx: &LateContext<'_>, + fn_kind: FnKind<'_>, + decl: &FnDecl<'_>, + _: &Body<'_>, + _: Span, + def_id: LocalDefId, + ) { + // it's unclear what part of a closure you would span, so for now it's ignored + // if this is changed, please also make sure not to call `hir_ty_to_ty` below + if matches!(fn_kind, FnKind::Closure) { + return; + } + + let FnRetTy::Return(return_ty_hir) = &decl.output else { return }; + + let return_ty = cx + .tcx + .erase_late_bound_regions(cx.tcx.fn_sig(def_id).skip_binder()) + .output(); + + if !return_ty.is_box() { + return; + } + + let boxed_ty = return_ty.boxed_ty(); + + // it's sometimes useful to return Box if T is unsized, so don't lint those + if boxed_ty.is_sized(cx.tcx, cx.param_env) { + span_lint_and_then( + cx, + UNNECESSARY_BOX_RETURNS, + return_ty_hir.span, + format!("boxed return of the sized type `{boxed_ty}`").as_str(), + |diagnostic| { + diagnostic.span_suggestion( + return_ty_hir.span, + "try", + boxed_ty.to_string(), + // the return value and function callers also needs to + // be changed, so this can't be MachineApplicable + Applicability::Unspecified, + ); + diagnostic.help("changing this also requires a change to the return expressions in this function"); + }, + ); + } + } +} diff --git a/tests/ui/unnecessary_box_returns.rs b/tests/ui/unnecessary_box_returns.rs new file mode 100644 index 000000000000..49e24878c82d --- /dev/null +++ b/tests/ui/unnecessary_box_returns.rs @@ -0,0 +1,31 @@ +#![warn(clippy::unnecessary_box_returns)] + +struct Foo {} + +// lint +fn boxed_usize() -> Box { + Box::new(5) +} + +// lint +fn boxed_foo() -> Box { + Box::new(Foo {}) +} + +// don't lint: str is unsized +fn boxed_str() -> Box { + "Hello, world!".to_string().into_boxed_str() +} + +// don't lint: this has an unspecified return type +fn default() {} + +// don't lint: this doesn't return a Box +fn string() -> String { + String::from("Hello, world") +} + +fn main() { + // don't lint: this is a closure + let a = || -> Box { Box::new(5) }; +} diff --git a/tests/ui/unnecessary_box_returns.stderr b/tests/ui/unnecessary_box_returns.stderr new file mode 100644 index 000000000000..8acaf33de047 --- /dev/null +++ b/tests/ui/unnecessary_box_returns.stderr @@ -0,0 +1,19 @@ +error: boxed return of the sized type `usize` + --> $DIR/unnecessary_box_returns.rs:6:21 + | +LL | fn boxed_usize() -> Box { + | ^^^^^^^^^^ help: try: `usize` + | + = help: changing this also requires a change to the return expressions in this function + = note: `-D clippy::unnecessary-box-returns` implied by `-D warnings` + +error: boxed return of the sized type `Foo` + --> $DIR/unnecessary_box_returns.rs:11:19 + | +LL | fn boxed_foo() -> Box { + | ^^^^^^^^ help: try: `Foo` + | + = help: changing this also requires a change to the return expressions in this function + +error: aborting due to 2 previous errors + From 1b55c81db565d8e94146b9e2a7ed54f242e349ec Mon Sep 17 00:00:00 2001 From: Micha White Date: Sun, 26 Feb 2023 12:11:47 -0500 Subject: [PATCH 036/272] Lint on trait declarations, not implementations --- clippy_lints/src/unnecessary_box_returns.rs | 102 +++++++++++--------- tests/ui/unnecessary_box_returns.rs | 19 ++++ tests/ui/unnecessary_box_returns.stderr | 24 ++++- 3 files changed, 94 insertions(+), 51 deletions(-) diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs index 533ee026500e..77c1506e5429 100644 --- a/clippy_lints/src/unnecessary_box_returns.rs +++ b/clippy_lints/src/unnecessary_box_returns.rs @@ -1,9 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; -use rustc_hir::{def_id::LocalDefId, intravisit::FnKind, Body, FnDecl, FnRetTy}; +use rustc_hir::{def_id::LocalDefId, FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -35,54 +34,63 @@ declare_clippy_lint! { } declare_lint_pass!(UnnecessaryBoxReturns => [UNNECESSARY_BOX_RETURNS]); -impl LateLintPass<'_> for UnnecessaryBoxReturns { - fn check_fn( - &mut self, - cx: &LateContext<'_>, - fn_kind: FnKind<'_>, - decl: &FnDecl<'_>, - _: &Body<'_>, - _: Span, - def_id: LocalDefId, - ) { - // it's unclear what part of a closure you would span, so for now it's ignored - // if this is changed, please also make sure not to call `hir_ty_to_ty` below - if matches!(fn_kind, FnKind::Closure) { - return; - } +fn check_fn_decl(cx: &LateContext<'_>, decl: &FnDecl<'_>, def_id: LocalDefId) { + let FnRetTy::Return(return_ty_hir) = &decl.output else { return }; - let FnRetTy::Return(return_ty_hir) = &decl.output else { return }; + let return_ty = cx + .tcx + .erase_late_bound_regions(cx.tcx.fn_sig(def_id).skip_binder()) + .output(); - let return_ty = cx - .tcx - .erase_late_bound_regions(cx.tcx.fn_sig(def_id).skip_binder()) - .output(); + if !return_ty.is_box() { + return; + } - if !return_ty.is_box() { - return; - } + let boxed_ty = return_ty.boxed_ty(); - let boxed_ty = return_ty.boxed_ty(); - - // it's sometimes useful to return Box if T is unsized, so don't lint those - if boxed_ty.is_sized(cx.tcx, cx.param_env) { - span_lint_and_then( - cx, - UNNECESSARY_BOX_RETURNS, - return_ty_hir.span, - format!("boxed return of the sized type `{boxed_ty}`").as_str(), - |diagnostic| { - diagnostic.span_suggestion( - return_ty_hir.span, - "try", - boxed_ty.to_string(), - // the return value and function callers also needs to - // be changed, so this can't be MachineApplicable - Applicability::Unspecified, - ); - diagnostic.help("changing this also requires a change to the return expressions in this function"); - }, - ); - } + // it's sometimes useful to return Box if T is unsized, so don't lint those + if boxed_ty.is_sized(cx.tcx, cx.param_env) { + span_lint_and_then( + cx, + UNNECESSARY_BOX_RETURNS, + return_ty_hir.span, + format!("boxed return of the sized type `{boxed_ty}`").as_str(), + |diagnostic| { + diagnostic.span_suggestion( + return_ty_hir.span, + "try", + boxed_ty.to_string(), + // the return value and function callers also needs to + // be changed, so this can't be MachineApplicable + Applicability::Unspecified, + ); + diagnostic.help("changing this also requires a change to the return expressions in this function"); + }, + ); + } +} + +impl LateLintPass<'_> for UnnecessaryBoxReturns { + fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) { + let TraitItemKind::Fn(signature, _) = &item.kind else { return }; + check_fn_decl(cx, signature.decl, item.owner_id.def_id); + } + + fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) { + // Ignore implementations of traits, because the lint should be on the + // trait, not on the implmentation of it. + let Node::Item(parent) = cx.tcx.hir().get_parent(item.hir_id()) else { return }; + let ItemKind::Impl(parent) = parent.kind else { return }; + if parent.of_trait.is_some() { + return; + } + + let ImplItemKind::Fn(signature, ..) = &item.kind else { return }; + check_fn_decl(cx, signature.decl, item.owner_id.def_id); + } + + fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { + let ItemKind::Fn(signature, ..) = &item.kind else { return }; + check_fn_decl(cx, signature.decl, item.owner_id.def_id); } } diff --git a/tests/ui/unnecessary_box_returns.rs b/tests/ui/unnecessary_box_returns.rs index 49e24878c82d..399266f90b0c 100644 --- a/tests/ui/unnecessary_box_returns.rs +++ b/tests/ui/unnecessary_box_returns.rs @@ -1,7 +1,26 @@ #![warn(clippy::unnecessary_box_returns)] +trait Bar { + // lint + fn baz(&self) -> Box; +} + struct Foo {} +impl Bar for Foo { + // don't lint: this is a problem with the trait, not the implementation + fn baz(&self) -> Box { + Box::new(42) + } +} + +impl Foo { + fn baz(&self) -> Box { + // lint + Box::new(13) + } +} + // lint fn boxed_usize() -> Box { Box::new(5) diff --git a/tests/ui/unnecessary_box_returns.stderr b/tests/ui/unnecessary_box_returns.stderr index 8acaf33de047..a431e37a201b 100644 --- a/tests/ui/unnecessary_box_returns.stderr +++ b/tests/ui/unnecessary_box_returns.stderr @@ -1,19 +1,35 @@ error: boxed return of the sized type `usize` - --> $DIR/unnecessary_box_returns.rs:6:21 + --> $DIR/unnecessary_box_returns.rs:5:22 + | +LL | fn baz(&self) -> Box; + | ^^^^^^^^^^ help: try: `usize` + | + = help: changing this also requires a change to the return expressions in this function + = note: `-D clippy::unnecessary-box-returns` implied by `-D warnings` + +error: boxed return of the sized type `usize` + --> $DIR/unnecessary_box_returns.rs:18:22 + | +LL | fn baz(&self) -> Box { + | ^^^^^^^^^^ help: try: `usize` + | + = help: changing this also requires a change to the return expressions in this function + +error: boxed return of the sized type `usize` + --> $DIR/unnecessary_box_returns.rs:25:21 | LL | fn boxed_usize() -> Box { | ^^^^^^^^^^ help: try: `usize` | = help: changing this also requires a change to the return expressions in this function - = note: `-D clippy::unnecessary-box-returns` implied by `-D warnings` error: boxed return of the sized type `Foo` - --> $DIR/unnecessary_box_returns.rs:11:19 + --> $DIR/unnecessary_box_returns.rs:30:19 | LL | fn boxed_foo() -> Box { | ^^^^^^^^ help: try: `Foo` | = help: changing this also requires a change to the return expressions in this function -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors From a143fb7a11695c45545e6a207f677bd1112032d7 Mon Sep 17 00:00:00 2001 From: Micha White Date: Sun, 26 Feb 2023 13:17:34 -0500 Subject: [PATCH 037/272] Avoid breaking exported API --- book/src/lint_configuration.md | 1 + clippy_lints/src/lib.rs | 6 +- clippy_lints/src/unnecessary_box_returns.rs | 84 +++++++++++++-------- clippy_lints/src/utils/conf.rs | 2 +- tests/ui/unnecessary_box_returns.rs | 9 ++- tests/ui/unnecessary_box_returns.stderr | 6 +- 6 files changed, 68 insertions(+), 40 deletions(-) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 9ed6627b7413..dbd1a404150a 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -130,6 +130,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat * [option_option](https://rust-lang.github.io/rust-clippy/master/index.html#option_option) * [linkedlist](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist) * [rc_mutex](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex) +* [unnecessary_box_returns](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns) ### msrv diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c172ee263c6a..117732c6efe9 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -941,7 +941,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute)); store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(msrv()))); store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct)); - store.register_late_pass(|_| Box::new(unnecessary_box_returns::UnnecessaryBoxReturns)); + store.register_late_pass(move |_| { + Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new( + avoid_breaking_exported_api, + )) + }); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs index 77c1506e5429..10aee89606dd 100644 --- a/clippy_lints/src/unnecessary_box_returns.rs +++ b/clippy_lints/src/unnecessary_box_returns.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::{def_id::LocalDefId, FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { /// ### What it does @@ -32,48 +32,66 @@ declare_clippy_lint! { pedantic, "Needlessly returning a Box" } -declare_lint_pass!(UnnecessaryBoxReturns => [UNNECESSARY_BOX_RETURNS]); -fn check_fn_decl(cx: &LateContext<'_>, decl: &FnDecl<'_>, def_id: LocalDefId) { - let FnRetTy::Return(return_ty_hir) = &decl.output else { return }; +pub struct UnnecessaryBoxReturns { + avoid_breaking_exported_api: bool, +} - let return_ty = cx - .tcx - .erase_late_bound_regions(cx.tcx.fn_sig(def_id).skip_binder()) - .output(); +impl_lint_pass!(UnnecessaryBoxReturns => [UNNECESSARY_BOX_RETURNS]); - if !return_ty.is_box() { - return; +impl UnnecessaryBoxReturns { + pub fn new(avoid_breaking_exported_api: bool) -> Self { + Self { + avoid_breaking_exported_api, + } } - let boxed_ty = return_ty.boxed_ty(); + fn check_fn_decl(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>, def_id: LocalDefId) { + // we don't want to tell someone to break an exported function if they ask us not to + if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) { + return; + } - // it's sometimes useful to return Box if T is unsized, so don't lint those - if boxed_ty.is_sized(cx.tcx, cx.param_env) { - span_lint_and_then( - cx, - UNNECESSARY_BOX_RETURNS, - return_ty_hir.span, - format!("boxed return of the sized type `{boxed_ty}`").as_str(), - |diagnostic| { - diagnostic.span_suggestion( - return_ty_hir.span, - "try", - boxed_ty.to_string(), - // the return value and function callers also needs to - // be changed, so this can't be MachineApplicable - Applicability::Unspecified, - ); - diagnostic.help("changing this also requires a change to the return expressions in this function"); - }, - ); + let FnRetTy::Return(return_ty_hir) = &decl.output else { return }; + + let return_ty = cx + .tcx + .erase_late_bound_regions(cx.tcx.fn_sig(def_id).skip_binder()) + .output(); + + if !return_ty.is_box() { + return; + } + + let boxed_ty = return_ty.boxed_ty(); + + // it's sometimes useful to return Box if T is unsized, so don't lint those + if boxed_ty.is_sized(cx.tcx, cx.param_env) { + span_lint_and_then( + cx, + UNNECESSARY_BOX_RETURNS, + return_ty_hir.span, + format!("boxed return of the sized type `{boxed_ty}`").as_str(), + |diagnostic| { + diagnostic.span_suggestion( + return_ty_hir.span, + "try", + boxed_ty.to_string(), + // the return value and function callers also needs to + // be changed, so this can't be MachineApplicable + Applicability::Unspecified, + ); + diagnostic.help("changing this also requires a change to the return expressions in this function"); + }, + ); + } } } impl LateLintPass<'_> for UnnecessaryBoxReturns { fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) { let TraitItemKind::Fn(signature, _) = &item.kind else { return }; - check_fn_decl(cx, signature.decl, item.owner_id.def_id); + self.check_fn_decl(cx, signature.decl, item.owner_id.def_id); } fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) { @@ -86,11 +104,11 @@ impl LateLintPass<'_> for UnnecessaryBoxReturns { } let ImplItemKind::Fn(signature, ..) = &item.kind else { return }; - check_fn_decl(cx, signature.decl, item.owner_id.def_id); + self.check_fn_decl(cx, signature.decl, item.owner_id.def_id); } fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { let ItemKind::Fn(signature, ..) = &item.kind else { return }; - check_fn_decl(cx, signature.decl, item.owner_id.def_id); + self.check_fn_decl(cx, signature.decl, item.owner_id.def_id); } } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 8ba252425a3d..5384ae01f926 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -249,7 +249,7 @@ define_Conf! { /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] /// ``` (arithmetic_side_effects_allowed_unary: rustc_data_structures::fx::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. + /// 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. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), diff --git a/tests/ui/unnecessary_box_returns.rs b/tests/ui/unnecessary_box_returns.rs index 399266f90b0c..f2f6aae380e9 100644 --- a/tests/ui/unnecessary_box_returns.rs +++ b/tests/ui/unnecessary_box_returns.rs @@ -5,7 +5,7 @@ trait Bar { fn baz(&self) -> Box; } -struct Foo {} +pub struct Foo {} impl Bar for Foo { // don't lint: this is a problem with the trait, not the implementation @@ -27,7 +27,12 @@ fn boxed_usize() -> Box { } // lint -fn boxed_foo() -> Box { +fn _boxed_foo() -> Box { + Box::new(Foo {}) +} + +// don't lint: this is exported +pub fn boxed_foo() -> Box { Box::new(Foo {}) } diff --git a/tests/ui/unnecessary_box_returns.stderr b/tests/ui/unnecessary_box_returns.stderr index a431e37a201b..0870af5f28f7 100644 --- a/tests/ui/unnecessary_box_returns.stderr +++ b/tests/ui/unnecessary_box_returns.stderr @@ -24,10 +24,10 @@ LL | fn boxed_usize() -> Box { = help: changing this also requires a change to the return expressions in this function error: boxed return of the sized type `Foo` - --> $DIR/unnecessary_box_returns.rs:30:19 + --> $DIR/unnecessary_box_returns.rs:30:20 | -LL | fn boxed_foo() -> Box { - | ^^^^^^^^ help: try: `Foo` +LL | fn _boxed_foo() -> Box { + | ^^^^^^^^ help: try: `Foo` | = help: changing this also requires a change to the return expressions in this function From 76d13bb7fa20ba316c75023c66d74fed8e1881df Mon Sep 17 00:00:00 2001 From: Micha White Date: Sun, 26 Mar 2023 11:00:10 -0400 Subject: [PATCH 038/272] Don't lint functions with "box" in their name --- clippy_lints/src/unnecessary_box_returns.rs | 14 ++++++++++---- tests/ui/unnecessary_box_returns.rs | 13 +++++++++---- tests/ui/unnecessary_box_returns.stderr | 12 ++++++------ 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs index 10aee89606dd..912bcda630b8 100644 --- a/clippy_lints/src/unnecessary_box_returns.rs +++ b/clippy_lints/src/unnecessary_box_returns.rs @@ -3,6 +3,7 @@ use rustc_errors::Applicability; use rustc_hir::{def_id::LocalDefId, FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::Symbol; declare_clippy_lint! { /// ### What it does @@ -46,12 +47,17 @@ impl UnnecessaryBoxReturns { } } - fn check_fn_decl(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>, def_id: LocalDefId) { + fn check_fn_item(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>, def_id: LocalDefId, name: Symbol) { // we don't want to tell someone to break an exported function if they ask us not to if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) { return; } + // functions which contain the word "box" are exempt from this lint + if name.as_str().contains("box") { + return; + } + let FnRetTy::Return(return_ty_hir) = &decl.output else { return }; let return_ty = cx @@ -91,7 +97,7 @@ impl UnnecessaryBoxReturns { impl LateLintPass<'_> for UnnecessaryBoxReturns { fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) { let TraitItemKind::Fn(signature, _) = &item.kind else { return }; - self.check_fn_decl(cx, signature.decl, item.owner_id.def_id); + self.check_fn_item(cx, signature.decl, item.owner_id.def_id, item.ident.name); } fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) { @@ -104,11 +110,11 @@ impl LateLintPass<'_> for UnnecessaryBoxReturns { } let ImplItemKind::Fn(signature, ..) = &item.kind else { return }; - self.check_fn_decl(cx, signature.decl, item.owner_id.def_id); + self.check_fn_item(cx, signature.decl, item.owner_id.def_id, item.ident.name); } fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { let ItemKind::Fn(signature, ..) = &item.kind else { return }; - self.check_fn_decl(cx, signature.decl, item.owner_id.def_id); + self.check_fn_item(cx, signature.decl, item.owner_id.def_id, item.ident.name); } } diff --git a/tests/ui/unnecessary_box_returns.rs b/tests/ui/unnecessary_box_returns.rs index f2f6aae380e9..fe60d929759b 100644 --- a/tests/ui/unnecessary_box_returns.rs +++ b/tests/ui/unnecessary_box_returns.rs @@ -22,25 +22,30 @@ impl Foo { } // lint -fn boxed_usize() -> Box { +fn bxed_usize() -> Box { Box::new(5) } // lint -fn _boxed_foo() -> Box { +fn _bxed_foo() -> Box { Box::new(Foo {}) } // don't lint: this is exported -pub fn boxed_foo() -> Box { +pub fn bxed_foo() -> Box { Box::new(Foo {}) } // don't lint: str is unsized -fn boxed_str() -> Box { +fn bxed_str() -> Box { "Hello, world!".to_string().into_boxed_str() } +// don't lint: function contains the word, "box" +fn boxed_usize() -> Box { + Box::new(7) +} + // don't lint: this has an unspecified return type fn default() {} diff --git a/tests/ui/unnecessary_box_returns.stderr b/tests/ui/unnecessary_box_returns.stderr index 0870af5f28f7..b17512c10a17 100644 --- a/tests/ui/unnecessary_box_returns.stderr +++ b/tests/ui/unnecessary_box_returns.stderr @@ -16,18 +16,18 @@ LL | fn baz(&self) -> Box { = help: changing this also requires a change to the return expressions in this function error: boxed return of the sized type `usize` - --> $DIR/unnecessary_box_returns.rs:25:21 + --> $DIR/unnecessary_box_returns.rs:25:20 | -LL | fn boxed_usize() -> Box { - | ^^^^^^^^^^ help: try: `usize` +LL | fn bxed_usize() -> Box { + | ^^^^^^^^^^ help: try: `usize` | = help: changing this also requires a change to the return expressions in this function error: boxed return of the sized type `Foo` - --> $DIR/unnecessary_box_returns.rs:30:20 + --> $DIR/unnecessary_box_returns.rs:30:19 | -LL | fn _boxed_foo() -> Box { - | ^^^^^^^^ help: try: `Foo` +LL | fn _bxed_foo() -> Box { + | ^^^^^^^^ help: try: `Foo` | = help: changing this also requires a change to the return expressions in this function From df65d21f4c98a19573f1cd89d9ff01ee8812cf43 Mon Sep 17 00:00:00 2001 From: bluthej Date: Mon, 27 Mar 2023 11:11:40 +0200 Subject: [PATCH 039/272] Include tests where the iterator is used later --- tests/ui/clear_with_drain.fixed | 10 ++++++---- tests/ui/clear_with_drain.rs | 10 ++++++---- tests/ui/clear_with_drain.stderr | 12 ++++++------ 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/tests/ui/clear_with_drain.fixed b/tests/ui/clear_with_drain.fixed index 0a15463ddf79..9c4dc010ca7f 100644 --- a/tests/ui/clear_with_drain.fixed +++ b/tests/ui/clear_with_drain.fixed @@ -10,7 +10,8 @@ fn range() { let n = v.drain(0..v.len()).count(); // Yay let mut v = vec![1, 2, 3]; - let n = v.drain(usize::MIN..v.len()).count(); // Yay + let iter = v.drain(usize::MIN..v.len()); // Yay + let n = iter.count(); let mut v = vec![1, 2, 3]; v.clear(); // Nay @@ -24,7 +25,8 @@ fn range_from() { let iter = v.drain(0..); // Yay let mut v = vec![1, 2, 3]; - let next = v.drain(0..).next(); // Yay + let mut iter = v.drain(0..); // Yay + let next = iter.next(); let mut v = vec![1, 2, 3]; let next = v.drain(usize::MIN..).next(); // Yay @@ -55,8 +57,8 @@ fn range_to() { let iter = v.drain(..v.len()); // Yay let mut v = vec![1, 2, 3]; - // Yay - for x in v.drain(..v.len()) { + let iter = v.drain(..v.len()); // Yay + for x in iter { let y = format!("x = {x}"); } diff --git a/tests/ui/clear_with_drain.rs b/tests/ui/clear_with_drain.rs index 40201d9cc4df..f00dbab234cc 100644 --- a/tests/ui/clear_with_drain.rs +++ b/tests/ui/clear_with_drain.rs @@ -10,7 +10,8 @@ fn range() { let n = v.drain(0..v.len()).count(); // Yay let mut v = vec![1, 2, 3]; - let n = v.drain(usize::MIN..v.len()).count(); // Yay + let iter = v.drain(usize::MIN..v.len()); // Yay + let n = iter.count(); let mut v = vec![1, 2, 3]; v.drain(0..v.len()); // Nay @@ -24,7 +25,8 @@ fn range_from() { let iter = v.drain(0..); // Yay let mut v = vec![1, 2, 3]; - let next = v.drain(0..).next(); // Yay + let mut iter = v.drain(0..); // Yay + let next = iter.next(); let mut v = vec![1, 2, 3]; let next = v.drain(usize::MIN..).next(); // Yay @@ -55,8 +57,8 @@ fn range_to() { let iter = v.drain(..v.len()); // Yay let mut v = vec![1, 2, 3]; - // Yay - for x in v.drain(..v.len()) { + let iter = v.drain(..v.len()); // Yay + for x in iter { let y = format!("x = {x}"); } diff --git a/tests/ui/clear_with_drain.stderr b/tests/ui/clear_with_drain.stderr index e7152a1cb687..c88aa1a23cb6 100644 --- a/tests/ui/clear_with_drain.stderr +++ b/tests/ui/clear_with_drain.stderr @@ -1,5 +1,5 @@ error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:16:7 + --> $DIR/clear_with_drain.rs:17:7 | LL | v.drain(0..v.len()); // Nay | ^^^^^^^^^^^^^^^^^ help: try: `clear()` @@ -7,31 +7,31 @@ LL | v.drain(0..v.len()); // Nay = note: `-D clippy::clear-with-drain` implied by `-D warnings` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:19:7 + --> $DIR/clear_with_drain.rs:20:7 | LL | v.drain(usize::MIN..v.len()); // Nay | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:33:7 + --> $DIR/clear_with_drain.rs:35:7 | LL | v.drain(0..); // Nay | ^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:36:7 + --> $DIR/clear_with_drain.rs:38:7 | LL | v.drain(usize::MIN..); // Nay | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:50:7 + --> $DIR/clear_with_drain.rs:52:7 | LL | v.drain(..); // Nay | ^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:64:7 + --> $DIR/clear_with_drain.rs:66:7 | LL | v.drain(..v.len()); // Nay | ^^^^^^^^^^^^^^^^ help: try: `clear()` From 28b80059ed3ff5ade532e5547af8be0612927fe5 Mon Sep 17 00:00:00 2001 From: Jamen Marz Date: Mon, 27 Mar 2023 10:14:08 -0400 Subject: [PATCH 040/272] Add notes to non-structural const in pattern error message --- tests/ui/crashes/ice-6254.stderr | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/ui/crashes/ice-6254.stderr b/tests/ui/crashes/ice-6254.stderr index 22d82a30c6aa..263c27d3d646 100644 --- a/tests/ui/crashes/ice-6254.stderr +++ b/tests/ui/crashes/ice-6254.stderr @@ -6,6 +6,8 @@ LL | FOO_REF_REF => {}, | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #62411 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details = note: `-D indirect-structural-match` implied by `-D warnings` error: aborting due to previous error From fc6262fa0c0cd9bd3e32b3db4f3df5c268acf291 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 16 Mar 2023 22:00:08 +0000 Subject: [PATCH 041/272] Add `(..)` syntax for RTN --- clippy_lints/src/ref_option_ref.rs | 4 ++-- clippy_lints/src/types/borrowed_box.rs | 2 +- clippy_lints/src/types/utils.rs | 4 ++-- clippy_lints/src/use_self.rs | 5 +++-- clippy_utils/src/hir_utils.rs | 7 +------ 5 files changed, 9 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs index 448a32b77c03..c984a8286eb8 100644 --- a/clippy_lints/src/ref_option_ref.rs +++ b/clippy_lints/src/ref_option_ref.rs @@ -3,7 +3,7 @@ use clippy_utils::last_path_segment; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{GenericArg, Mutability, Ty, TyKind}; +use rustc_hir::{GenericArg, GenericArgsParentheses, Mutability, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; @@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for RefOptionRef { if cx.tcx.is_diagnostic_item(sym::Option, def_id); if let Some(params) = last_path_segment(qpath).args ; - if !params.parenthesized; + if params.parenthesized == GenericArgsParentheses::No; if let Some(inner_ty) = params.args.iter().find_map(|arg| match arg { GenericArg::Type(inner_ty) => Some(inner_ty), _ => None, diff --git a/clippy_lints/src/types/borrowed_box.rs b/clippy_lints/src/types/borrowed_box.rs index 65dfe7637ea9..acdf54710691 100644 --- a/clippy_lints/src/types/borrowed_box.rs +++ b/clippy_lints/src/types/borrowed_box.rs @@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m if let QPath::Resolved(None, path) = *qpath; if let [ref bx] = *path.segments; if let Some(params) = bx.args; - if !params.parenthesized; + if params.parenthesized == hir::GenericArgsParentheses::No; if let Some(inner) = params.args.iter().find_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), _ => None, diff --git a/clippy_lints/src/types/utils.rs b/clippy_lints/src/types/utils.rs index 7f43b7841ff3..a30748db88fc 100644 --- a/clippy_lints/src/types/utils.rs +++ b/clippy_lints/src/types/utils.rs @@ -1,6 +1,6 @@ use clippy_utils::last_path_segment; use if_chain::if_chain; -use rustc_hir::{GenericArg, QPath, TyKind}; +use rustc_hir::{GenericArg, GenericArgsParentheses, QPath, TyKind}; use rustc_lint::LateContext; use rustc_span::source_map::Span; @@ -8,7 +8,7 @@ pub(super) fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) let last = last_path_segment(qpath); if_chain! { if let Some(params) = last.args; - if !params.parenthesized; + if params.parenthesized == GenericArgsParentheses::No; if let Some(ty) = params.args.iter().find_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), _ => None, diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 8ea5475fb252..7dfb0956077e 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -10,7 +10,7 @@ use rustc_hir::{ def::{CtorOf, DefKind, Res}, def_id::LocalDefId, intravisit::{walk_inf, walk_ty, Visitor}, - Expr, ExprKind, FnRetTy, FnSig, GenericArg, GenericParam, GenericParamKind, HirId, Impl, ImplItemKind, Item, + Expr, ExprKind, FnRetTy, FnSig, GenericArg, GenericArgsParentheses, GenericParam, GenericParamKind, HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind, }; use rustc_hir_analysis::hir_ty_to_ty; @@ -100,7 +100,8 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { if let TyKind::Path(QPath::Resolved(_, item_path)) = self_ty.kind; let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args; if parameters.as_ref().map_or(true, |params| { - !params.parenthesized && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))) + params.parenthesized == GenericArgsParentheses::No + && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))) }); if !item.span.from_expansion(); if !is_from_proc_macro(cx, item); // expensive, should be last check diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 3a6d23ca5c10..3ee7147828bd 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -401,14 +401,9 @@ impl HirEqInterExpr<'_, '_, '_> { } fn eq_path_parameters(&mut self, left: &GenericArgs<'_>, right: &GenericArgs<'_>) -> bool { - if !(left.parenthesized || right.parenthesized) { + if left.parenthesized == right.parenthesized { over(left.args, right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work && over(left.bindings, right.bindings, |l, r| self.eq_type_binding(l, r)) - } else if left.parenthesized && right.parenthesized { - over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r)) - && both(&Some(&left.bindings[0].ty()), &Some(&right.bindings[0].ty()), |l, r| { - self.eq_ty(l, r) - }) } else { false } From 3259b48568c4fe19b60a47011c9fe424b707533c Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Tue, 28 Mar 2023 12:22:22 +0000 Subject: [PATCH 042/272] Migrate `format_args.rs` to `rustc_ast::FormatArgs` No longer lints empty precisions `{:.}` as the spans aren't available --- clippy_lints/Cargo.toml | 1 + clippy_lints/src/format_args.rs | 220 ++++++++++-------- .../src/utils/format_args_collector.rs | 79 ++++++- clippy_utils/src/macros.rs | 73 +++--- .../uninlined_format_args.stderr | 24 +- tests/ui/uninlined_format_args.fixed | 2 +- tests/ui/uninlined_format_args.stderr | 14 +- tests/ui/unused_format_specs.fixed | 18 -- tests/ui/unused_format_specs.rs | 18 -- tests/ui/unused_format_specs.stderr | 54 ----- tests/ui/unused_format_specs_unfixable.stderr | 12 +- 11 files changed, 270 insertions(+), 245 deletions(-) delete mode 100644 tests/ui/unused_format_specs.fixed delete mode 100644 tests/ui/unused_format_specs.rs delete mode 100644 tests/ui/unused_format_specs.stderr diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 6701bedfe5ed..5c6040f63f50 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -9,6 +9,7 @@ keywords = ["clippy", "lint", "plugin"] edition = "2021" [dependencies] +arrayvec = { version = "0.7", default-features = false } cargo_metadata = "0.15.3" clippy_utils = { path = "../clippy_utils" } declare_clippy_lint = { path = "../declare_clippy_lint" } diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index e7caed65bf28..08e45ed7d0ec 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -1,27 +1,31 @@ +use arrayvec::ArrayVec; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diag_trait_item; -use clippy_utils::macros::FormatParamKind::{Implicit, Named, NamedInline, Numbered, Starred}; use clippy_utils::macros::{ - is_assert_macro, is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam, - FormatParamUsage, + find_format_arg_expr, find_format_args, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, + is_format_macro, is_panic, root_macro_call, root_macro_call_first_node, FormatParamUsage, }; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; use if_chain::if_chain; use itertools::Itertools; +use rustc_ast::{ + FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions, + FormatPlaceholder, FormatTrait, +}; use rustc_errors::{ Applicability, SuggestionStyle::{CompletelyHidden, ShowCode}, }; -use rustc_hir::{Expr, ExprKind, HirId, LangItem, QPath}; +use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::Ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::DefId; use rustc_span::edition::Edition::Edition2021; -use rustc_span::{sym, ExpnData, ExpnKind, Span, Symbol}; +use rustc_span::{sym, Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -184,72 +188,79 @@ impl FormatArgs { impl<'tcx> LateLintPass<'tcx> for FormatArgs { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let Some(format_args) = FormatArgsExpn::parse(cx, expr) - && let expr_expn_data = expr.span.ctxt().outer_expn_data() - && let outermost_expn_data = outermost_expn_data(expr_expn_data) - && let Some(macro_def_id) = outermost_expn_data.macro_def_id - && is_format_macro(cx, macro_def_id) - && let ExpnKind::Macro(_, name) = outermost_expn_data.kind - { - for arg in &format_args.args { - check_unused_format_specifier(cx, arg); - if !arg.format.is_default() { - continue; - } - if is_aliased(&format_args, arg.param.value.hir_id) { - continue; - } - check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.param.value); - check_to_string_in_format_args(cx, name, arg.param.value); - } - if self.msrv.meets(msrvs::FORMAT_ARGS_CAPTURE) { - check_uninlined_args(cx, &format_args, outermost_expn_data.call_site, macro_def_id, self.ignore_mixed); - } + let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return }; + if !is_format_macro(cx, macro_call.def_id) { + return; } + let name = cx.tcx.item_name(macro_call.def_id); + + find_format_args(cx, expr, macro_call.expn, |format_args| { + for piece in &format_args.template { + if let FormatArgsPiece::Placeholder(placeholder) = piece + && let Ok(index) = placeholder.argument.index + && let Some(arg) = format_args.arguments.all_args().get(index) + { + let arg_expr = find_format_arg_expr(expr, arg); + + check_unused_format_specifier(cx, placeholder, arg_expr); + + if placeholder.format_trait != FormatTrait::Display + || placeholder.format_options != FormatOptions::default() + || is_aliased(format_args, index) + { + continue; + } + + if let Ok(arg_hir_expr) = arg_expr { + check_format_in_format_args(cx, macro_call.span, name, arg_hir_expr); + check_to_string_in_format_args(cx, name, arg_hir_expr); + } + } + } + + if self.msrv.meets(msrvs::FORMAT_ARGS_CAPTURE) { + check_uninlined_args(cx, format_args, macro_call.span, macro_call.def_id, self.ignore_mixed); + } + }); } extract_msrv_attr!(LateContext); } -fn check_unused_format_specifier(cx: &LateContext<'_>, arg: &FormatArg<'_>) { - let param_ty = cx.typeck_results().expr_ty(arg.param.value).peel_refs(); +fn check_unused_format_specifier( + cx: &LateContext<'_>, + placeholder: &FormatPlaceholder, + arg_expr: Result<&Expr<'_>, &rustc_ast::Expr>, +) { + let ty_or_ast_expr = arg_expr.map(|expr| cx.typeck_results().expr_ty(expr).peel_refs()); - if let Count::Implied(Some(mut span)) = arg.format.precision - && !span.is_empty() + let is_format_args = match ty_or_ast_expr { + Ok(ty) => is_type_lang_item(cx, ty, LangItem::FormatArguments), + Err(expr) => matches!(expr.peel_parens_and_refs().kind, rustc_ast::ExprKind::FormatArgs(_)), + }; + + let options = &placeholder.format_options; + + let arg_span = match arg_expr { + Ok(expr) => expr.span, + Err(expr) => expr.span, + }; + + if let Some(placeholder_span) = placeholder.span + && is_format_args + && *options != FormatOptions::default() { span_lint_and_then( cx, UNUSED_FORMAT_SPECS, - span, - "empty precision specifier has no effect", - |diag| { - if param_ty.is_floating_point() { - diag.note("a precision specifier is not required to format floats"); - } - - if arg.format.is_default() { - // If there's no other specifiers remove the `:` too - span = arg.format_span(); - } - - diag.span_suggestion_verbose(span, "remove the `.`", "", Applicability::MachineApplicable); - }, - ); - } - - if is_type_lang_item(cx, param_ty, LangItem::FormatArguments) && !arg.format.is_default_for_trait() { - span_lint_and_then( - cx, - UNUSED_FORMAT_SPECS, - arg.span, + placeholder_span, "format specifiers have no effect on `format_args!()`", |diag| { - let mut suggest_format = |spec, span| { + let mut suggest_format = |spec| { let message = format!("for the {spec} to apply consider using `format!()`"); - if let Some(mac_call) = root_macro_call(arg.param.value.span) + if let Some(mac_call) = root_macro_call(arg_span) && cx.tcx.is_diagnostic_item(sym::format_args_macro, mac_call.def_id) - && arg.span.eq_ctxt(mac_call.span) { diag.span_suggestion( cx.sess().source_map().span_until_char(mac_call.span, '!'), @@ -257,25 +268,27 @@ fn check_unused_format_specifier(cx: &LateContext<'_>, arg: &FormatArg<'_>) { "format", Applicability::MaybeIncorrect, ); - } else if let Some(span) = span { - diag.span_help(span, message); + } else { + diag.help(message); } }; - if !arg.format.width.is_implied() { - suggest_format("width", arg.format.width.span()); + if options.width.is_some() { + suggest_format("width"); } - if !arg.format.precision.is_implied() { - suggest_format("precision", arg.format.precision.span()); + if options.precision.is_some() { + suggest_format("precision"); } - diag.span_suggestion_verbose( - arg.format_span(), - "if the current behavior is intentional, remove the format specifiers", - "", - Applicability::MaybeIncorrect, - ); + if let Some(format_span) = format_placeholder_format_span(placeholder) { + diag.span_suggestion_verbose( + format_span, + "if the current behavior is intentional, remove the format specifiers", + "", + Applicability::MaybeIncorrect, + ); + } }, ); } @@ -283,12 +296,12 @@ fn check_unused_format_specifier(cx: &LateContext<'_>, arg: &FormatArg<'_>) { fn check_uninlined_args( cx: &LateContext<'_>, - args: &FormatArgsExpn<'_>, + args: &rustc_ast::FormatArgs, call_site: Span, def_id: DefId, ignore_mixed: bool, ) { - if args.format_string.span.from_expansion() { + if args.span.from_expansion() { return; } if call_site.edition() < Edition2021 && (is_panic(cx, def_id) || is_assert_macro(cx, def_id)) { @@ -303,7 +316,13 @@ fn check_uninlined_args( // we cannot remove any other arguments in the format string, // because the index numbers might be wrong after inlining. // Example of an un-inlinable format: print!("{}{1}", foo, 2) - if !args.params().all(|p| check_one_arg(args, &p, &mut fixes, ignore_mixed)) || fixes.is_empty() { + for (pos, usage) in format_arg_positions(args) { + if !check_one_arg(args, pos, usage, &mut fixes, ignore_mixed) { + return; + } + } + + if fixes.is_empty() { return; } @@ -332,38 +351,36 @@ fn check_uninlined_args( } fn check_one_arg( - args: &FormatArgsExpn<'_>, - param: &FormatParam<'_>, + args: &rustc_ast::FormatArgs, + pos: &FormatArgPosition, + usage: FormatParamUsage, fixes: &mut Vec<(Span, String)>, ignore_mixed: bool, ) -> bool { - if matches!(param.kind, Implicit | Starred | Named(_) | Numbered) - && let ExprKind::Path(QPath::Resolved(None, path)) = param.value.kind - && let [segment] = path.segments + let index = pos.index.unwrap(); + let arg = &args.arguments.all_args()[index]; + + if !matches!(arg.kind, FormatArgumentKind::Captured(_)) + && let rustc_ast::ExprKind::Path(None, path) = &arg.expr.kind + && let [segment] = path.segments.as_slice() && segment.args.is_none() - && let Some(arg_span) = args.value_with_prev_comma_span(param.value.hir_id) + && let Some(arg_span) = format_arg_removal_span(args, index) + && let Some(pos_span) = pos.span { - let replacement = match param.usage { + let replacement = match usage { FormatParamUsage::Argument => segment.ident.name.to_string(), FormatParamUsage::Width => format!("{}$", segment.ident.name), FormatParamUsage::Precision => format!(".{}$", segment.ident.name), }; - fixes.push((param.span, replacement)); + fixes.push((pos_span, replacement)); fixes.push((arg_span, String::new())); true // successful inlining, continue checking } else { // Do not continue inlining (return false) in case // * if we can't inline a numbered argument, e.g. `print!("{0} ...", foo.bar, ...)` // * if allow_mixed_uninlined_format_args is false and this arg hasn't been inlined already - param.kind != Numbered && (!ignore_mixed || matches!(param.kind, NamedInline(_))) - } -} - -fn outermost_expn_data(expn_data: ExpnData) -> ExpnData { - if expn_data.call_site.from_expansion() { - outermost_expn_data(expn_data.call_site.ctxt().outer_expn_data()) - } else { - expn_data + pos.kind != FormatArgPositionKind::Number + && (!ignore_mixed || matches!(arg.kind, FormatArgumentKind::Captured(_))) } } @@ -438,10 +455,31 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex } } -/// Returns true if `hir_id` is referred to by multiple format params -fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool { - args.params() - .filter(|param| param.value.hir_id == hir_id) +fn format_arg_positions( + format_args: &rustc_ast::FormatArgs, +) -> impl Iterator { + format_args.template.iter().flat_map(|piece| match piece { + FormatArgsPiece::Placeholder(placeholder) => { + let mut positions = ArrayVec::<_, 3>::new(); + + positions.push((&placeholder.argument, FormatParamUsage::Argument)); + if let Some(FormatCount::Argument(position)) = &placeholder.format_options.width { + positions.push((position, FormatParamUsage::Width)); + } + if let Some(FormatCount::Argument(position)) = &placeholder.format_options.precision { + positions.push((position, FormatParamUsage::Precision)); + } + + positions + }, + FormatArgsPiece::Literal(_) => ArrayVec::new(), + }) +} + +/// Returns true if the format argument at `index` is referred to by multiple format params +fn is_aliased(format_args: &rustc_ast::FormatArgs, index: usize) -> bool { + format_arg_positions(format_args) + .filter(|(position, _)| position.index == Ok(index)) .at_most_one() .is_err() } diff --git a/clippy_lints/src/utils/format_args_collector.rs b/clippy_lints/src/utils/format_args_collector.rs index be56b842b98c..09fcb82c37c8 100644 --- a/clippy_lints/src/utils/format_args_collector.rs +++ b/clippy_lints/src/utils/format_args_collector.rs @@ -1,7 +1,12 @@ use clippy_utils::macros::collect_ast_format_args; -use rustc_ast::{Expr, ExprKind}; +use clippy_utils::source::snippet_opt; +use itertools::Itertools; +use rustc_ast::{Expr, ExprKind, FormatArgs}; +use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::hygiene; +use std::iter::once; declare_clippy_lint! { /// ### What it does @@ -15,9 +20,79 @@ declare_clippy_lint! { declare_lint_pass!(FormatArgsCollector => [FORMAT_ARGS_COLLECTOR]); impl EarlyLintPass for FormatArgsCollector { - fn check_expr(&mut self, _: &EarlyContext<'_>, expr: &Expr) { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::FormatArgs(args) = &expr.kind { + if has_span_from_proc_macro(cx, args) { + return; + } + collect_ast_format_args(expr.span, args); } } } + +/// Detects if the format string or an argument has its span set by a proc macro to something inside +/// a macro callsite, e.g. +/// +/// ```ignore +/// println!(some_proc_macro!("input {}"), a); +/// ``` +/// +/// Where `some_proc_macro` expands to +/// +/// ```ignore +/// println!("output {}", a); +/// ``` +/// +/// But with the span of `"output {}"` set to the macro input +/// +/// ```ignore +/// println!(some_proc_macro!("input {}"), a); +/// // ^^^^^^^^^^ +/// ``` +fn has_span_from_proc_macro(cx: &EarlyContext<'_>, args: &FormatArgs) -> bool { + let ctxt = args.span.ctxt(); + + // `format!("{} {} {c}", "one", "two", c = "three")` + // ^^^^^ ^^^^^ ^^^^^^^ + let argument_span = args + .arguments + .explicit_args() + .iter() + .map(|argument| hygiene::walk_chain(argument.expr.span, ctxt)); + + // `format!("{} {} {c}", "one", "two", c = "three")` + // ^^ ^^ ^^^^^^ + let between_spans = once(args.span) + .chain(argument_span) + .tuple_windows() + .map(|(start, end)| start.between(end)); + + for between_span in between_spans { + let mut seen_comma = false; + + let Some(snippet) = snippet_opt(cx, between_span) else { return true }; + for token in tokenize(&snippet) { + match token.kind { + TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace => {}, + TokenKind::Comma if !seen_comma => seen_comma = true, + // named arguments, `start_val, name = end_val` + // ^^^^^^^^^ between_span + TokenKind::Ident | TokenKind::Eq if seen_comma => {}, + // An unexpected token usually indicates that we crossed a macro boundary + // + // `println!(some_proc_macro!("input {}"), a)` + // ^^^ between_span + // `println!("{}", val!(x))` + // ^^^^^^^ between_span + _ => return true, + } + } + + if !seen_comma { + return true; + } + } + + false +} diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index c0e32068ecac..b03e0d4a1ca5 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -6,7 +6,7 @@ use crate::visitors::{for_each_expr, Descend}; use arrayvec::ArrayVec; use itertools::{izip, Either, Itertools}; use rustc_ast::ast::LitKind; -use rustc_ast::FormatArgs; +use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, LangItem, Node, QPath, TyKind}; @@ -391,30 +391,67 @@ pub fn collect_ast_format_args(span: Span, format_args: &FormatArgs) { }); } -/// Calls `callback` with an AST [`FormatArgs`] node if one is found +/// Calls `callback` with an AST [`FormatArgs`] node if a `format_args` expansion is found as a +/// descendant of `expn_id` pub fn find_format_args(cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId, callback: impl FnOnce(&FormatArgs)) { let format_args_expr = for_each_expr(start, |expr| { let ctxt = expr.span.ctxt(); - if ctxt == start.span.ctxt() { - ControlFlow::Continue(Descend::Yes) - } else if ctxt.outer_expn().is_descendant_of(expn_id) - && macro_backtrace(expr.span) + if ctxt.outer_expn().is_descendant_of(expn_id) { + if macro_backtrace(expr.span) .map(|macro_call| cx.tcx.item_name(macro_call.def_id)) .any(|name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl)) - { - ControlFlow::Break(expr) + { + ControlFlow::Break(expr) + } else { + ControlFlow::Continue(Descend::Yes) + } } else { ControlFlow::Continue(Descend::No) } }); - if let Some(format_args_expr) = format_args_expr { + if let Some(expr) = format_args_expr { AST_FORMAT_ARGS.with(|ast_format_args| { - ast_format_args.borrow().get(&format_args_expr.span).map(callback); + ast_format_args.borrow().get(&expr.span).map(callback); }); } } +/// Attempt to find the [`rustc_hir::Expr`] that corresponds to the [`FormatArgument`]'s value, if +/// it cannot be found it will return the [`rustc_ast::Expr`]. +pub fn find_format_arg_expr<'hir, 'ast>( + start: &'hir Expr<'hir>, + target: &'ast FormatArgument, +) -> Result<&'hir rustc_hir::Expr<'hir>, &'ast rustc_ast::Expr> { + for_each_expr(start, |expr| { + if expr.span == target.expr.span { + ControlFlow::Break(expr) + } else { + ControlFlow::Continue(()) + } + }) + .ok_or(&target.expr) +} + +/// Span of the `:` and format specifiers +/// +/// ```ignore +/// format!("{:.}"), format!("{foo:.}") +/// ^^ ^^ +/// ``` +pub fn format_placeholder_format_span(placeholder: &FormatPlaceholder) -> Option { + let base = placeholder.span?.data(); + + // `base.hi` is `{...}|`, subtract 1 byte (the length of '}') so that it points before the closing + // brace `{...|}` + Some(Span::new( + placeholder.argument.span?.hi(), + base.hi - BytePos(1), + base.ctxt, + base.parent, + )) +} + /// Returns the [`Span`] of the value at `index` extended to the previous comma, e.g. for the value /// `10` /// @@ -897,22 +934,6 @@ pub struct FormatArg<'tcx> { pub span: Span, } -impl<'tcx> FormatArg<'tcx> { - /// Span of the `:` and format specifiers - /// - /// ```ignore - /// format!("{:.}"), format!("{foo:.}") - /// ^^ ^^ - /// ``` - pub fn format_span(&self) -> Span { - let base = self.span.data(); - - // `base.hi` is `{...}|`, subtract 1 byte (the length of '}') so that it points before the closing - // brace `{...|}` - Span::new(self.param.span.hi(), base.hi - BytePos(1), base.ctxt, base.parent) - } -} - /// A parsed `format_args!` expansion. #[derive(Debug)] pub struct FormatArgsExpn<'tcx> { diff --git a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr index ee9417621961..1be0cda12fc1 100644 --- a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr +++ b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr @@ -11,6 +11,18 @@ LL - println!("val='{}'", local_i32); LL + println!("val='{local_i32}'"); | +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:10:5 + | +LL | println!("Hello {} is {:.*}", "x", local_i32, local_f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - println!("Hello {} is {:.*}", "x", local_i32, local_f64); +LL + println!("Hello {} is {local_f64:.local_i32$}", "x"); + | + error: literal with an empty format string --> $DIR/uninlined_format_args.rs:10:35 | @@ -24,18 +36,6 @@ LL - println!("Hello {} is {:.*}", "x", local_i32, local_f64); LL + println!("Hello x is {:.*}", local_i32, local_f64); | -error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:10:5 - | -LL | println!("Hello {} is {:.*}", "x", local_i32, local_f64); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: change this to - | -LL - println!("Hello {} is {:.*}", "x", local_i32, local_f64); -LL + println!("Hello {} is {local_f64:.local_i32$}", "x"); - | - error: variables can be used directly in the `format!` string --> $DIR/uninlined_format_args.rs:11:5 | diff --git a/tests/ui/uninlined_format_args.fixed b/tests/ui/uninlined_format_args.fixed index 1475d781c673..5ecb9a5bf9eb 100644 --- a/tests/ui/uninlined_format_args.fixed +++ b/tests/ui/uninlined_format_args.fixed @@ -119,7 +119,7 @@ fn tester(fn_arg: i32) { println!("Width = {local_i32}, value with width = {local_f64:local_i32$}"); println!("{local_i32:width$.prec$}"); println!("{width:width$.prec$}"); - println!("{}", format!("{local_i32}")); + println!("{}", format!("{}", local_i32)); my_println!("{}", local_i32); my_println_args!("{}", local_i32); diff --git a/tests/ui/uninlined_format_args.stderr b/tests/ui/uninlined_format_args.stderr index a12abf8bef8a..dc4af6ef42ec 100644 --- a/tests/ui/uninlined_format_args.stderr +++ b/tests/ui/uninlined_format_args.stderr @@ -774,18 +774,6 @@ LL - println!("{:w$.p$}", w = width, p = prec); LL + println!("{width:width$.prec$}"); | -error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:125:20 - | -LL | println!("{}", format!("{}", local_i32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: change this to - | -LL - println!("{}", format!("{}", local_i32)); -LL + println!("{}", format!("{local_i32}")); - | - error: variables can be used directly in the `format!` string --> $DIR/uninlined_format_args.rs:143:5 | @@ -856,5 +844,5 @@ LL - println!("expand='{}'", local_i32); LL + println!("expand='{local_i32}'"); | -error: aborting due to 72 previous errors +error: aborting due to 71 previous errors diff --git a/tests/ui/unused_format_specs.fixed b/tests/ui/unused_format_specs.fixed deleted file mode 100644 index 2930722b42d9..000000000000 --- a/tests/ui/unused_format_specs.fixed +++ /dev/null @@ -1,18 +0,0 @@ -// run-rustfix - -#![warn(clippy::unused_format_specs)] -#![allow(unused)] - -fn main() { - let f = 1.0f64; - println!("{}", 1.0); - println!("{f} {f:?}"); - - println!("{}", 1); -} - -fn should_not_lint() { - let f = 1.0f64; - println!("{:.1}", 1.0); - println!("{f:.w$} {f:.*?}", 3, w = 2); -} diff --git a/tests/ui/unused_format_specs.rs b/tests/ui/unused_format_specs.rs deleted file mode 100644 index ee192a000d4b..000000000000 --- a/tests/ui/unused_format_specs.rs +++ /dev/null @@ -1,18 +0,0 @@ -// run-rustfix - -#![warn(clippy::unused_format_specs)] -#![allow(unused)] - -fn main() { - let f = 1.0f64; - println!("{:.}", 1.0); - println!("{f:.} {f:.?}"); - - println!("{:.}", 1); -} - -fn should_not_lint() { - let f = 1.0f64; - println!("{:.1}", 1.0); - println!("{f:.w$} {f:.*?}", 3, w = 2); -} diff --git a/tests/ui/unused_format_specs.stderr b/tests/ui/unused_format_specs.stderr deleted file mode 100644 index 7231c17e74c1..000000000000 --- a/tests/ui/unused_format_specs.stderr +++ /dev/null @@ -1,54 +0,0 @@ -error: empty precision specifier has no effect - --> $DIR/unused_format_specs.rs:8:17 - | -LL | println!("{:.}", 1.0); - | ^ - | - = note: a precision specifier is not required to format floats - = note: `-D clippy::unused-format-specs` implied by `-D warnings` -help: remove the `.` - | -LL - println!("{:.}", 1.0); -LL + println!("{}", 1.0); - | - -error: empty precision specifier has no effect - --> $DIR/unused_format_specs.rs:9:18 - | -LL | println!("{f:.} {f:.?}"); - | ^ - | - = note: a precision specifier is not required to format floats -help: remove the `.` - | -LL - println!("{f:.} {f:.?}"); -LL + println!("{f} {f:.?}"); - | - -error: empty precision specifier has no effect - --> $DIR/unused_format_specs.rs:9:24 - | -LL | println!("{f:.} {f:.?}"); - | ^ - | - = note: a precision specifier is not required to format floats -help: remove the `.` - | -LL - println!("{f:.} {f:.?}"); -LL + println!("{f:.} {f:?}"); - | - -error: empty precision specifier has no effect - --> $DIR/unused_format_specs.rs:11:17 - | -LL | println!("{:.}", 1); - | ^ - | -help: remove the `.` - | -LL - println!("{:.}", 1); -LL + println!("{}", 1); - | - -error: aborting due to 4 previous errors - diff --git a/tests/ui/unused_format_specs_unfixable.stderr b/tests/ui/unused_format_specs_unfixable.stderr index 9f1890282e6a..cb7156b6baf0 100644 --- a/tests/ui/unused_format_specs_unfixable.stderr +++ b/tests/ui/unused_format_specs_unfixable.stderr @@ -37,11 +37,7 @@ error: format specifiers have no effect on `format_args!()` LL | println!("{:5}.", format_args_from_macro!()); | ^^^^ | -help: for the width to apply consider using `format!()` - --> $DIR/unused_format_specs_unfixable.rs:16:17 - | -LL | println!("{:5}.", format_args_from_macro!()); - | ^ + = help: for the width to apply consider using `format!()` help: if the current behavior is intentional, remove the format specifiers | LL - println!("{:5}.", format_args_from_macro!()); @@ -54,11 +50,7 @@ error: format specifiers have no effect on `format_args!()` LL | println!("{args:5}"); | ^^^^^^^^ | -help: for the width to apply consider using `format!()` - --> $DIR/unused_format_specs_unfixable.rs:19:21 - | -LL | println!("{args:5}"); - | ^ + = help: for the width to apply consider using `format!()` help: if the current behavior is intentional, remove the format specifiers | LL - println!("{args:5}"); From 6589d794927451ed5d503b108e0e6900bbf91d3d Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Tue, 28 Mar 2023 21:28:57 +0000 Subject: [PATCH 043/272] Replace remaining usage of `FormatArgsExpn` --- clippy_lints/src/explicit_write.rs | 29 +- clippy_lints/src/format.rs | 91 ++- clippy_lints/src/format_impl.rs | 60 +- clippy_lints/src/methods/expect_fun_call.rs | 27 +- clippy_utils/src/lib.rs | 1 - clippy_utils/src/macros.rs | 727 +------------------- 6 files changed, 132 insertions(+), 803 deletions(-) diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index c0ea6f338a23..315df6c714ff 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::FormatArgsExpn; +use clippy_utils::macros::{find_format_args, format_args_inputs_span}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_expn_of, match_function_call, paths}; use if_chain::if_chain; @@ -8,7 +8,7 @@ use rustc_hir::def::Res; use rustc_hir::{BindingAnnotation, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; +use rustc_span::{sym, ExpnId}; declare_clippy_lint! { /// ### What it does @@ -43,23 +43,22 @@ declare_lint_pass!(ExplicitWrite => [EXPLICIT_WRITE]); impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - // match call to unwrap - if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind; - if unwrap_fun.ident.name == sym::unwrap; + // match call to unwrap + if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind + && unwrap_fun.ident.name == sym::unwrap // match call to write_fmt - if let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind); - if write_fun.ident.name == sym!(write_fmt); + && let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind) + && write_fun.ident.name == sym!(write_fmt) // match calls to std::io::stdout() / std::io::stderr () - if let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() { + && let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() { Some("stdout") } else if match_function_call(cx, write_recv, &paths::STDERR).is_some() { Some("stderr") } else { None - }; - if let Some(format_args) = FormatArgsExpn::parse(cx, write_arg); - then { + } + { + find_format_args(cx, write_arg, ExpnId::root(), |format_args| { let calling_macro = // ordering is important here, since `writeln!` uses `write!` internally if is_expn_of(write_call.span, "writeln").is_some() { @@ -92,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { let mut applicability = Applicability::MachineApplicable; let inputs_snippet = snippet_with_applicability( cx, - format_args.inputs_span(), + format_args_inputs_span(format_args), "..", &mut applicability, ); @@ -104,8 +103,8 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { "try this", format!("{prefix}{sugg_mac}!({inputs_snippet})"), applicability, - ) - } + ); + }); } } } diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 8040938c6263..d34d6e9279e4 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,14 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn}; -use clippy_utils::source::snippet_with_context; +use clippy_utils::macros::{find_format_arg_expr, find_format_args, root_macro_call_first_node}; +use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::sugg::Sugg; -use if_chain::if_chain; +use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::symbol::kw; use rustc_span::{sym, Span}; declare_clippy_lint! { @@ -44,55 +43,53 @@ declare_lint_pass!(UselessFormat => [USELESS_FORMAT]); impl<'tcx> LateLintPass<'tcx> for UselessFormat { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let (format_args, call_site) = if_chain! { - if let Some(macro_call) = root_macro_call_first_node(cx, expr); - if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id); - if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, macro_call.expn); - then { - (format_args, macro_call.span) - } else { - return - } - }; + let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return }; + if !cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) { + return; + } - let mut applicability = Applicability::MachineApplicable; - if format_args.args.is_empty() { - match *format_args.format_string.parts { - [] => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), - [_] => { + find_format_args(cx, expr, macro_call.expn, |format_args| { + let mut applicability = Applicability::MachineApplicable; + let call_site = macro_call.span; + + match (format_args.arguments.all_args(), &format_args.template[..]) { + ([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), + ([], [_]) => { // Simulate macro expansion, converting {{ and }} to { and }. - let s_expand = format_args.format_string.snippet.replace("{{", "{").replace("}}", "}"); + let Some(snippet) = snippet_opt(cx, format_args.span) else { return }; + let s_expand = snippet.replace("{{", "{").replace("}}", "}"); let sugg = format!("{s_expand}.to_string()"); span_useless_format(cx, call_site, sugg, applicability); }, - [..] => {}, + ([arg], [piece]) => { + if let Ok(value) = find_format_arg_expr(expr, arg) + && let FormatArgsPiece::Placeholder(placeholder) = piece + && placeholder.format_trait == FormatTrait::Display + && placeholder.format_options == FormatOptions::default() + && match cx.typeck_results().expr_ty(value).peel_refs().kind() { + ty::Adt(adt, _) => Some(adt.did()) == cx.tcx.lang_items().string(), + ty::Str => true, + _ => false, + } + { + let is_new_string = match value.kind { + ExprKind::Binary(..) => true, + ExprKind::MethodCall(path, ..) => path.ident.name == sym::to_string, + _ => false, + }; + let sugg = if is_new_string { + snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability).0.into_owned() + } else { + let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "", &mut applicability); + format!("{}.to_string()", sugg.maybe_par()) + }; + span_useless_format(cx, call_site, sugg, applicability); + + } + }, + _ => {}, } - } else if let [arg] = &*format_args.args { - let value = arg.param.value; - if_chain! { - if format_args.format_string.parts == [kw::Empty]; - if arg.format.is_default(); - if match cx.typeck_results().expr_ty(value).peel_refs().kind() { - ty::Adt(adt, _) => Some(adt.did()) == cx.tcx.lang_items().string(), - ty::Str => true, - _ => false, - }; - then { - let is_new_string = match value.kind { - ExprKind::Binary(..) => true, - ExprKind::MethodCall(path, ..) => path.ident.name == sym::to_string, - _ => false, - }; - let sugg = if is_new_string { - snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability).0.into_owned() - } else { - let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "", &mut applicability); - format!("{}.to_string()", sugg.maybe_par()) - }; - span_useless_format(cx, call_site, sugg, applicability); - } - } - }; + }); } } diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index ed1342a54654..e3ddbfb5981f 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -1,11 +1,13 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::macros::{is_format_macro, root_macro_call_first_node, FormatArg, FormatArgsExpn}; +use clippy_utils::macros::{find_format_arg_expr, find_format_args, is_format_macro, root_macro_call_first_node}; use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators}; use if_chain::if_chain; +use rustc_ast::{FormatArgsPiece, FormatTrait}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::Span; use rustc_span::{sym, symbol::kw, Symbol}; declare_clippy_lint! { @@ -89,7 +91,7 @@ declare_clippy_lint! { } #[derive(Clone, Copy)] -struct FormatTrait { +struct FormatTraitNames { /// e.g. `sym::Display` name: Symbol, /// `f` in `fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {}` @@ -99,7 +101,7 @@ struct FormatTrait { #[derive(Default)] pub struct FormatImpl { // Whether we are inside Display or Debug trait impl - None for neither - format_trait_impl: Option, + format_trait_impl: Option, } impl FormatImpl { @@ -161,43 +163,57 @@ fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) { } } -fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, impl_trait: FormatTrait) { +fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, impl_trait: FormatTraitNames) { // Check each arg in format calls - do we ever use Display on self (directly or via deref)? - if_chain! { - if let Some(outer_macro) = root_macro_call_first_node(cx, expr); - if let macro_def_id = outer_macro.def_id; - if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, outer_macro.expn); - if is_format_macro(cx, macro_def_id); - then { - for arg in format_args.args { - if arg.format.r#trait != impl_trait.name { - continue; + if let Some(outer_macro) = root_macro_call_first_node(cx, expr) + && let macro_def_id = outer_macro.def_id + && is_format_macro(cx, macro_def_id) + { + find_format_args(cx, expr, outer_macro.expn, |format_args| { + for piece in &format_args.template { + if let FormatArgsPiece::Placeholder(placeholder) = piece + && let trait_name = match placeholder.format_trait { + FormatTrait::Display => sym::Display, + FormatTrait::Debug => sym::Debug, + FormatTrait::LowerExp => sym!(LowerExp), + FormatTrait::UpperExp => sym!(UpperExp), + FormatTrait::Octal => sym!(Octal), + FormatTrait::Pointer => sym::Pointer, + FormatTrait::Binary => sym!(Binary), + FormatTrait::LowerHex => sym!(LowerHex), + FormatTrait::UpperHex => sym!(UpperHex), + } + && trait_name == impl_trait.name + && let Ok(index) = placeholder.argument.index + && let Some(arg) = format_args.arguments.all_args().get(index) + && let Ok(arg_expr) = find_format_arg_expr(expr, arg) + { + check_format_arg_self(cx, expr.span, arg_expr, impl_trait); } - check_format_arg_self(cx, expr, &arg, impl_trait); } - } + }); } } -fn check_format_arg_self(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &FormatArg<'_>, impl_trait: FormatTrait) { +fn check_format_arg_self(cx: &LateContext<'_>, span: Span, arg: &Expr<'_>, impl_trait: FormatTraitNames) { // Handle multiple dereferencing of references e.g. &&self // Handle dereference of &self -> self that is equivalent (i.e. via *self in fmt() impl) // Since the argument to fmt is itself a reference: &self - let reference = peel_ref_operators(cx, arg.param.value); + let reference = peel_ref_operators(cx, arg); let map = cx.tcx.hir(); // Is the reference self? if path_to_local(reference).map(|x| map.name(x)) == Some(kw::SelfLower) { - let FormatTrait { name, .. } = impl_trait; + let FormatTraitNames { name, .. } = impl_trait; span_lint( cx, RECURSIVE_FORMAT_IMPL, - expr.span, + span, &format!("using `self` as `{name}` in `impl {name}` will cause infinite recursion"), ); } } -fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait: FormatTrait) { +fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait: FormatTraitNames) { if_chain! { if let Some(macro_call) = root_macro_call_first_node(cx, expr); if let Some(name) = cx.tcx.get_diagnostic_name(macro_call.def_id); @@ -227,7 +243,7 @@ fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait: } } -fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Option { +fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Option { if_chain! { if impl_item.ident.name == sym::fmt; if let ImplItemKind::Fn(_, body_id) = impl_item.kind; @@ -241,7 +257,7 @@ fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Optio .and_then(|param| param.pat.simple_ident()) .map(|ident| ident.name); - Some(FormatTrait { + Some(FormatTraitNames { name, formatter_name, }) diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index a22285058d48..92d21bb89326 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn}; +use clippy_utils::macros::{find_format_args, format_args_inputs_span, root_macro_call_first_node}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_errors::Applicability; @@ -136,18 +136,19 @@ pub(super) fn check<'tcx>( if !cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) { return; } - let Some(format_args) = FormatArgsExpn::find_nested(cx, arg_root, macro_call.expn) else { return }; - let span = format_args.inputs_span(); - let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); - span_lint_and_sugg( - cx, - EXPECT_FUN_CALL, - span_replace_word, - &format!("use of `{name}` followed by a function call"), - "try this", - format!("unwrap_or_else({closure_args} panic!({sugg}))"), - applicability, - ); + find_format_args(cx, arg_root, macro_call.expn, |format_args| { + let span = format_args_inputs_span(format_args); + let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); + span_lint_and_sugg( + cx, + EXPECT_FUN_CALL, + span_replace_word, + &format!("use of `{name}` followed by a function call"), + "try this", + format!("unwrap_or_else({closure_args} panic!({sugg}))"), + applicability, + ); + }); return; } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 2e839fdf4728..f4af00599cd2 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -33,7 +33,6 @@ extern crate rustc_lexer; extern crate rustc_lint; extern crate rustc_middle; extern crate rustc_mir_dataflow; -extern crate rustc_parse_format; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index b03e0d4a1ca5..62d388a5ece8 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -1,24 +1,16 @@ #![allow(clippy::similar_names)] // `expr` and `expn` -use crate::source::snippet_opt; use crate::visitors::{for_each_expr, Descend}; use arrayvec::ArrayVec; -use itertools::{izip, Either, Itertools}; -use rustc_ast::ast::LitKind; use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder}; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, LangItem, Node, QPath, TyKind}; -use rustc_lexer::unescape::unescape_literal; -use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind}; +use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; use rustc_lint::LateContext; -use rustc_parse_format::{self as rpf, Alignment}; use rustc_span::def_id::DefId; use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; -use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Pos, Span, SpanData, Symbol}; +use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Span, Symbol}; use std::cell::RefCell; -use std::iter::{once, zip}; use std::ops::ControlFlow; use std::sync::atomic::{AtomicBool, Ordering}; @@ -226,11 +218,11 @@ pub enum PanicExpn<'a> { /// A single argument that implements `Display` - `panic!("{}", object)` Display(&'a Expr<'a>), /// Anything else - `panic!("error {}: {}", a, b)` - Format(FormatArgsExpn<'a>), + Format(&'a Expr<'a>), } impl<'a> PanicExpn<'a> { - pub fn parse(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option { + pub fn parse(expr: &'a Expr<'a>) -> Option { let ExprKind::Call(callee, [arg, rest @ ..]) = &expr.kind else { return None }; let ExprKind::Path(QPath::Resolved(_, path)) = &callee.kind else { return None }; let result = match path.segments.last().unwrap().ident.as_str() { @@ -240,7 +232,7 @@ impl<'a> PanicExpn<'a> { let ExprKind::AddrOf(_, _, e) = &arg.kind else { return None }; Self::Display(e) }, - "panic_fmt" => Self::Format(FormatArgsExpn::parse(cx, arg)?), + "panic_fmt" => Self::Format(arg), // Since Rust 1.52, `assert_{eq,ne}` macros expand to use: // `core::panicking::assert_failed(.., left_val, right_val, None | Some(format_args!(..)));` "assert_failed" => { @@ -252,7 +244,7 @@ impl<'a> PanicExpn<'a> { // `msg_arg` is either `None` (no custom message) or `Some(format_args!(..))` (custom message) let msg_arg = &rest[2]; match msg_arg.kind { - ExprKind::Call(_, [fmt_arg]) => Self::Format(FormatArgsExpn::parse(cx, fmt_arg)?), + ExprKind::Call(_, [fmt_arg]) => Self::Format(fmt_arg), _ => Self::Empty, } }, @@ -304,7 +296,7 @@ fn find_assert_args_inner<'a, const N: usize>( let mut args = ArrayVec::new(); let panic_expn = for_each_expr(expr, |e| { if args.is_full() { - match PanicExpn::parse(cx, e) { + match PanicExpn::parse(e) { Some(expn) => ControlFlow::Break(expn), None => ControlFlow::Continue(Descend::Yes), } @@ -452,6 +444,21 @@ pub fn format_placeholder_format_span(placeholder: &FormatPlaceholder) -> Option )) } +/// Span covering the format string and values +/// +/// ```ignore +/// format("{}.{}", 10, 11) +/// // ^^^^^^^^^^^^^^^ +/// ``` +pub fn format_args_inputs_span(format_args: &FormatArgs) -> Span { + match format_args.arguments.explicit_args() { + [] => format_args.span, + [.., last] => format_args + .span + .to(hygiene::walk_chain(last.expr.span, format_args.span.ctxt())), + } +} + /// Returns the [`Span`] of the value at `index` extended to the previous comma, e.g. for the value /// `10` /// @@ -473,251 +480,6 @@ pub fn format_arg_removal_span(format_args: &FormatArgs, index: usize) -> Option Some(current.with_lo(prev.hi())) } -/// The format string doesn't exist in the HIR, so we reassemble it from source code -#[derive(Debug)] -pub struct FormatString { - /// Span of the whole format string literal, including `[r#]"`. - pub span: Span, - /// Snippet of the whole format string literal, including `[r#]"`. - pub snippet: String, - /// If the string is raw `r"..."`/`r#""#`, how many `#`s does it have on each side. - pub style: Option, - /// The unescaped value of the format string, e.g. `"val – {}"` for the literal - /// `"val \u{2013} {}"`. - pub unescaped: String, - /// The format string split by format args like `{..}`. - pub parts: Vec, -} - -impl FormatString { - fn new(cx: &LateContext<'_>, pieces: &Expr<'_>) -> Option { - // format_args!(r"a {} b \", 1); - // - // expands to - // - // ::core::fmt::Arguments::new_v1(&["a ", " b \\"], - // &[::core::fmt::ArgumentV1::new_display(&1)]); - // - // where `pieces` is the expression `&["a ", " b \\"]`. It has the span of `r"a {} b \"` - let span = pieces.span; - let snippet = snippet_opt(cx, span)?; - - let (inner, style) = match tokenize(&snippet).next()?.kind { - TokenKind::Literal { kind, .. } => { - let style = match kind { - LiteralKind::Str { .. } => None, - LiteralKind::RawStr { n_hashes: Some(n), .. } => Some(n.into()), - _ => return None, - }; - - let start = style.map_or(1, |n| 2 + n); - let end = snippet.len() - style.map_or(1, |n| 1 + n); - - (&snippet[start..end], style) - }, - _ => return None, - }; - - let mode = if style.is_some() { - unescape::Mode::RawStr - } else { - unescape::Mode::Str - }; - - let mut unescaped = String::with_capacity(inner.len()); - // Sometimes the original string comes from a macro which accepts a malformed string, such as in a - // #[display(""somestring)] attribute (accepted by the `displaythis` crate). Reconstructing the - // string from the span will not be possible, so we will just return None here. - let mut unparsable = false; - unescape_literal(inner, mode, &mut |_, ch| match ch { - Ok(ch) => unescaped.push(ch), - Err(e) if !e.is_fatal() => (), - Err(_) => unparsable = true, - }); - if unparsable { - return None; - } - - let mut parts = Vec::new(); - let _: Option = for_each_expr(pieces, |expr| { - if let ExprKind::Lit(lit) = &expr.kind - && let LitKind::Str(symbol, _) = lit.node - { - parts.push(symbol); - } - ControlFlow::Continue(()) - }); - - Some(Self { - span, - snippet, - style, - unescaped, - parts, - }) - } -} - -struct FormatArgsValues<'tcx> { - /// Values passed after the format string and implicit captures. `[1, z + 2, x]` for - /// `format!("{x} {} {}", 1, z + 2)`. - value_args: Vec<&'tcx Expr<'tcx>>, - /// Maps an `rt::v1::Argument::position` or an `rt::v1::Count::Param` to its index in - /// `value_args` - pos_to_value_index: Vec, - /// Used to check if a value is declared inline & to resolve `InnerSpan`s. - format_string_span: SpanData, -} - -impl<'tcx> FormatArgsValues<'tcx> { - fn new_empty(format_string_span: SpanData) -> Self { - Self { - value_args: Vec::new(), - pos_to_value_index: Vec::new(), - format_string_span, - } - } - - fn new(args: &'tcx Expr<'tcx>, format_string_span: SpanData) -> Self { - let mut pos_to_value_index = Vec::new(); - let mut value_args = Vec::new(); - let _: Option = for_each_expr(args, |expr| { - if expr.span.ctxt() == args.span.ctxt() { - // ArgumentV1::new_() - // ArgumentV1::from_usize() - if let ExprKind::Call(callee, [val]) = expr.kind - && let ExprKind::Path(QPath::TypeRelative(ty, _)) = callee.kind - && let TyKind::Path(QPath::LangItem(LangItem::FormatArgument, _, _)) = ty.kind - { - let val_idx = if val.span.ctxt() == expr.span.ctxt() - && let ExprKind::Field(_, field) = val.kind - && let Ok(idx) = field.name.as_str().parse() - { - // tuple index - idx - } else { - // assume the value expression is passed directly - pos_to_value_index.len() - }; - - pos_to_value_index.push(val_idx); - } - ControlFlow::Continue(Descend::Yes) - } else { - // assume that any expr with a differing span is a value - value_args.push(expr); - ControlFlow::Continue(Descend::No) - } - }); - - Self { - value_args, - pos_to_value_index, - format_string_span, - } - } -} - -/// The positions of a format argument's value, precision and width -/// -/// A position is an index into the second argument of `Arguments::new_v1[_formatted]` -#[derive(Debug, Default, Copy, Clone)] -struct ParamPosition { - /// The position stored in `rt::v1::Argument::position`. - value: usize, - /// The position stored in `rt::v1::FormatSpec::width` if it is a `Count::Param`. - width: Option, - /// The position stored in `rt::v1::FormatSpec::precision` if it is a `Count::Param`. - precision: Option, -} - -impl<'tcx> Visitor<'tcx> for ParamPosition { - fn visit_expr_field(&mut self, field: &'tcx ExprField<'tcx>) { - match field.ident.name { - sym::position => { - if let ExprKind::Lit(lit) = &field.expr.kind - && let LitKind::Int(pos, _) = lit.node - { - self.value = pos as usize; - } - }, - sym::precision => { - self.precision = parse_count(field.expr); - }, - sym::width => { - self.width = parse_count(field.expr); - }, - _ => walk_expr(self, field.expr), - } - } -} - -fn parse_count(expr: &Expr<'_>) -> Option { - // <::core::fmt::rt::v1::Count>::Param(1usize), - if let ExprKind::Call(ctor, [val]) = expr.kind - && let ExprKind::Path(QPath::TypeRelative(_, path)) = ctor.kind - && path.ident.name == sym::Param - && let ExprKind::Lit(lit) = &val.kind - && let LitKind::Int(pos, _) = lit.node - { - Some(pos as usize) - } else { - None - } -} - -/// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)` -fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option + 'tcx> { - if let ExprKind::AddrOf(.., array) = fmt_arg.kind - && let ExprKind::Array(specs) = array.kind - { - Some(specs.iter().map(|spec| { - if let ExprKind::Call(f, args) = spec.kind - && let ExprKind::Path(QPath::TypeRelative(ty, f)) = f.kind - && let TyKind::Path(QPath::LangItem(LangItem::FormatPlaceholder, _, _)) = ty.kind - && f.ident.name == sym::new - && let [position, _fill, _align, _flags, precision, width] = args - && let ExprKind::Lit(position) = &position.kind - && let LitKind::Int(position, _) = position.node { - ParamPosition { - value: position as usize, - width: parse_count(width), - precision: parse_count(precision), - } - } else { - ParamPosition::default() - } - })) - } else { - None - } -} - -/// `Span::from_inner`, but for `rustc_parse_format`'s `InnerSpan` -fn span_from_inner(base: SpanData, inner: rpf::InnerSpan) -> Span { - Span::new( - base.lo + BytePos::from_usize(inner.start), - base.lo + BytePos::from_usize(inner.end), - base.ctxt, - base.parent, - ) -} - -/// How a format parameter is used in the format string -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum FormatParamKind { - /// An implicit parameter , such as `{}` or `{:?}`. - Implicit, - /// A parameter with an explicit number, e.g. `{1}`, `{0:?}`, or `{:.0$}` - Numbered, - /// A parameter with an asterisk precision. e.g. `{:.*}`. - Starred, - /// A named parameter with a named `value_arg`, such as the `x` in `format!("{x}", x = 1)`. - Named(Symbol), - /// An implicit named parameter, such as the `y` in `format!("{y}")`. - NamedInline(Symbol), -} - /// Where a format parameter is being used in the format string #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum FormatParamUsage { @@ -729,451 +491,6 @@ pub enum FormatParamUsage { Precision, } -/// A `FormatParam` is any place in a `FormatArgument` that refers to a supplied value, e.g. -/// -/// ``` -/// let precision = 2; -/// format!("{:.precision$}", 0.1234); -/// ``` -/// -/// has two `FormatParam`s, a [`FormatParamKind::Implicit`] `.kind` with a `.value` of `0.1234` -/// and a [`FormatParamKind::NamedInline("precision")`] `.kind` with a `.value` of `2` -#[derive(Debug, Copy, Clone)] -pub struct FormatParam<'tcx> { - /// The expression this parameter refers to. - pub value: &'tcx Expr<'tcx>, - /// How this parameter refers to its `value`. - pub kind: FormatParamKind, - /// Where this format param is being used - argument/width/precision - pub usage: FormatParamUsage, - /// Span of the parameter, may be zero width. Includes the whitespace of implicit parameters. - /// - /// ```text - /// format!("{}, { }, {0}, {name}", ...); - /// ^ ~~ ~ ~~~~ - /// ``` - pub span: Span, -} - -impl<'tcx> FormatParam<'tcx> { - fn new( - mut kind: FormatParamKind, - usage: FormatParamUsage, - position: usize, - inner: rpf::InnerSpan, - values: &FormatArgsValues<'tcx>, - ) -> Option { - let value_index = *values.pos_to_value_index.get(position)?; - let value = *values.value_args.get(value_index)?; - let span = span_from_inner(values.format_string_span, inner); - - // if a param is declared inline, e.g. `format!("{x}")`, the generated expr's span points - // into the format string - if let FormatParamKind::Named(name) = kind && values.format_string_span.contains(value.span.data()) { - kind = FormatParamKind::NamedInline(name); - } - - Some(Self { - value, - kind, - usage, - span, - }) - } -} - -/// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and -/// [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers. -#[derive(Debug, Copy, Clone)] -pub enum Count<'tcx> { - /// Specified with a literal number, stores the value. - Is(usize, Span), - /// Specified using `$` and `*` syntaxes. The `*` format is still considered to be - /// `FormatParamKind::Numbered`. - Param(FormatParam<'tcx>), - /// Not specified. - Implied(Option), -} - -impl<'tcx> Count<'tcx> { - fn new( - usage: FormatParamUsage, - count: rpf::Count<'_>, - position: Option, - inner: Option, - values: &FormatArgsValues<'tcx>, - ) -> Option { - let span = inner.map(|inner| span_from_inner(values.format_string_span, inner)); - - Some(match count { - rpf::Count::CountIs(val) => Self::Is(val, span?), - rpf::Count::CountIsName(name, _) => Self::Param(FormatParam::new( - FormatParamKind::Named(Symbol::intern(name)), - usage, - position?, - inner?, - values, - )?), - rpf::Count::CountIsParam(_) => Self::Param(FormatParam::new( - FormatParamKind::Numbered, - usage, - position?, - inner?, - values, - )?), - rpf::Count::CountIsStar(_) => Self::Param(FormatParam::new( - FormatParamKind::Starred, - usage, - position?, - inner?, - values, - )?), - rpf::Count::CountImplied => Self::Implied(span), - }) - } - - pub fn is_implied(self) -> bool { - matches!(self, Count::Implied(_)) - } - - pub fn param(self) -> Option> { - match self { - Count::Param(param) => Some(param), - _ => None, - } - } - - pub fn span(self) -> Option { - match self { - Count::Is(_, span) => Some(span), - Count::Param(param) => Some(param.span), - Count::Implied(span) => span, - } - } -} - -/// Specification for the formatting of an argument in the format string. See -/// for the precise meanings. -#[derive(Debug)] -pub struct FormatSpec<'tcx> { - /// Optionally specified character to fill alignment with. - pub fill: Option, - /// Optionally specified alignment. - pub align: Alignment, - /// Whether all flag options are set to default (no flags specified). - pub no_flags: bool, - /// Represents either the maximum width or the integer precision. - pub precision: Count<'tcx>, - /// The minimum width, will be padded according to `width`/`align` - pub width: Count<'tcx>, - /// The formatting trait used by the argument, e.g. `sym::Display` for `{}`, `sym::Debug` for - /// `{:?}`. - pub r#trait: Symbol, - pub trait_span: Option, -} - -impl<'tcx> FormatSpec<'tcx> { - fn new(spec: rpf::FormatSpec<'_>, positions: ParamPosition, values: &FormatArgsValues<'tcx>) -> Option { - Some(Self { - fill: spec.fill, - align: spec.align, - no_flags: spec.sign.is_none() && !spec.alternate && !spec.zero_pad && spec.debug_hex.is_none(), - precision: Count::new( - FormatParamUsage::Precision, - spec.precision, - positions.precision, - spec.precision_span, - values, - )?, - width: Count::new( - FormatParamUsage::Width, - spec.width, - positions.width, - spec.width_span, - values, - )?, - r#trait: match spec.ty { - "" => sym::Display, - "?" => sym::Debug, - "o" => sym!(Octal), - "x" => sym!(LowerHex), - "X" => sym!(UpperHex), - "p" => sym::Pointer, - "b" => sym!(Binary), - "e" => sym!(LowerExp), - "E" => sym!(UpperExp), - _ => return None, - }, - trait_span: spec - .ty_span - .map(|span| span_from_inner(values.format_string_span, span)), - }) - } - - /// Returns true if this format spec is unchanged from the default. e.g. returns true for `{}`, - /// `{foo}` and `{2}`, but false for `{:?}`, `{foo:5}` and `{3:.5}` - pub fn is_default(&self) -> bool { - self.r#trait == sym::Display && self.is_default_for_trait() - } - - /// Has no other formatting specifiers than setting the format trait. returns true for `{}`, - /// `{foo}`, `{:?}`, but false for `{foo:5}`, `{3:.5?}` - pub fn is_default_for_trait(&self) -> bool { - self.width.is_implied() && self.precision.is_implied() && self.align == Alignment::AlignUnknown && self.no_flags - } -} - -/// A format argument, such as `{}`, `{foo:?}`. -#[derive(Debug)] -pub struct FormatArg<'tcx> { - /// The parameter the argument refers to. - pub param: FormatParam<'tcx>, - /// How to format `param`. - pub format: FormatSpec<'tcx>, - /// span of the whole argument, `{..}`. - pub span: Span, -} - -/// A parsed `format_args!` expansion. -#[derive(Debug)] -pub struct FormatArgsExpn<'tcx> { - /// The format string literal. - pub format_string: FormatString, - /// The format arguments, such as `{:?}`. - pub args: Vec>, - /// Has an added newline due to `println!()`/`writeln!()`/etc. The last format string part will - /// include this added newline. - pub newline: bool, - /// Spans of the commas between the format string and explicit values, excluding any trailing - /// comma - /// - /// ```ignore - /// format!("..", 1, 2, 3,) - /// // ^ ^ ^ - /// ``` - comma_spans: Vec, - /// Explicit values passed after the format string, ignoring implicit captures. `[1, z + 2]` for - /// `format!("{x} {} {y}", 1, z + 2)`. - explicit_values: Vec<&'tcx Expr<'tcx>>, -} - -impl<'tcx> FormatArgsExpn<'tcx> { - /// Gets the spans of the commas inbetween the format string and explicit args, not including - /// any trailing comma - /// - /// ```ignore - /// format!("{} {}", a, b) - /// // ^ ^ - /// ``` - /// - /// Ensures that the format string and values aren't coming from a proc macro that sets the - /// output span to that of its input - fn comma_spans(cx: &LateContext<'_>, explicit_values: &[&Expr<'_>], fmt_span: Span) -> Option> { - // `format!("{} {} {c}", "one", "two", c = "three")` - // ^^^^^ ^^^^^ ^^^^^^^ - let value_spans = explicit_values - .iter() - .map(|val| hygiene::walk_chain(val.span, fmt_span.ctxt())); - - // `format!("{} {} {c}", "one", "two", c = "three")` - // ^^ ^^ ^^^^^^ - let between_spans = once(fmt_span) - .chain(value_spans) - .tuple_windows() - .map(|(start, end)| start.between(end)); - - let mut comma_spans = Vec::new(); - for between_span in between_spans { - let mut offset = 0; - let mut seen_comma = false; - - for token in tokenize(&snippet_opt(cx, between_span)?) { - match token.kind { - TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace => {}, - TokenKind::Comma if !seen_comma => { - seen_comma = true; - - let base = between_span.data(); - comma_spans.push(Span::new( - base.lo + BytePos(offset), - base.lo + BytePos(offset + 1), - base.ctxt, - base.parent, - )); - }, - // named arguments, `start_val, name = end_val` - // ^^^^^^^^^ between_span - TokenKind::Ident | TokenKind::Eq if seen_comma => {}, - // An unexpected token usually indicates the format string or a value came from a proc macro output - // that sets the span of its output to an input, e.g. `println!(some_proc_macro!("input"), ..)` that - // emits a string literal with the span set to that of `"input"` - _ => return None, - } - offset += token.len; - } - - if !seen_comma { - return None; - } - } - - Some(comma_spans) - } - - pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option { - let macro_name = macro_backtrace(expr.span) - .map(|macro_call| cx.tcx.item_name(macro_call.def_id)) - .find(|&name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))?; - let newline = macro_name == sym::format_args_nl; - - // ::core::fmt::Arguments::new_const(pieces) - // ::core::fmt::Arguments::new_v1(pieces, args) - // ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg) - if let ExprKind::Call(callee, [pieces, rest @ ..]) = expr.kind - && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind - && let TyKind::Path(QPath::LangItem(LangItem::FormatArguments, _, _)) = ty.kind - && matches!(seg.ident.as_str(), "new_const" | "new_v1" | "new_v1_formatted") - { - let format_string = FormatString::new(cx, pieces)?; - - let mut parser = rpf::Parser::new( - &format_string.unescaped, - format_string.style, - Some(format_string.snippet.clone()), - // `format_string.unescaped` does not contain the appended newline - false, - rpf::ParseMode::Format, - ); - - let parsed_args = parser - .by_ref() - .filter_map(|piece| match piece { - rpf::Piece::NextArgument(a) => Some(a), - rpf::Piece::String(_) => None, - }) - .collect_vec(); - if !parser.errors.is_empty() { - return None; - } - - let positions = if let Some(fmt_arg) = rest.get(1) { - // If the argument contains format specs, `new_v1_formatted(_, _, fmt, _)`, parse - // them. - - Either::Left(parse_rt_fmt(fmt_arg)?) - } else { - // If no format specs are given, the positions are in the given order and there are - // no `precision`/`width`s to consider. - - Either::Right((0..).map(|n| ParamPosition { - value: n, - width: None, - precision: None, - })) - }; - - let values = if let Some(args) = rest.first() { - FormatArgsValues::new(args, format_string.span.data()) - } else { - FormatArgsValues::new_empty(format_string.span.data()) - }; - - let args = izip!(positions, parsed_args, parser.arg_places) - .map(|(position, parsed_arg, arg_span)| { - Some(FormatArg { - param: FormatParam::new( - match parsed_arg.position { - rpf::Position::ArgumentImplicitlyIs(_) => FormatParamKind::Implicit, - rpf::Position::ArgumentIs(_) => FormatParamKind::Numbered, - // NamedInline is handled by `FormatParam::new()` - rpf::Position::ArgumentNamed(name) => FormatParamKind::Named(Symbol::intern(name)), - }, - FormatParamUsage::Argument, - position.value, - parsed_arg.position_span, - &values, - )?, - format: FormatSpec::new(parsed_arg.format, position, &values)?, - span: span_from_inner(values.format_string_span, arg_span), - }) - }) - .collect::>>()?; - - let mut explicit_values = values.value_args; - // remove values generated for implicitly captured vars - let len = explicit_values - .iter() - .take_while(|val| !format_string.span.contains(val.span)) - .count(); - explicit_values.truncate(len); - - let comma_spans = Self::comma_spans(cx, &explicit_values, format_string.span)?; - - Some(Self { - format_string, - args, - newline, - comma_spans, - explicit_values, - }) - } else { - None - } - } - - pub fn find_nested(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expn_id: ExpnId) -> Option { - for_each_expr(expr, |e| { - let e_ctxt = e.span.ctxt(); - if e_ctxt == expr.span.ctxt() { - ControlFlow::Continue(Descend::Yes) - } else if e_ctxt.outer_expn().is_descendant_of(expn_id) { - if let Some(args) = FormatArgsExpn::parse(cx, e) { - ControlFlow::Break(args) - } else { - ControlFlow::Continue(Descend::No) - } - } else { - ControlFlow::Continue(Descend::No) - } - }) - } - - /// Source callsite span of all inputs - pub fn inputs_span(&self) -> Span { - match *self.explicit_values { - [] => self.format_string.span, - [.., last] => self - .format_string - .span - .to(hygiene::walk_chain(last.span, self.format_string.span.ctxt())), - } - } - - /// Get the span of a value expanded to the previous comma, e.g. for the value `10` - /// - /// ```ignore - /// format("{}.{}", 10, 11) - /// // ^^^^ - /// ``` - pub fn value_with_prev_comma_span(&self, value_id: HirId) -> Option { - for (comma_span, value) in zip(&self.comma_spans, &self.explicit_values) { - if value.hir_id == value_id { - return Some(comma_span.to(hygiene::walk_chain(value.span, comma_span.ctxt()))); - } - } - - None - } - - /// Iterator of all format params, both values and those referenced by `width`/`precision`s. - pub fn params(&'tcx self) -> impl Iterator> { - self.args - .iter() - .flat_map(|arg| [Some(arg.param), arg.format.precision.param(), arg.format.width.param()]) - .flatten() - } -} - /// A node with a `HirId` and a `Span` pub trait HirNode { fn hir_id(&self) -> HirId; From 783879e6fe48b5bd776bf2b1c9314fda3e30447d Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Tue, 28 Mar 2023 20:52:55 -0400 Subject: [PATCH 044/272] Partial no-op refactoring of #9948 This contains preparatory work for #9948 to keep that change to the minimum, and make it easier to review it. --- clippy_dev/src/new_lint.rs | 8 +-- clippy_dev/src/update_lints.rs | 14 ++--- tests/ui/format_args_unfixable.rs | 44 ++++++++++++++ tests/ui/format_args_unfixable.stderr | 36 +++++------ tests/ui/uninlined_format_args.fixed | 86 ++++++++++++++++++++++++++- tests/ui/uninlined_format_args.rs | 86 ++++++++++++++++++++++++++- 6 files changed, 239 insertions(+), 35 deletions(-) diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 420214d9256d..13a277034278 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -369,9 +369,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R }} todo!(); }} - "#, - context_import = context_import, - name_upper = name_upper, + "# ); } else { let _: fmt::Result = writedoc!( @@ -385,9 +383,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R pub(super) fn check(cx: &{context_import}) {{ todo!(); }} - "#, - context_import = context_import, - name_upper = name_upper, + "# ); } diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 779e4d0e1e30..95222a9acdfc 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -537,17 +537,13 @@ fn declare_deprecated(name: &str, path: &Path, reason: &str) -> io::Result<()> { /// Nothing. This lint has been deprecated. /// /// ### Deprecation reason - /// {} - #[clippy::version = \"{}\"] - pub {}, - \"{}\" + /// {deprecation_reason} + #[clippy::version = \"{version}\"] + pub {name}, + \"{reason}\" }} - ", - deprecation_reason, - version, - name, - reason, + " ) } diff --git a/tests/ui/format_args_unfixable.rs b/tests/ui/format_args_unfixable.rs index eb0ac15bfbf1..423bfaf97965 100644 --- a/tests/ui/format_args_unfixable.rs +++ b/tests/ui/format_args_unfixable.rs @@ -1,4 +1,5 @@ #![warn(clippy::format_in_format_args, clippy::to_string_in_format_args)] +#![allow(unused)] #![allow(clippy::assertions_on_constants, clippy::eq_op, clippy::uninlined_format_args)] use std::io::{stdout, Error, ErrorKind, Write}; @@ -57,3 +58,46 @@ fn main() { my_macro!(); println!("error: {}", my_other_macro!()); } + +macro_rules! _internal { + ($($args:tt)*) => { + println!("{}", format_args!($($args)*)) + }; +} + +macro_rules! my_println2 { + ($target:expr, $($args:tt)+) => {{ + if $target { + _internal!($($args)+) + } + }}; +} + +macro_rules! my_println2_args { + ($target:expr, $($args:tt)+) => {{ + if $target { + _internal!("foo: {}", format_args!($($args)+)) + } + }}; +} + +fn test2() { + let error = Error::new(ErrorKind::Other, "bad thing"); + + // None of these should be linted without the config change + my_println2!(true, "error: {}", format!("something failed at {}", Location::caller())); + my_println2!( + true, + "{}: {}", + error, + format!("something failed at {}", Location::caller()) + ); + + my_println2_args!(true, "error: {}", format!("something failed at {}", Location::caller())); + my_println2_args!( + true, + "{}: {}", + error, + format!("something failed at {}", Location::caller()) + ); +} diff --git a/tests/ui/format_args_unfixable.stderr b/tests/ui/format_args_unfixable.stderr index b291d475ad90..c1be48c3b726 100644 --- a/tests/ui/format_args_unfixable.stderr +++ b/tests/ui/format_args_unfixable.stderr @@ -1,5 +1,5 @@ error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:25:5 + --> $DIR/format_args_unfixable.rs:26:5 | LL | println!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | println!("error: {}", format!("something failed at {}", Location::calle = note: `-D clippy::format-in-format-args` implied by `-D warnings` error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:26:5 + --> $DIR/format_args_unfixable.rs:27:5 | LL | println!("{}: {}", error, format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | println!("{}: {}", error, format!("something failed at {}", Location::c = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:27:5 + --> $DIR/format_args_unfixable.rs:28:5 | LL | println!("{:?}: {}", error, format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | println!("{:?}: {}", error, format!("something failed at {}", Location: = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:28:5 + --> $DIR/format_args_unfixable.rs:29:5 | LL | println!("{{}}: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | println!("{{}}: {}", format!("something failed at {}", Location::caller = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:29:5 + --> $DIR/format_args_unfixable.rs:30:5 | LL | println!(r#"error: "{}""#, format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | println!(r#"error: "{}""#, format!("something failed at {}", Location:: = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:30:5 + --> $DIR/format_args_unfixable.rs:31:5 | LL | println!("error: {}", format!(r#"something failed at "{}""#, Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | println!("error: {}", format!(r#"something failed at "{}""#, Location:: = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:31:5 + --> $DIR/format_args_unfixable.rs:32:5 | LL | println!("error: {}", format!("something failed at {} {0}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | println!("error: {}", format!("something failed at {} {0}", Location::c = help: or consider changing `format!` to `format_args!` error: `format!` in `format!` args - --> $DIR/format_args_unfixable.rs:32:13 + --> $DIR/format_args_unfixable.rs:33:13 | LL | let _ = format!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | let _ = format!("error: {}", format!("something failed at {}", Location = help: or consider changing `format!` to `format_args!` error: `format!` in `write!` args - --> $DIR/format_args_unfixable.rs:33:13 + --> $DIR/format_args_unfixable.rs:34:13 | LL | let _ = write!( | _____________^ @@ -86,7 +86,7 @@ LL | | ); = help: or consider changing `format!` to `format_args!` error: `format!` in `writeln!` args - --> $DIR/format_args_unfixable.rs:38:13 + --> $DIR/format_args_unfixable.rs:39:13 | LL | let _ = writeln!( | _____________^ @@ -100,7 +100,7 @@ LL | | ); = help: or consider changing `format!` to `format_args!` error: `format!` in `print!` args - --> $DIR/format_args_unfixable.rs:43:5 + --> $DIR/format_args_unfixable.rs:44:5 | LL | print!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL | print!("error: {}", format!("something failed at {}", Location::caller( = help: or consider changing `format!` to `format_args!` error: `format!` in `eprint!` args - --> $DIR/format_args_unfixable.rs:44:5 + --> $DIR/format_args_unfixable.rs:45:5 | LL | eprint!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,7 +118,7 @@ LL | eprint!("error: {}", format!("something failed at {}", Location::caller = help: or consider changing `format!` to `format_args!` error: `format!` in `eprintln!` args - --> $DIR/format_args_unfixable.rs:45:5 + --> $DIR/format_args_unfixable.rs:46:5 | LL | eprintln!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,7 +127,7 @@ LL | eprintln!("error: {}", format!("something failed at {}", Location::call = help: or consider changing `format!` to `format_args!` error: `format!` in `format_args!` args - --> $DIR/format_args_unfixable.rs:46:13 + --> $DIR/format_args_unfixable.rs:47:13 | LL | let _ = format_args!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL | let _ = format_args!("error: {}", format!("something failed at {}", Loc = help: or consider changing `format!` to `format_args!` error: `format!` in `assert!` args - --> $DIR/format_args_unfixable.rs:47:5 + --> $DIR/format_args_unfixable.rs:48:5 | LL | assert!(true, "error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL | assert!(true, "error: {}", format!("something failed at {}", Location:: = help: or consider changing `format!` to `format_args!` error: `format!` in `assert_eq!` args - --> $DIR/format_args_unfixable.rs:48:5 + --> $DIR/format_args_unfixable.rs:49:5 | LL | assert_eq!(0, 0, "error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -154,7 +154,7 @@ LL | assert_eq!(0, 0, "error: {}", format!("something failed at {}", Locatio = help: or consider changing `format!` to `format_args!` error: `format!` in `assert_ne!` args - --> $DIR/format_args_unfixable.rs:49:5 + --> $DIR/format_args_unfixable.rs:50:5 | LL | assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -163,7 +163,7 @@ LL | assert_ne!(0, 0, "error: {}", format!("something failed at {}", Locatio = help: or consider changing `format!` to `format_args!` error: `format!` in `panic!` args - --> $DIR/format_args_unfixable.rs:50:5 + --> $DIR/format_args_unfixable.rs:51:5 | LL | panic!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/uninlined_format_args.fixed b/tests/ui/uninlined_format_args.fixed index 5ecb9a5bf9eb..3122081a44f9 100644 --- a/tests/ui/uninlined_format_args.fixed +++ b/tests/ui/uninlined_format_args.fixed @@ -1,7 +1,7 @@ // aux-build:proc_macros.rs // run-rustfix #![warn(clippy::uninlined_format_args)] -#![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)] +#![allow(named_arguments_used_positionally, unused)] #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] extern crate proc_macros; @@ -178,3 +178,87 @@ fn _meets_msrv() { fn _do_not_fire() { println!("{:?}", None::<()>); } + +macro_rules! _internal { + ($($args:tt)*) => { + println!("{}", format_args!($($args)*)) + }; +} + +macro_rules! my_println2 { + ($target:expr, $($args:tt)+) => {{ + if $target { + _internal!($($args)+) + } + }}; +} + +macro_rules! my_println2_args { + ($target:expr, $($args:tt)+) => {{ + if $target { + _internal!("foo: {}", format_args!($($args)+)) + } + }}; +} + +macro_rules! my_concat { + ($fmt:literal $(, $e:expr)*) => { + println!(concat!("ERROR: ", $fmt), $($e,)*) + } +} + +macro_rules! my_good_macro { + ($fmt:literal $(, $e:expr)* $(,)?) => { + println!($fmt $(, $e)*) + } +} + +macro_rules! my_bad_macro { + ($fmt:literal, $($e:expr),*) => { + println!($fmt, $($e,)*) + } +} + +macro_rules! my_bad_macro2 { + ($fmt:literal) => { + let s = $fmt.clone(); + println!("{}", s); + }; + ($fmt:literal, $($e:expr)+) => { + println!($fmt, $($e,)*) + }; +} + +// This abomination was suggested by @Alexendoo, may the Rust gods have mercy on their soul... +// https://github.com/rust-lang/rust-clippy/pull/9948#issuecomment-1327965962 +macro_rules! used_twice { + ( + large = $large:literal, + small = $small:literal, + $val:expr, + ) => { + if $val < 5 { + println!($small, $val); + } else { + println!($large, $val); + } + }; +} + +fn tester2() { + let local_i32 = 1; + my_println2_args!(true, "{}", local_i32); + my_println2!(true, "{}", local_i32); + my_concat!("{}", local_i32); + my_good_macro!("{}", local_i32); + my_good_macro!("{}", local_i32,); + + // FIXME: Broken false positives, currently unhandled + my_bad_macro!("{}", local_i32); + my_bad_macro2!("{}", local_i32); + used_twice! { + large = "large value: {}", + small = "small value: {}", + local_i32, + }; +} diff --git a/tests/ui/uninlined_format_args.rs b/tests/ui/uninlined_format_args.rs index 835afac393fa..b153ef256e0c 100644 --- a/tests/ui/uninlined_format_args.rs +++ b/tests/ui/uninlined_format_args.rs @@ -1,7 +1,7 @@ // aux-build:proc_macros.rs // run-rustfix #![warn(clippy::uninlined_format_args)] -#![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)] +#![allow(named_arguments_used_positionally, unused)] #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] extern crate proc_macros; @@ -183,3 +183,87 @@ fn _meets_msrv() { fn _do_not_fire() { println!("{:?}", None::<()>); } + +macro_rules! _internal { + ($($args:tt)*) => { + println!("{}", format_args!($($args)*)) + }; +} + +macro_rules! my_println2 { + ($target:expr, $($args:tt)+) => {{ + if $target { + _internal!($($args)+) + } + }}; +} + +macro_rules! my_println2_args { + ($target:expr, $($args:tt)+) => {{ + if $target { + _internal!("foo: {}", format_args!($($args)+)) + } + }}; +} + +macro_rules! my_concat { + ($fmt:literal $(, $e:expr)*) => { + println!(concat!("ERROR: ", $fmt), $($e,)*) + } +} + +macro_rules! my_good_macro { + ($fmt:literal $(, $e:expr)* $(,)?) => { + println!($fmt $(, $e)*) + } +} + +macro_rules! my_bad_macro { + ($fmt:literal, $($e:expr),*) => { + println!($fmt, $($e,)*) + } +} + +macro_rules! my_bad_macro2 { + ($fmt:literal) => { + let s = $fmt.clone(); + println!("{}", s); + }; + ($fmt:literal, $($e:expr)+) => { + println!($fmt, $($e,)*) + }; +} + +// This abomination was suggested by @Alexendoo, may the Rust gods have mercy on their soul... +// https://github.com/rust-lang/rust-clippy/pull/9948#issuecomment-1327965962 +macro_rules! used_twice { + ( + large = $large:literal, + small = $small:literal, + $val:expr, + ) => { + if $val < 5 { + println!($small, $val); + } else { + println!($large, $val); + } + }; +} + +fn tester2() { + let local_i32 = 1; + my_println2_args!(true, "{}", local_i32); + my_println2!(true, "{}", local_i32); + my_concat!("{}", local_i32); + my_good_macro!("{}", local_i32); + my_good_macro!("{}", local_i32,); + + // FIXME: Broken false positives, currently unhandled + my_bad_macro!("{}", local_i32); + my_bad_macro2!("{}", local_i32); + used_twice! { + large = "large value: {}", + small = "small value: {}", + local_i32, + }; +} From 4f5a019d6e836ff4b56154bf6c646cc358310fa9 Mon Sep 17 00:00:00 2001 From: csmoe Date: Wed, 29 Mar 2023 15:12:20 +0800 Subject: [PATCH 045/272] Update clippy_lints/src/large_futures.rs Co-authored-by: Fridtjof Stoldt --- clippy_lints/src/large_futures.rs | 45 +++++++-------- .../ui-toml/large_futures/large_futures.fixed | 29 ---------- tests/ui-toml/large_futures/large_futures.rs | 2 - .../large_futures/large_futures.stderr | 2 +- tests/ui/large_futures.fixed | 41 -------------- tests/ui/large_futures.rs | 24 +++++++- tests/ui/large_futures.stderr | 56 ++++++++++++++++--- 7 files changed, 93 insertions(+), 106 deletions(-) delete mode 100644 tests/ui-toml/large_futures/large_futures.fixed delete mode 100644 tests/ui/large_futures.fixed diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index 494bb2a97d26..1b0544813718 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -59,31 +59,28 @@ 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 { - if matches!( - func.kind, - ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) - ) { - let ty = cx.typeck_results().expr_ty(expr); - if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() - && implements_trait(cx, ty, future_trait_def_id, &[]) { - if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) { - let size = layout.layout.size(); - if 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::MachineApplicable, - ); - } - } - } - } + 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, + ); } } } diff --git a/tests/ui-toml/large_futures/large_futures.fixed b/tests/ui-toml/large_futures/large_futures.fixed deleted file mode 100644 index 1238c512b0fa..000000000000 --- a/tests/ui-toml/large_futures/large_futures.fixed +++ /dev/null @@ -1,29 +0,0 @@ -// run-rustfix - -#![warn(clippy::large_futures)] - -fn main() {} - -pub async fn should_warn() { - let x = [0u8; 1024]; - async {}.await; - dbg!(x); -} - -pub async fn should_not_warn() { - let x = [0u8; 1020]; - async {}.await; - dbg!(x); -} - -pub async fn bar() { - Box::pin(should_warn()).await; - - async { - let x = [0u8; 1024]; - dbg!(x); - } - .await; - - should_not_warn().await; -} diff --git a/tests/ui-toml/large_futures/large_futures.rs b/tests/ui-toml/large_futures/large_futures.rs index 80039d9047b3..4158df8b5ff5 100644 --- a/tests/ui-toml/large_futures/large_futures.rs +++ b/tests/ui-toml/large_futures/large_futures.rs @@ -1,5 +1,3 @@ -// run-rustfix - #![warn(clippy::large_futures)] fn main() {} diff --git a/tests/ui-toml/large_futures/large_futures.stderr b/tests/ui-toml/large_futures/large_futures.stderr index f7895f8eaf7a..b92734de2f08 100644 --- a/tests/ui-toml/large_futures/large_futures.stderr +++ b/tests/ui-toml/large_futures/large_futures.stderr @@ -1,5 +1,5 @@ error: large future with a size of 1026 bytes - --> $DIR/large_futures.rs:20:5 + --> $DIR/large_futures.rs:18:5 | LL | should_warn().await; | ^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(should_warn())` diff --git a/tests/ui/large_futures.fixed b/tests/ui/large_futures.fixed deleted file mode 100644 index 9d839998afd7..000000000000 --- a/tests/ui/large_futures.fixed +++ /dev/null @@ -1,41 +0,0 @@ -// run-rustfix - -#![feature(generators)] -#![warn(clippy::large_futures)] -#![allow(clippy::future_not_send)] -#![allow(clippy::manual_async_fn)] - -async fn big_fut(_arg: [u8; 1024 * 16]) {} - -async fn wait() { - let f = async { - Box::pin(big_fut([0u8; 1024 * 16])).await; - }; - Box::pin(f).await -} -async fn calls_fut(fut: impl std::future::Future) { - loop { - Box::pin(wait()).await; - if true { - return fut.await; - } else { - Box::pin(wait()).await; - } - } -} - -pub async fn test() { - let fut = big_fut([0u8; 1024 * 16]); - Box::pin(foo()).await; - Box::pin(calls_fut(fut)).await; -} - -pub fn foo() -> impl std::future::Future { - async { - let x = [0i32; 1024 * 16]; - async {}.await; - dbg!(x); - } -} - -fn main() {} diff --git a/tests/ui/large_futures.rs b/tests/ui/large_futures.rs index 8b7aaa61b888..4a8ba995da55 100644 --- a/tests/ui/large_futures.rs +++ b/tests/ui/large_futures.rs @@ -1,5 +1,3 @@ -// run-rustfix - #![feature(generators)] #![warn(clippy::large_futures)] #![allow(clippy::future_not_send)] @@ -38,4 +36,26 @@ pub fn foo() -> impl std::future::Future { } } +pub async fn lines() { + async { + let x = [0i32; 1024 * 16]; + async {}.await; + println!("{:?}", x); + } + .await; +} + +pub async fn macro_expn() { + macro_rules! macro_ { + () => { + async { + let x = [0i32; 1024 * 16]; + async {}.await; + println!("macro: {:?}", x); + } + }; + } + macro_!().await +} + fn main() {} diff --git a/tests/ui/large_futures.stderr b/tests/ui/large_futures.stderr index 557455299a9c..67e0fceff6ef 100644 --- a/tests/ui/large_futures.stderr +++ b/tests/ui/large_futures.stderr @@ -1,5 +1,5 @@ error: large future with a size of 16385 bytes - --> $DIR/large_futures.rs:12:9 + --> $DIR/large_futures.rs:10:9 | LL | big_fut([0u8; 1024 * 16]).await; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(big_fut([0u8; 1024 * 16]))` @@ -7,34 +7,76 @@ LL | big_fut([0u8; 1024 * 16]).await; = note: `-D clippy::large-futures` implied by `-D warnings` error: large future with a size of 16386 bytes - --> $DIR/large_futures.rs:14:5 + --> $DIR/large_futures.rs:12:5 | LL | f.await | ^ help: consider `Box::pin` on it: `Box::pin(f)` error: large future with a size of 16387 bytes - --> $DIR/large_futures.rs:18:9 + --> $DIR/large_futures.rs:16:9 | LL | wait().await; | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` error: large future with a size of 16387 bytes - --> $DIR/large_futures.rs:22:13 + --> $DIR/large_futures.rs:20:13 | LL | wait().await; | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` error: large future with a size of 65540 bytes - --> $DIR/large_futures.rs:29:5 + --> $DIR/large_futures.rs:27:5 | LL | foo().await; | ^^^^^ help: consider `Box::pin` on it: `Box::pin(foo())` error: large future with a size of 49159 bytes - --> $DIR/large_futures.rs:30:5 + --> $DIR/large_futures.rs:28:5 | LL | calls_fut(fut).await; | ^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(calls_fut(fut))` -error: aborting due to 6 previous errors +error: large future with a size of 65540 bytes + --> $DIR/large_futures.rs:40:5 + | +LL | / async { +LL | | let x = [0i32; 1024 * 16]; +LL | | async {}.await; +LL | | println!("{:?}", x); +LL | | } + | |_____^ + | +help: consider `Box::pin` on it + | +LL ~ Box::pin(async { +LL + let x = [0i32; 1024 * 16]; +LL + async {}.await; +LL + println!("{:?}", x); +LL + }) + | + +error: large future with a size of 65540 bytes + --> $DIR/large_futures.rs:51:13 + | +LL | / async { +LL | | let x = [0i32; 1024 * 16]; +LL | | async {}.await; +LL | | println!("macro: {:?}", x); +LL | | } + | |_____________^ +... +LL | macro_!().await + | --------- in this macro invocation + | + = note: this error originates in the macro `macro_` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider `Box::pin` on it + | +LL ~ Box::pin(async { +LL + let x = [0i32; 1024 * 16]; +LL + async {}.await; +LL + println!("macro: {:?}", x); +LL + }) + | + +error: aborting due to 8 previous errors From 51b4d2a1e825c39c444be1385f3618302ef0b452 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 26 Mar 2023 14:52:46 +0000 Subject: [PATCH 046/272] In uninit checking, add fallback for polymorphic types --- clippy_utils/src/ty.rs | 22 +++++++++++++++++++--- tests/ui/uninit.rs | 18 +++++++++++++++--- tests/ui/uninit.stderr | 10 +++++----- tests/ui/uninit_vec.rs | 8 ++++++++ 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 0b47234647fb..9449f0b55674 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -541,9 +541,25 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { pub fn is_uninit_value_valid_for_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { cx.tcx .check_validity_requirement((ValidityRequirement::Uninit, cx.param_env.and(ty))) - // For types containing generic parameters we cannot get a layout to check. - // Therefore, we are conservative and assume that they don't allow uninit. - .unwrap_or(false) + .unwrap_or_else(|_| is_uninit_value_valid_for_ty_fallback(cx, ty)) +} + +/// A fallback for polymorphic types, which are not supported by `check_validity_requirement`. +fn is_uninit_value_valid_for_ty_fallback<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + match *ty.kind() { + // The array length may be polymorphic, let's try the inner type. + ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component), + // Peek through tuples and try their fallbacks. + ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)), + // Unions are always fine right now. + // This includes MaybeUninit, the main way people use uninitialized memory. + // For ADTs, we could look at all fields just like for tuples, but that's potentially + // exponential, so let's avoid doing that for now. Code doing that is sketchy enough to + // just use an `#[allow()]`. + ty::Adt(adt, _) => adt.is_union(), + // For the rest, conservatively assume that they cannot be uninit. + _ => false, + } } /// Gets an iterator over all predicates which apply to the given item. diff --git a/tests/ui/uninit.rs b/tests/ui/uninit.rs index 412b36b4ee8f..c996de89422b 100644 --- a/tests/ui/uninit.rs +++ b/tests/ui/uninit.rs @@ -1,7 +1,7 @@ #![feature(stmt_expr_attributes)] #![allow(clippy::let_unit_value, invalid_value)] -use std::mem::{self, MaybeUninit}; +use std::mem::MaybeUninit; union MyOwnMaybeUninit { value: u8, @@ -30,12 +30,24 @@ fn main() { let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() }; // Was a false negative. - let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() }; + let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; polymorphic::<()>(); + polymorphic_maybe_uninit_array::<10>(); + polymorphic_maybe_uninit::(); fn polymorphic() { // We are conservative around polymorphic types. - let _: T = unsafe { mem::MaybeUninit::uninit().assume_init() }; + let _: T = unsafe { MaybeUninit::uninit().assume_init() }; + } + + fn polymorphic_maybe_uninit_array() { + // While the type is polymorphic, MaybeUninit is not. + let _: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; + } + + fn polymorphic_maybe_uninit() { + // The entire type is polymorphic, but it's wrapped in a MaybeUninit. + let _: MaybeUninit = unsafe { MaybeUninit::uninit().assume_init() }; } } diff --git a/tests/ui/uninit.stderr b/tests/ui/uninit.stderr index 9e01b9a4aa81..248de56da76c 100644 --- a/tests/ui/uninit.stderr +++ b/tests/ui/uninit.stderr @@ -9,14 +9,14 @@ LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; error: this call for this type may be undefined behavior --> $DIR/uninit.rs:33:29 | -LL | let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call for this type may be undefined behavior - --> $DIR/uninit.rs:39:29 + --> $DIR/uninit.rs:41:29 | -LL | let _: T = unsafe { mem::MaybeUninit::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _: T = unsafe { MaybeUninit::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/uninit_vec.rs b/tests/ui/uninit_vec.rs index 59ec64a7ab1b..79effc82fdf7 100644 --- a/tests/ui/uninit_vec.rs +++ b/tests/ui/uninit_vec.rs @@ -124,4 +124,12 @@ fn main() { vec.set_len(10); } } + + fn poly_maybe_uninit() { + // We are conservative around polymorphic types. + let mut vec: Vec> = Vec::with_capacity(1000); + unsafe { + vec.set_len(10); + } + } } From 4cf5bdc60c7ccec3b5f395ee393615c224e28555 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 12 Dec 2022 00:42:45 -0500 Subject: [PATCH 047/272] Stabilize a portion of 'once_cell' Move items not part of this stabilization to 'lazy_cell' or 'once_cell_try' --- clippy_dev/src/lib.rs | 1 - clippy_lints/src/lib.rs | 1 - clippy_utils/src/lib.rs | 1 - src/driver.rs | 2 +- tests/compile-test.rs | 2 +- tests/dogfood.rs | 2 +- tests/lint_message_convention.rs | 2 +- tests/workspace.rs | 2 +- 8 files changed, 5 insertions(+), 8 deletions(-) diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index e70488165b99..8871873c6612 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -1,5 +1,4 @@ #![feature(let_chains)] -#![feature(once_cell)] #![feature(rustc_private)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] // warn on lints, that are included in `rust-lang/rust`s bootstrap diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c9210bf73f89..3da7f95c1b9f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -7,7 +7,6 @@ #![feature(let_chains)] #![feature(lint_reasons)] #![feature(never_type)] -#![feature(once_cell)] #![feature(rustc_private)] #![feature(stmt_expr_attributes)] #![recursion_limit = "512"] diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index fd06c0b86775..619aa9f4bf6f 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -3,7 +3,6 @@ #![feature(let_chains)] #![feature(lint_reasons)] #![feature(never_type)] -#![feature(once_cell)] #![feature(rustc_private)] #![recursion_limit = "512"] #![cfg_attr(feature = "deny-warnings", deny(warnings))] diff --git a/src/driver.rs b/src/driver.rs index f08393c303ef..9e0822404b6b 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,6 +1,6 @@ #![feature(rustc_private)] #![feature(let_chains)] -#![feature(once_cell)] +#![feature(lazy_cell)] #![feature(lint_reasons)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] // warn on lints, that are included in `rust-lang/rust`s bootstrap diff --git a/tests/compile-test.rs b/tests/compile-test.rs index c10ee969c014..57890ff31737 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -1,5 +1,5 @@ #![feature(test)] // compiletest_rs requires this attribute -#![feature(once_cell)] +#![feature(lazy_cell)] #![feature(is_sorted)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![warn(rust_2018_idioms, unused_lifetimes)] diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 3a5d478fa314..68a878e9a3d3 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -3,7 +3,7 @@ //! //! See [Eating your own dog food](https://en.wikipedia.org/wiki/Eating_your_own_dog_food) for context -#![feature(once_cell)] +#![feature(lazy_cell)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![warn(rust_2018_idioms, unused_lifetimes)] diff --git a/tests/lint_message_convention.rs b/tests/lint_message_convention.rs index abd0d1bc5934..8feea800fdbe 100644 --- a/tests/lint_message_convention.rs +++ b/tests/lint_message_convention.rs @@ -1,4 +1,4 @@ -#![feature(once_cell)] +#![feature(lazy_cell)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![warn(rust_2018_idioms, unused_lifetimes)] diff --git a/tests/workspace.rs b/tests/workspace.rs index 95325e060378..c9cbc50546cf 100644 --- a/tests/workspace.rs +++ b/tests/workspace.rs @@ -1,4 +1,4 @@ -#![feature(once_cell)] +#![feature(lazy_cell)] use std::path::PathBuf; use std::process::Command; From a2165533e1b5797e1043b961b4d5aaa599e8a305 Mon Sep 17 00:00:00 2001 From: Elliot Bobrow Date: Wed, 29 Mar 2023 18:19:29 -0700 Subject: [PATCH 048/272] fix `single_component_path_imports` FP --- .../src/single_component_path_imports.rs | 59 +++++++++++++++---- tests/ui/single_component_path_imports.fixed | 6 ++ tests/ui/single_component_path_imports.rs | 6 ++ tests/ui/single_component_path_imports.stderr | 4 +- 4 files changed, 60 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index d46f6a6352c6..5743dd21c283 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use rustc_ast::node_id::{NodeId, NodeMap}; -use rustc_ast::{ptr::P, Crate, Item, ItemKind, MacroDef, ModKind, UseTreeKind}; +use rustc_ast::visit::{walk_expr, Visitor}; +use rustc_ast::{ptr::P, Crate, Expr, ExprKind, Item, ItemKind, MacroDef, ModKind, Ty, TyKind, UseTreeKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -55,7 +56,7 @@ impl EarlyLintPass for SingleComponentPathImports { return; } - self.check_mod(cx, &krate.items); + self.check_mod(&krate.items); } fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { @@ -84,8 +85,43 @@ impl EarlyLintPass for SingleComponentPathImports { } } +#[derive(Default)] +struct ImportUsageVisitor { + // keep track of imports reused with `self` keyword, such as `self::std` in the example below. + // Removing the `use std;` would make this a compile error (#10549) + // ``` + // use std; + // + // fn main() { + // let _ = self::std::io::stdout(); + // } + // ``` + imports_referenced_with_self: Vec, +} + +impl<'tcx> Visitor<'tcx> for ImportUsageVisitor { + fn visit_expr(&mut self, expr: &Expr) { + if let ExprKind::Path(_, path) = &expr.kind + && path.segments.len() > 1 + && path.segments[0].ident.name == kw::SelfLower + { + self.imports_referenced_with_self.push(path.segments[1].ident.name); + } + walk_expr(self, expr); + } + + fn visit_ty(&mut self, ty: &Ty) { + if let TyKind::Path(_, path) = &ty.kind + && path.segments.len() > 1 + && path.segments[0].ident.name == kw::SelfLower + { + self.imports_referenced_with_self.push(path.segments[1].ident.name); + } + } +} + impl SingleComponentPathImports { - fn check_mod(&mut self, cx: &EarlyContext<'_>, items: &[P]) { + fn check_mod(&mut self, items: &[P]) { // keep track of imports reused with `self` keyword, such as `self::crypto_hash` in the example // below. Removing the `use crypto_hash;` would make this a compile error // ``` @@ -108,18 +144,16 @@ impl SingleComponentPathImports { // ``` let mut macros = Vec::new(); + let mut import_usage_visitor = ImportUsageVisitor::default(); for item in items { - self.track_uses( - cx, - item, - &mut imports_reused_with_self, - &mut single_use_usages, - &mut macros, - ); + self.track_uses(item, &mut imports_reused_with_self, &mut single_use_usages, &mut macros); + import_usage_visitor.visit_item(item); } for usage in single_use_usages { - if !imports_reused_with_self.contains(&usage.name) { + if !imports_reused_with_self.contains(&usage.name) + && !import_usage_visitor.imports_referenced_with_self.contains(&usage.name) + { self.found.entry(usage.item_id).or_default().push(usage); } } @@ -127,7 +161,6 @@ impl SingleComponentPathImports { fn track_uses( &mut self, - cx: &EarlyContext<'_>, item: &Item, imports_reused_with_self: &mut Vec, single_use_usages: &mut Vec, @@ -139,7 +172,7 @@ impl SingleComponentPathImports { match &item.kind { ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => { - self.check_mod(cx, items); + self.check_mod(items); }, ItemKind::MacroDef(MacroDef { macro_rules: true, .. }) => { macros.push(item.ident.name); diff --git a/tests/ui/single_component_path_imports.fixed b/tests/ui/single_component_path_imports.fixed index 4c40739d6f55..8c96c4715d30 100644 --- a/tests/ui/single_component_path_imports.fixed +++ b/tests/ui/single_component_path_imports.fixed @@ -2,9 +2,11 @@ #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] +use core; use serde as edres; pub use serde; +use std; macro_rules! m { () => { @@ -17,6 +19,10 @@ fn main() { // False positive #5154, shouldn't trigger lint. m!(); + + // False positive #10549 + let _ = self::std::io::stdout(); + let _ = 0 as self::core::ffi::c_uint; } mod hello_mod { diff --git a/tests/ui/single_component_path_imports.rs b/tests/ui/single_component_path_imports.rs index 9280bab3c71b..8434bf7eaf1f 100644 --- a/tests/ui/single_component_path_imports.rs +++ b/tests/ui/single_component_path_imports.rs @@ -2,9 +2,11 @@ #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] +use core; use regex; use serde as edres; pub use serde; +use std; macro_rules! m { () => { @@ -17,6 +19,10 @@ fn main() { // False positive #5154, shouldn't trigger lint. m!(); + + // False positive #10549 + let _ = self::std::io::stdout(); + let _ = 0 as self::core::ffi::c_uint; } mod hello_mod { diff --git a/tests/ui/single_component_path_imports.stderr b/tests/ui/single_component_path_imports.stderr index 71dcc25d6e5b..d69a86470a5e 100644 --- a/tests/ui/single_component_path_imports.stderr +++ b/tests/ui/single_component_path_imports.stderr @@ -1,5 +1,5 @@ error: this import is redundant - --> $DIR/single_component_path_imports.rs:5:1 + --> $DIR/single_component_path_imports.rs:6:1 | LL | use regex; | ^^^^^^^^^^ help: remove it entirely @@ -7,7 +7,7 @@ LL | use regex; = note: `-D clippy::single-component-path-imports` implied by `-D warnings` error: this import is redundant - --> $DIR/single_component_path_imports.rs:23:5 + --> $DIR/single_component_path_imports.rs:29:5 | LL | use regex; | ^^^^^^^^^^ help: remove it entirely From 6e87ae0f1ae5247c83470c6c039c0946063bfdda Mon Sep 17 00:00:00 2001 From: xFrednet Date: Thu, 30 Mar 2023 10:49:29 +0200 Subject: [PATCH 049/272] Run metadata collection --- book/src/lint_configuration.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 33f2b5c1de99..2aebd632507c 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -54,6 +54,7 @@ Please use that command to update the file and do not edit it by hand. | [allow-mixed-uninlined-format-args](#allow-mixed-uninlined-format-args) | `true` | | [suppress-restriction-lint-in-const](#suppress-restriction-lint-in-const) | `false` | | [missing-docs-in-crate-items](#missing-docs-in-crate-items) | `false` | +| [future-size-threshold](#future-size-threshold) | `16384` | ### arithmetic-side-effects-allowed Suppress checking of the passed type names in all types of operations. @@ -550,4 +551,12 @@ crate. For example, `pub(crate)` items. * [missing_docs_in_private_items](https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items) +### future-size-threshold +The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint + +**Default Value:** `16384` (`u64`) + +* [large_futures](https://rust-lang.github.io/rust-clippy/master/index.html#large_futures) + + From 2e21b54789d2d61287e22fe4246cf856e5f4217d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 30 Mar 2023 19:09:56 +0400 Subject: [PATCH 050/272] rustc_middle: Document which exactly `DefId`s don't have `DefKind`s --- compiler/rustc_middle/src/hir/map/mod.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 89a485b47ca8..22df2f7d6f7b 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -8,7 +8,7 @@ use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; -use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; +use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::*; use rustc_index::vec::Idx; @@ -180,7 +180,19 @@ impl<'hir> Map<'hir> { /// Do not call this function directly. The query should be called. pub(super) fn opt_def_kind(self, local_def_id: LocalDefId) -> Option { let hir_id = self.local_def_id_to_hir_id(local_def_id); - let def_kind = match self.find(hir_id)? { + let node = match self.find(hir_id) { + Some(node) => node, + None => match self.def_key(local_def_id).disambiguated_data.data { + // FIXME: Some anonymous constants do not have corresponding HIR nodes, + // so many local queries will panic on their def ids. `None` is currently + // returned here instead of `DefKind::{Anon,Inline}Const` to avoid such panics. + // Ideally all def ids should have `DefKind`s, we need to create the missing + // HIR nodes or feed relevant query results to achieve that. + DefPathData::AnonConst => return None, + _ => bug!("no HIR node for def id {local_def_id:?}"), + }, + }; + let def_kind = match node { Node::Item(item) => match item.kind { ItemKind::Static(_, mt, _) => DefKind::Static(mt), ItemKind::Const(..) => DefKind::Const, @@ -267,7 +279,10 @@ impl<'hir> Map<'hir> { | Node::Param(_) | Node::Arm(_) | Node::Lifetime(_) - | Node::Block(_) => return None, + | Node::Block(_) => span_bug!( + self.span(hir_id), + "unexpected node with def id {local_def_id:?}: {node:?}" + ), }; Some(def_kind) } From 17f80456d18c954cd82a1232807ae8c5bc1cb5cb Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Thu, 30 Mar 2023 16:17:11 +0000 Subject: [PATCH 051/272] Ignore `file!()` macro in `print_literal`, `write_literal` --- clippy_lints/src/write.rs | 14 ++++++++++---- tests/ui/auxiliary/proc_macros.rs | 2 +- tests/ui/print_literal.rs | 4 ++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 8114a8463faa..d7c94b909bdc 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -463,12 +463,18 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { && let Some(value_string) = snippet_opt(cx, arg.expr.span) { let (replacement, replace_raw) = match lit.kind { - LitKind::Str | LitKind::StrRaw(_) => extract_str_literal(&value_string), + LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) { + Some(extracted) => extracted, + None => return, + }, LitKind::Char => ( match lit.symbol.as_str() { "\"" => "\\\"", "\\'" => "'", - _ => &value_string[1..value_string.len() - 1], + _ => match value_string.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) { + Some(stripped) => stripped, + None => return, + }, } .to_string(), false, @@ -533,13 +539,13 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { /// `r#"a"#` -> (`a`, true) /// /// `"b"` -> (`b`, false) -fn extract_str_literal(literal: &str) -> (String, bool) { +fn extract_str_literal(literal: &str) -> Option<(String, bool)> { let (literal, raw) = match literal.strip_prefix('r') { Some(stripped) => (stripped.trim_matches('#'), true), None => (literal, false), }; - (literal[1..literal.len() - 1].to_string(), raw) + Some((literal.strip_prefix('"')?.strip_suffix('"')?.to_string(), raw)) } enum UnescapeErr { diff --git a/tests/ui/auxiliary/proc_macros.rs b/tests/ui/auxiliary/proc_macros.rs index 325be83a0d73..3d5beab1eff1 100644 --- a/tests/ui/auxiliary/proc_macros.rs +++ b/tests/ui/auxiliary/proc_macros.rs @@ -63,7 +63,7 @@ fn group_with_span(delimiter: Delimiter, stream: TokenStream, span: Span) -> Gro /// Token used to escape the following token from the macro's span rules. const ESCAPE_CHAR: char = '$'; -/// Takes a single token followed by a sequence tokens. Returns the sequence of tokens with their +/// Takes a single token followed by a sequence of tokens. Returns the sequence of tokens with their /// span set to that of the first token. Tokens may be escaped with either `#ident` or `#(tokens)`. #[proc_macro] pub fn with_span(input: TokenStream) -> TokenStream { diff --git a/tests/ui/print_literal.rs b/tests/ui/print_literal.rs index 86f908f66b8f..538513e9156f 100644 --- a/tests/ui/print_literal.rs +++ b/tests/ui/print_literal.rs @@ -38,4 +38,8 @@ fn main() { // named args shouldn't change anything either println!("{foo} {bar}", foo = "hello", bar = "world"); println!("{bar} {foo}", foo = "hello", bar = "world"); + + // The string literal from `file!()` has a callsite span that isn't marked as coming from an + // expansion + println!("file: {}", file!()); } From d29dec1a3f15914871cd0451dab899501156688d Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Thu, 30 Mar 2023 13:23:48 -0400 Subject: [PATCH 052/272] Update subtree sync docs for changes in rustc-dev-guide --- book/src/development/infrastructure/sync.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/book/src/development/infrastructure/sync.md b/book/src/development/infrastructure/sync.md index 02cfc11b55ac..45a72c292146 100644 --- a/book/src/development/infrastructure/sync.md +++ b/book/src/development/infrastructure/sync.md @@ -19,8 +19,7 @@ to beta. For reference, the first sync following this cadence was performed the 2020-08-27. This process is described in detail in the following sections. For general -information about `subtree`s in the Rust repository see [Rust's -`CONTRIBUTING.md`][subtree]. +information about `subtree`s in the Rust repository see [the rustc-dev-guide][subtree]. ## Patching git-subtree to work with big repos @@ -118,5 +117,5 @@ All of the following commands have to be run inside the `rust` directory. 3. Open a PR to [`rust-lang/rust`] [gitgitgadget-pr]: https://github.com/gitgitgadget/git/pull/493 -[subtree]: https://rustc-dev-guide.rust-lang.org/contributing.html#external-dependencies-subtree +[subtree]: https://rustc-dev-guide.rust-lang.org/external-repos.html#external-dependencies-subtree [`rust-lang/rust`]: https://github.com/rust-lang/rust From 41b367fa5f0127ed7d245f517aaed9b8f4855974 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Sat, 11 Mar 2023 18:50:50 -0500 Subject: [PATCH 053/272] Gramar, and spelin kleanup A few minor cleanups in various markdown files, mostly focusing on spelling and ignoring non-compilable codeblocks. --- README.md | 6 ++-- book/src/README.md | 2 +- book/src/configuration.md | 8 +++--- book/src/development/README.md | 2 +- book/src/development/adding_lints.md | 24 ++++++++-------- book/src/development/basics.md | 2 +- .../development/common_tools_writing_lints.md | 14 +++++----- book/src/development/infrastructure/book.md | 4 +-- .../infrastructure/changelog_update.md | 2 +- .../src/development/infrastructure/release.md | 2 +- book/src/development/infrastructure/sync.md | 8 +++--- book/src/development/proposals/README.md | 2 +- .../src/development/proposals/roadmap-2021.md | 6 ++-- .../proposals/syntax-tree-patterns.md | 28 +++++++++---------- book/src/installation.md | 4 +-- book/src/lint_configuration.md | 8 +++--- book/src/lints.md | 10 +++---- book/src/usage.md | 4 +-- clippy_lints/src/utils/conf.rs | 8 +++--- etc/relicense/RELICENSE_DOCUMENTATION.md | 4 +-- lintcheck/README.md | 2 +- 21 files changed, 75 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index b69ed8900a49..85798e0e80c1 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Lints are divided into categories, each with a default [lint level](https://doc. You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. | Category | Description | Default level | -| --------------------- | ----------------------------------------------------------------------------------- | ------------- | +|-----------------------|-------------------------------------------------------------------------------------|---------------| | `clippy::all` | all lints that are on by default (correctness, suspicious, style, complexity, perf) | **warn/deny** | | `clippy::correctness` | code that is outright wrong or useless | **deny** | | `clippy::suspicious` | code that is most likely wrong or useless | **warn** | @@ -130,7 +130,7 @@ for example. You can add Clippy to Travis CI in the same way you use it locally: -```yml +```yaml language: rust rust: - stable @@ -253,7 +253,7 @@ rust-version = "1.30" The MSRV can also be specified as an attribute, like below. -```rust +```rust,ignore #![feature(custom_inner_attributes)] #![clippy::msrv = "1.30.0"] diff --git a/book/src/README.md b/book/src/README.md index df4a1f2702e4..3b6270962680 100644 --- a/book/src/README.md +++ b/book/src/README.md @@ -14,7 +14,7 @@ much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. | Category | Description | Default level | -| --------------------- | ----------------------------------------------------------------------------------- | ------------- | +|-----------------------|-------------------------------------------------------------------------------------|---------------| | `clippy::all` | all lints that are on by default (correctness, suspicious, style, complexity, perf) | **warn/deny** | | `clippy::correctness` | code that is outright wrong or useless | **deny** | | `clippy::suspicious` | code that is most likely wrong or useless | **warn** | diff --git a/book/src/configuration.md b/book/src/configuration.md index 87f4a697af9f..4947d3d12262 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -3,7 +3,7 @@ > **Note:** The configuration file is unstable and may be deprecated in the future. Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml`. It contains a -basic `variable = value` mapping eg. +basic `variable = value` mapping e.g. ```toml avoid-breaking-exported-api = false @@ -60,7 +60,7 @@ And to warn on `lint_name`, run cargo clippy -- -W clippy::lint_name ``` -This also works with lint groups. For example you can run Clippy with warnings for all lints enabled: +This also works with lint groups. For example, you can run Clippy with warnings for all lints enabled: ```terminal cargo clippy -- -W clippy::pedantic @@ -84,7 +84,7 @@ msrv = "1.30.0" The MSRV can also be specified as an attribute, like below. -```rust +```rust,ignore #![feature(custom_inner_attributes)] #![clippy::msrv = "1.30.0"] @@ -96,7 +96,7 @@ fn main() { You can also omit the patch version when specifying the MSRV, so `msrv = 1.30` is equivalent to `msrv = 1.30.0`. -Note: `custom_inner_attributes` is an unstable feature so it has to be enabled explicitly. +Note: `custom_inner_attributes` is an unstable feature, so it has to be enabled explicitly. Lints that recognize this configuration option can be found [here](https://rust-lang.github.io/rust-clippy/master/index.html#msrv) diff --git a/book/src/development/README.md b/book/src/development/README.md index 5cf7201cffad..616e6d182b72 100644 --- a/book/src/development/README.md +++ b/book/src/development/README.md @@ -5,7 +5,7 @@ making Clippy better by contributing to it. In that case, welcome to the project! > _Note:_ If you're just interested in using Clippy, there's nothing to see from -> this point onward and you should return to one of the earlier chapters. +> this point onward, and you should return to one of the earlier chapters. ## Getting started diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index 0f5ee7103de1..3f4088e74eaf 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -24,7 +24,7 @@ because that's clearly a non-descriptive name. - [Lint passes](#lint-passes) - [Emitting a lint](#emitting-a-lint) - [Adding the lint logic](#adding-the-lint-logic) - - [Specifying the lint's minimum supported Rust version (MSRV)](#specifying-the-lints-minimum-supported-rust-version-msrv) + - [Specifying the lint's minimum supported Rust version (MSRV)](#specifying-the-lints-minimum-supported-rust-version--msrv-) - [Author lint](#author-lint) - [Print HIR lint](#print-hir-lint) - [Documentation](#documentation) @@ -275,7 +275,7 @@ When declaring a new lint by hand and `cargo dev update_lints` is used, the lint pass may have to be registered manually in the `register_plugins` function in `clippy_lints/src/lib.rs`: -```rust +```rust,ignore store.register_early_pass(|| Box::new(foo_functions::FooFunctions)); ``` @@ -301,7 +301,7 @@ either [`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass]. In short, the `LateLintPass` has access to type information while the `EarlyLintPass` doesn't. If you don't need access to type information, use the -`EarlyLintPass`. The `EarlyLintPass` is also faster. However linting speed +`EarlyLintPass`. The `EarlyLintPass` is also faster. However, linting speed hasn't really been a concern with Clippy so far. Since we don't need type information for checking the function name, we used @@ -318,7 +318,7 @@ implementation of the lint logic. Let's start by implementing the `EarlyLintPass` for our `FooFunctions`: -```rust +```rust,ignore impl EarlyLintPass for FooFunctions { fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) { // TODO: Emit lint here @@ -337,10 +337,10 @@ variety of lint emission functions. They can all be found in [`clippy_utils/src/diagnostics.rs`][diagnostics]. `span_lint_and_help` seems most appropriate in this case. It allows us to -provide an extra help message and we can't really suggest a better name +provide an extra help message, and we can't really suggest a better name automatically. This is how it looks: -```rust +```rust,ignore impl EarlyLintPass for FooFunctions { fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) { span_lint_and_help( @@ -479,7 +479,7 @@ the value from `clippy.toml`. This can be accounted for using the `extract_msrv_attr!(LintContext)` macro and passing `LateContext`/`EarlyContext`. -```rust +```rust,ignore impl<'tcx> LateLintPass<'tcx> for ManualStrip { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { ... @@ -493,7 +493,7 @@ the lint's test file, `tests/ui/manual_strip.rs` in this example. It should have a case for the version below the MSRV and one with the same contents but for the MSRV version itself. -```rust +```rust,ignore ... #[clippy::msrv = "1.44"] @@ -524,7 +524,7 @@ define_Conf! { If you have trouble implementing your lint, there is also the internal `author` lint to generate Clippy code that detects the offending pattern. It does not -work for all of the Rust syntax, but can give a good starting point. +work for all the Rust syntax, but can give a good starting point. The quickest way to use it, is the [Rust playground: play.rust-lang.org][author_example]. Put the code you want to lint into the @@ -617,7 +617,7 @@ output in the `stdout` part. ## PR Checklist -Before submitting your PR make sure you followed all of the basic requirements: +Before submitting your PR make sure you followed all the basic requirements: @@ -637,7 +637,7 @@ for some users. Adding a configuration is done in the following steps: 1. Adding a new configuration entry to [`clippy_lints::utils::conf`] like this: - ```rust + ```rust,ignore /// Lint: LINT_NAME. /// /// @@ -690,7 +690,7 @@ for some users. Adding a configuration is done in the following steps: configuration value is now cloned or copied into a local value that is then passed to the impl struct like this: - ```rust + ```rust,ignore // Default generated registration: store.register_*_pass(|| box module::StructName); diff --git a/book/src/development/basics.md b/book/src/development/basics.md index 6fb53236e6f1..b07d3de7187e 100644 --- a/book/src/development/basics.md +++ b/book/src/development/basics.md @@ -125,7 +125,7 @@ We follow a rustc no merge-commit policy. See ## Common Abbreviations | Abbreviation | Meaning | -| ------------ | -------------------------------------- | +|--------------|----------------------------------------| | UB | Undefined Behavior | | FP | False Positive | | FN | False Negative | diff --git a/book/src/development/common_tools_writing_lints.md b/book/src/development/common_tools_writing_lints.md index f5aa06e4bf65..09171d86a209 100644 --- a/book/src/development/common_tools_writing_lints.md +++ b/book/src/development/common_tools_writing_lints.md @@ -3,7 +3,7 @@ You may need following tooltips to catch up with common operations. - [Common tools for writing lints](#common-tools-for-writing-lints) - - [Retrieving the type of an expression](#retrieving-the-type-of-an-expression) + - [Retrieving the type of expression](#retrieving-the-type-of-expression) - [Checking if an expr is calling a specific method](#checking-if-an-expr-is-calling-a-specific-method) - [Checking for a specific type](#checking-for-a-specific-type) - [Checking if a type implements a specific trait](#checking-if-a-type-implements-a-specific-trait) @@ -16,7 +16,7 @@ Useful Rustc dev guide links: - [Type checking](https://rustc-dev-guide.rust-lang.org/type-checking.html) - [Ty module](https://rustc-dev-guide.rust-lang.org/ty.html) -## Retrieving the type of an expression +## Retrieving the type of expression Sometimes you may want to retrieve the type `Ty` of an expression `Expr`, for example to answer following questions: @@ -45,7 +45,7 @@ impl LateLintPass<'_> for MyStructLint { } ``` -Similarly in [`TypeckResults`][TypeckResults] methods, you have the +Similarly, in [`TypeckResults`][TypeckResults] methods, you have the [`pat_ty()`][pat_ty] method to retrieve a type from a pattern. Two noticeable items here: @@ -192,7 +192,7 @@ functions to deal with macros: - `span.from_expansion()`: detects if a span is from macro expansion or desugaring. Checking this is a common first step in a lint. - ```rust + ```rust,ignore if expr.span.from_expansion() { // just forget it return; @@ -203,11 +203,11 @@ functions to deal with macros: if so, which macro call expanded it. It is sometimes useful to check if the context of two spans are equal. - ```rust + ```rust,ignore // expands to `1 + 0`, but don't lint 1 + mac!() ``` - ```rust + ```rust,ignore if left.span.ctxt() != right.span.ctxt() { // the coder most likely cannot modify this expression return; @@ -246,7 +246,7 @@ functions to deal with macros: `macro_rules!` with `a == $b`, `$b` is expanded to some expression with a different context from `a`. - ```rust + ```rust,ignore macro_rules! m { ($a:expr, $b:expr) => { if $a.is_some() { diff --git a/book/src/development/infrastructure/book.md b/book/src/development/infrastructure/book.md index dbd624ecd738..de5de4bebaa9 100644 --- a/book/src/development/infrastructure/book.md +++ b/book/src/development/infrastructure/book.md @@ -13,7 +13,7 @@ guide to Clippy that you're reading right now. The Clippy book is formatted with While not strictly necessary since the book source is simply Markdown text files, having mdBook locally will allow you to build, test and serve the book locally to view changes before you commit them to the repository. You likely -already have `cargo` installed, so the easiest option is to simply: +already have `cargo` installed, so the easiest option is to: ```shell cargo install mdbook @@ -26,7 +26,7 @@ instructions for other options. The book's [src](https://github.com/rust-lang/rust-clippy/tree/master/book/src) -directory contains all of the markdown files used to generate the book. If you +directory contains all the markdown files used to generate the book. If you want to see your changes in real time, you can use the mdBook `serve` command to run a web server locally that will automatically update changes as they are made. From the top level of your `rust-clippy` directory: diff --git a/book/src/development/infrastructure/changelog_update.md b/book/src/development/infrastructure/changelog_update.md index d1ac7237b5e3..df9b1bbe18f3 100644 --- a/book/src/development/infrastructure/changelog_update.md +++ b/book/src/development/infrastructure/changelog_update.md @@ -101,7 +101,7 @@ Look for the [`beta-accepted`] label and make sure to also include the PRs with that label in the changelog. If you can, remove the `beta-accepted` labels **after** the changelog PR was merged. -> _Note:_ Some of those PRs might even got backported to the previous `beta`. +> _Note:_ Some of those PRs might even get backported to the previous `beta`. > Those have to be included in the changelog of the _previous_ release. ### 4. Update `clippy::version` attributes diff --git a/book/src/development/infrastructure/release.md b/book/src/development/infrastructure/release.md index 0572281803e7..98fabf8e89ae 100644 --- a/book/src/development/infrastructure/release.md +++ b/book/src/development/infrastructure/release.md @@ -44,7 +44,7 @@ $ git push origin backport_remerge # This can be pushed to your fork ``` After this, open a PR to the master branch. In this PR, the commit hash of the -`HEAD` of the `beta` branch must exists. In addition to that, no files should be +`HEAD` of the `beta` branch must exist. In addition to that, no files should be changed by this PR. ## Update the `beta` branch diff --git a/book/src/development/infrastructure/sync.md b/book/src/development/infrastructure/sync.md index 02cfc11b55ac..7fb127c6284f 100644 --- a/book/src/development/infrastructure/sync.md +++ b/book/src/development/infrastructure/sync.md @@ -47,7 +47,7 @@ sudo chown --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subt > _Note:_ If you are a Debian user, `dash` is the shell used by default for > scripts instead of `sh`. This shell has a hardcoded recursion limit set to -> 1000. In order to make this process work, you need to force the script to run +> 1,000. In order to make this process work, you need to force the script to run > `bash` instead. You can do this by editing the first line of the `git-subtree` > script and changing `sh` to `bash`. @@ -71,10 +71,10 @@ $ git remote add clippy-local /path/to/rust-clippy ## Performing the sync from [`rust-lang/rust`] to Clippy -Here is a TL;DR version of the sync process (all of the following commands have +Here is a TL;DR version of the sync process (all the following commands have to be run inside the `rust` directory): -1. Clone the [`rust-lang/rust`] repository or make sure it is up to date. +1. Clone the [`rust-lang/rust`] repository or make sure it is up-to-date. 2. Checkout the commit from the latest available nightly. You can get it using `rustup check`. 3. Sync the changes to the rust-copy of Clippy to your Clippy fork: @@ -107,7 +107,7 @@ to be run inside the `rust` directory): ## Performing the sync from Clippy to [`rust-lang/rust`] -All of the following commands have to be run inside the `rust` directory. +All the following commands have to be run inside the `rust` directory. 1. Make sure you have checked out the latest `master` of `rust-lang/rust`. 2. Sync the `rust-lang/rust-clippy` master to the rust-copy of Clippy: diff --git a/book/src/development/proposals/README.md b/book/src/development/proposals/README.md index 78fe34ebf8fa..059c22ce1ce8 100644 --- a/book/src/development/proposals/README.md +++ b/book/src/development/proposals/README.md @@ -6,6 +6,6 @@ or around Clippy in the long run. Besides adding more and more lints and improve the lints that Clippy already has, Clippy is also interested in making the experience of its users, developers and maintainers better over time. Projects that address bigger picture things -like this usually take more time and it is useful to have a proposal for those +like this usually take more time, and it is useful to have a proposal for those first. This is the place where such proposals are collected, so that we can refer to them when working on them. diff --git a/book/src/development/proposals/roadmap-2021.md b/book/src/development/proposals/roadmap-2021.md index fe8b080f56f2..4406616bbb61 100644 --- a/book/src/development/proposals/roadmap-2021.md +++ b/book/src/development/proposals/roadmap-2021.md @@ -52,8 +52,8 @@ In the following, plans to improve the usability are covered. #### No Output After `cargo check` -Currently when `cargo clippy` is run after `cargo check`, it does not produce -any output. This is especially problematic since `rust-analyzer` is on the rise +Currently, when `cargo clippy` is run after `cargo check`, it does not produce +any output. This is especially problematic since `rust-analyzer` is on the rise, and it uses `cargo check` for checking code. A fix is already implemented, but it still has to be pushed over the finish line. This also includes the stabilization of the `cargo clippy --fix` command or the support of multi-span @@ -221,7 +221,7 @@ regarding the user facing issues. Rust's roadmap process was established by [RFC 1728] in 2016. Since then every year a roadmap was published, that defined the bigger plans for the coming -years. This years roadmap can be found [here][Rust Roadmap 2021]. +years. This year roadmap can be found [here][Rust Roadmap 2021]. [RFC 1728]: https://rust-lang.github.io/rfcs/1728-north-star.html diff --git a/book/src/development/proposals/syntax-tree-patterns.md b/book/src/development/proposals/syntax-tree-patterns.md index ea4978011b19..36d722609f4a 100644 --- a/book/src/development/proposals/syntax-tree-patterns.md +++ b/book/src/development/proposals/syntax-tree-patterns.md @@ -16,7 +16,7 @@ lints. For non-trivial lints, it often requires nested pattern matching of AST / HIR nodes. For example, testing that an expression is a boolean literal requires the following checks: -```rust +```rust,ignore if let ast::ExprKind::Lit(lit) = &expr.node { if let ast::LitKind::Bool(_) = &lit.node { ... @@ -28,7 +28,7 @@ Writing this kind of matching code quickly becomes a complex task and the resulting code is often hard to comprehend. The code below shows a simplified version of the pattern matching required by the `collapsible_if` lint: -```rust +```rust,ignore // simplified version of the collapsible_if lint if let ast::ExprKind::If(check, then, None) = &expr.node { if then.stmts.len() == 1 { @@ -111,7 +111,7 @@ expressions that are boolean literals with value `false`. The pattern can then be used to implement lints in the following way: -```rust +```rust,ignore ... impl EarlyLintPass for MyAwesomeLint { @@ -346,7 +346,7 @@ pattern!{ one could get references to the nodes that matched the subpatterns in the following way: -```rust +```rust,ignore ... fn check_expr(expr: &syntax::ast::Expr) { if let Some(result) = my_pattern(expr) { @@ -372,7 +372,7 @@ matches arrays that consist of any number of literal expressions. Because those expressions are named `foo`, the result struct contains a `foo` attribute which is a vector of expressions: -```rust +```rust,ignore ... if let Some(result) = my_pattern_seq(expr) { result.foo // type: Vec<&syntax::ast::Expr> @@ -394,7 +394,7 @@ In the pattern above, the `bar` name is only defined if the pattern matches a boolean literal. If it matches an integer literal, the name isn't set. To account for this, the result struct's `bar` attribute is an option type: -```rust +```rust,ignore ... if let Some(result) = my_pattern_alt(expr) { result.bar // type: Option<&bool> @@ -404,7 +404,7 @@ if let Some(result) = my_pattern_alt(expr) { It's also possible to use a name in multiple alternation branches if they have compatible types: -```rust +```rust,ignore pattern!{ // matches if expression is a boolean or integer literal my_pattern_mult: Expr = @@ -519,7 +519,7 @@ The `Alt`, `Seq` and `Opt` structs look like these: > Note: The current implementation can be found > [here](https://github.com/fkohlgrueber/pattern-matching/blob/dfb3bc9fbab69cec7c91e72564a63ebaa2ede638/pattern-match/src/matchers.rs#L35-L60). -```rust +```rust,ignore pub enum Alt { Any, Elmt(Box), @@ -580,7 +580,7 @@ implementations is the `IsMatch` trait. It defines how to match *PatternTree* nodes against specific syntax tree nodes. A simplified implementation of the `IsMatch` trait is shown below: -```rust +```rust,ignore pub trait IsMatch { fn is_match(&self, other: &'o O) -> bool; } @@ -619,7 +619,7 @@ approach (matching against the coarse pattern first and checking for additional properties later) might be slower than the current practice of checking for structure and additional properties in one pass. For example, the following lint -```rust +```rust,ignore pattern!{ pat_if_without_else: Expr = If( @@ -644,7 +644,7 @@ first matches against the pattern and then checks that the `then` block doesn't start with a comment. Using clippy's current approach, it's possible to check for these conditions earlier: -```rust +```rust,ignore fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { if_chain! { if let ast::ExprKind::If(ref check, ref then, None) = expr.node; @@ -708,7 +708,7 @@ is similar to actual Rust syntax (probably like the `quote!` macro). For example, a pattern that matches `if` expressions that have `false` in their condition could look like this: -```rust +```rust,ignore if false { #[*] } @@ -742,7 +742,7 @@ affects the structure of the resulting AST. `1 + 0 + 0` is parsed as `(1 + 0) + Another example of a problem would be named submatches. Take a look at this pattern: -```rust +```rust,ignore fn test() { 1 #foo } @@ -862,7 +862,7 @@ op b` and recommends changing it to `a op= b` requires that both occurrences of `a` are the same. Using `=#...` as syntax for backreferences, the lint could be implemented like this: -```rust +```rust,ignore pattern!{ assign_op_pattern: Expr = Assign(_#target, Binary(_, =#target, _) diff --git a/book/src/installation.md b/book/src/installation.md index cce888b17d4d..d54fff9deba1 100644 --- a/book/src/installation.md +++ b/book/src/installation.md @@ -17,8 +17,8 @@ $ rustup component add clippy [--toolchain=] ## From Source -Take a look at the [Basics] chapter in the Clippy developer guide to find step -by step instructions on how to build and install Clippy from source. +Take a look at the [Basics] chapter in the Clippy developer guide to find step-by-step +instructions on how to build and install Clippy from source. [Basics]: development/basics.md#install-from-source [Usage]: usage.md diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 4415a05251e9..78e1a55cff32 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -195,7 +195,7 @@ The maximum cognitive complexity a function can have ### disallowed-names The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value `".."` can be used as part of the list to indicate, that the configured values should be appended to the -default configuration of Clippy. By default any configuration will replace the default value. +default configuration of Clippy. By default, any configuration will replace the default value. **Default Value:** `["foo", "baz", "quux"]` (`Vec`) @@ -205,7 +205,7 @@ default configuration of Clippy. By default any configuration will replace the d ### doc-valid-idents The list of words this lint should not consider as identifiers needing ticks. The value `".."` can be used as part of the list to indicate, that the configured values should be appended to the -default configuration of Clippy. By default any configuraction will replace the default value. For example: +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. @@ -415,7 +415,7 @@ For internal testing only, ignores the current `publish` settings in the Cargo m Enforce the named macros always use the braces specified. A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro -is could be used with a full path two `MacroMatcher`s have to be added one with the full path +could be used with a full path two `MacroMatcher`s have to be added one with the full path `crate_name::macro_name` and one with just the macro name. **Default Value:** `[]` (`Vec`) @@ -449,7 +449,7 @@ Whether to apply the raw pointer heuristic to determine if a type is `Send`. ### max-suggested-slice-pattern-length When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in -the slice pattern that is suggested. If more elements would be necessary, the lint is suppressed. +the slice pattern that is suggested. If more elements are necessary, the lint is suppressed. For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. **Default Value:** `3` (`u64`) diff --git a/book/src/lints.md b/book/src/lints.md index 35e30960b56c..442dc63914e9 100644 --- a/book/src/lints.md +++ b/book/src/lints.md @@ -17,7 +17,7 @@ The different lint groups were defined in the [Clippy 1.0 RFC]. The `clippy::correctness` group is the only lint group in Clippy which lints are deny-by-default and abort the compilation when triggered. This is for good reason: If you see a `correctness` lint, it means that your code is outright -wrong or useless and you should try to fix it. +wrong or useless, and you should try to fix it. Lints in this category are carefully picked and should be free of false positives. So just `#[allow]`ing those lints is not recommended. @@ -41,7 +41,7 @@ simplify your code. It mostly focuses on code that can be written in a shorter and more readable way, while preserving the semantics. If you should see a complexity lint, it usually means that you can remove or -replace some code and it is recommended to do so. However, if you need the more +replace some code, and it is recommended to do so. However, if you need the more complex code for some expressiveness reason, it is recommended to allow complexity lints on a case-by-case basis. @@ -50,9 +50,9 @@ complexity lints on a case-by-case basis. The `clippy::perf` group gives you suggestions on how you can increase the performance of your code. Those lints are mostly about code that the compiler can't trivially optimize, but has to be written in a slightly different way to -make the optimizer's job easier. +make the optimizer job easier. -Perf lints are usually easy to apply and it is recommended to do so. +Perf lints are usually easy to apply, and it is recommended to do so. ## Style @@ -91,7 +91,7 @@ and your use case. Lints from this group will restrict you in some way. If you enable a restriction lint for your crate it is recommended to also fix code that this lint triggers -on. However, those lints are really strict by design and you might want to +on. However, those lints are really strict by design, and you might want to `#[allow]` them in some special cases, with a comment justifying that. ## Cargo diff --git a/book/src/usage.md b/book/src/usage.md index 61a90445d753..32084a9199b7 100644 --- a/book/src/usage.md +++ b/book/src/usage.md @@ -19,7 +19,7 @@ cargo clippy ### Lint configuration The above command will run the default set of lints, which are included in the -lint group `clippy::all`. You might want to use even more lints or you might not +lint group `clippy::all`. You might want to use even more lints, or you may not agree with every Clippy lint, and for that there are ways to configure lint levels. @@ -98,7 +98,7 @@ other of Clippy's lint groups. You can configure lint levels in source code the same way you can configure `rustc` lints: -```rust +```rust,ignore #![allow(clippy::style)] #[warn(clippy::double_neg)] diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index e1c9dd101177..f75a5cf7196a 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -275,13 +275,13 @@ define_Conf! { /// /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the - /// default configuration of Clippy. By default any configuration will replace the default value. + /// default configuration of Clippy. By default, any configuration will replace the default value. (disallowed_names: Vec = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()), /// Lint: DOC_MARKDOWN. /// /// The list of words this lint should not consider as identifiers needing ticks. The value /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the - /// default configuration of Clippy. By default any configuraction will replace the default value. For example: + /// 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. /// @@ -390,7 +390,7 @@ define_Conf! { /// Enforce the named macros always use the braces specified. /// /// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro - /// is could be used with a full path two `MacroMatcher`s have to be added one with the full path + /// could be used with a full path two `MacroMatcher`s have to be added one with the full path /// `crate_name::macro_name` and one with just the macro name. (standard_macro_braces: Vec = Vec::new()), /// Lint: MISSING_ENFORCED_IMPORT_RENAMES. @@ -408,7 +408,7 @@ define_Conf! { /// Lint: INDEX_REFUTABLE_SLICE. /// /// When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in - /// the slice pattern that is suggested. If more elements would be necessary, the lint is suppressed. + /// the slice pattern that is suggested. If more elements are necessary, the lint is suppressed. /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. (max_suggested_slice_pattern_length: u64 = 3), /// Lint: AWAIT_HOLDING_INVALID_TYPE. diff --git a/etc/relicense/RELICENSE_DOCUMENTATION.md b/etc/relicense/RELICENSE_DOCUMENTATION.md index fcd7abbf3f16..ffb99cde4f86 100644 --- a/etc/relicense/RELICENSE_DOCUMENTATION.md +++ b/etc/relicense/RELICENSE_DOCUMENTATION.md @@ -35,7 +35,7 @@ relicensing are archived on GitHub. We also have saved Wayback Machine copies of The usernames of commenters on these issues can be found in relicense_comments.txt -There are a couple people in relicense_comments.txt who are not found in contributors.txt: +There are a few people in relicense_comments.txt who are not found in contributors.txt: - @EpocSquadron has [made minor text contributions to the README](https://github.com/rust-lang/rust-clippy/commits?author=EpocSquadron) which have since been overwritten, and @@ -55,7 +55,7 @@ There are a couple people in relicense_comments.txt who are not found in contrib we rewrote (see below) -Two of these contributors had nonminor contributions (#2184, #427) requiring a rewrite, carried out in #3251 +Two of these contributors had non-minor contributions (#2184, #427) requiring a rewrite, carried out in #3251 ([archive](http://web.archive.org/web/20181005192411/https://github.com/rust-lang-nursery/rust-clippy/pull/3251), [screenshot](https://user-images.githubusercontent.com/1617736/46573515-5cb69580-c94b-11e8-86e5-b456452121b2.png)) diff --git a/lintcheck/README.md b/lintcheck/README.md index e997eb47e321..faf3ce9093a2 100644 --- a/lintcheck/README.md +++ b/lintcheck/README.md @@ -16,7 +16,7 @@ or cargo lintcheck ``` -By default the logs will be saved into +By default, the logs will be saved into `lintcheck-logs/lintcheck_crates_logs.txt`. You can set a custom sources.toml by adding `--crates-toml custom.toml` or using From 10c36445ff13625186d924250b3ba9c4b90b23f9 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Thu, 30 Mar 2023 21:43:32 +0100 Subject: [PATCH 054/272] Update non-derive macro error message to match suggestion It's now split between two errors, one to remove the invalid derive macro and one suggesting adding a new non-derive macro --- compiler/rustc_resolve/src/macros.rs | 12 +++------- .../macros/macro-path-prelude-fail-4.stderr | 12 +++++----- .../macro-namespace-reserved-2.stderr | 24 +++++++++---------- .../tool-attributes-misplaced-2.stderr | 12 +++++----- 4 files changed, 27 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 38e8cf8cd2f1..082c051e21e5 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -549,15 +549,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { err.span_label(path.span, format!("not {} {}", article, expected)); if kind == MacroKind::Derive && ext.macro_kind() != MacroKind::Derive { - // Suggest removing the derive() as the macro isn't Derive - let opening_span = - path.span.shrink_to_lo().with_lo(path.span.lo() - rustc_span::BytePos(7)); - let closing_span = - path.span.shrink_to_hi().with_hi(path.span.hi() + rustc_span::BytePos(1)); - err.span_help( - vec![opening_span, closing_span], - "remove the surrounding \"derive()\":", - ); + // Suggest moving the macro our of the derive() as the macro isn't Derive + err.span_help(path.span, "Remove from the surrounding `derive()`"); + err.help(format!("Add as non-Derive macro\n`#[{}]`", path_str)); } err.emit(); diff --git a/tests/ui/macros/macro-path-prelude-fail-4.stderr b/tests/ui/macros/macro-path-prelude-fail-4.stderr index fb4e19d85651..cefe655b0f78 100644 --- a/tests/ui/macros/macro-path-prelude-fail-4.stderr +++ b/tests/ui/macros/macro-path-prelude-fail-4.stderr @@ -2,13 +2,13 @@ error: expected derive macro, found built-in attribute `inline` --> $DIR/macro-path-prelude-fail-4.rs:1:10 | LL | #[derive(inline)] - | ^^^^^^ not a derive macro + | ^^^^^^ + | | + | not a derive macro + | help: Remove from the surrounding `derive()` | -help: remove the surrounding "derive()": - --> $DIR/macro-path-prelude-fail-4.rs:1:3 - | -LL | #[derive(inline)] - | ^^^^^^^ ^ + = help: Add as non-Derive macro + `#[inline]` error: aborting due to previous error diff --git a/tests/ui/proc-macro/macro-namespace-reserved-2.stderr b/tests/ui/proc-macro/macro-namespace-reserved-2.stderr index 6e7adc2e3b12..01814a302374 100644 --- a/tests/ui/proc-macro/macro-namespace-reserved-2.stderr +++ b/tests/ui/proc-macro/macro-namespace-reserved-2.stderr @@ -56,13 +56,13 @@ error: expected derive macro, found attribute macro `my_macro_attr` --> $DIR/macro-namespace-reserved-2.rs:53:10 | LL | #[derive(my_macro_attr)] - | ^^^^^^^^^^^^^ not a derive macro + | ^^^^^^^^^^^^^ + | | + | not a derive macro + | help: Remove from the surrounding `derive()` | -help: remove the surrounding "derive()": - --> $DIR/macro-namespace-reserved-2.rs:53:3 - | -LL | #[derive(my_macro_attr)] - | ^^^^^^^ ^ + = help: Add as non-Derive macro + `#[my_macro_attr]` error: can't use a procedural macro from the same crate that defines it --> $DIR/macro-namespace-reserved-2.rs:56:10 @@ -92,13 +92,13 @@ error: expected derive macro, found macro `crate::my_macro` --> $DIR/macro-namespace-reserved-2.rs:50:10 | LL | #[derive(crate::my_macro)] - | ^^^^^^^^^^^^^^^ not a derive macro + | ^^^^^^^^^^^^^^^ + | | + | not a derive macro + | help: Remove from the surrounding `derive()` | -help: remove the surrounding "derive()": - --> $DIR/macro-namespace-reserved-2.rs:50:3 - | -LL | #[derive(crate::my_macro)] - | ^^^^^^^ ^ + = help: Add as non-Derive macro + `#[crate::my_macro]` error: cannot find macro `my_macro_attr` in this scope --> $DIR/macro-namespace-reserved-2.rs:28:5 diff --git a/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr b/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr index 6befa99f5835..c1ed2618b2af 100644 --- a/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr +++ b/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr @@ -2,13 +2,13 @@ error: expected derive macro, found tool attribute `rustfmt::skip` --> $DIR/tool-attributes-misplaced-2.rs:1:10 | LL | #[derive(rustfmt::skip)] - | ^^^^^^^^^^^^^ not a derive macro + | ^^^^^^^^^^^^^ + | | + | not a derive macro + | help: Remove from the surrounding `derive()` | -help: remove the surrounding "derive()": - --> $DIR/tool-attributes-misplaced-2.rs:1:3 - | -LL | #[derive(rustfmt::skip)] - | ^^^^^^^ ^ + = help: Add as non-Derive macro + `#[rustfmt::skip]` error: expected macro, found tool attribute `rustfmt::skip` --> $DIR/tool-attributes-misplaced-2.rs:5:5 From ed84d1d9052912d4d948313be72a6dd50c2baa26 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Thu, 30 Mar 2023 21:53:56 +0100 Subject: [PATCH 055/272] Fix typo --- compiler/rustc_resolve/src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 082c051e21e5..39e30767da27 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -549,7 +549,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { err.span_label(path.span, format!("not {} {}", article, expected)); if kind == MacroKind::Derive && ext.macro_kind() != MacroKind::Derive { - // Suggest moving the macro our of the derive() as the macro isn't Derive + // Suggest moving the macro out of the derive() as the macro isn't Derive err.span_help(path.span, "Remove from the surrounding `derive()`"); err.help(format!("Add as non-Derive macro\n`#[{}]`", path_str)); } From 6601d85c22a0e5b632e3332991c45058ed420ba2 Mon Sep 17 00:00:00 2001 From: "Samuel \"Sam\" Tardieu" Date: Wed, 22 Mar 2023 22:56:17 +0100 Subject: [PATCH 056/272] Flag `bufreader.lines().filter_map(Result::ok)` as suspicious --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/lines_filter_map_ok.rs | 100 ++++++++++++++++++++++++ clippy_utils/src/paths.rs | 2 + tests/ui/lines_filter_map_ok.fixed | 29 +++++++ tests/ui/lines_filter_map_ok.rs | 29 +++++++ tests/ui/lines_filter_map_ok.stderr | 51 ++++++++++++ 8 files changed, 215 insertions(+) create mode 100644 clippy_lints/src/lines_filter_map_ok.rs create mode 100644 tests/ui/lines_filter_map_ok.fixed create mode 100644 tests/ui/lines_filter_map_ok.rs create mode 100644 tests/ui/lines_filter_map_ok.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index f54bfbfa472e..239631777e9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4647,6 +4647,7 @@ Released 2018-09-13 [`let_underscore_untyped`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_untyped [`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value [`let_with_type_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_with_type_underscore +[`lines_filter_map_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#lines_filter_map_ok [`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist [`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index f07c7f0534c6..7836e5ccb9a6 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -232,6 +232,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::let_with_type_underscore::LET_WITH_TYPE_UNDERSCORE_INFO, crate::lifetimes::EXTRA_UNUSED_LIFETIMES_INFO, crate::lifetimes::NEEDLESS_LIFETIMES_INFO, + crate::lines_filter_map_ok::LINES_FILTER_MAP_OK_INFO, crate::literal_representation::DECIMAL_LITERAL_REPRESENTATION_INFO, crate::literal_representation::INCONSISTENT_DIGIT_GROUPING_INFO, crate::literal_representation::LARGE_DIGIT_GROUPS_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 75c53a09d796..ce055f16240b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -171,6 +171,7 @@ mod let_if_seq; mod let_underscore; mod let_with_type_underscore; mod lifetimes; +mod lines_filter_map_ok; mod literal_representation; mod loops; mod macro_use; @@ -949,6 +950,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: avoid_breaking_exported_api, )) }); + store.register_late_pass(|_| Box::new(lines_filter_map_ok::LinesFilterMapOk)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs new file mode 100644 index 000000000000..b0f9276475d3 --- /dev/null +++ b/clippy_lints/src/lines_filter_map_ok.rs @@ -0,0 +1,100 @@ +use clippy_utils::{ + diagnostics::span_lint_and_then, is_diag_item_method, is_trait_method, match_def_path, path_to_local_id, paths, + ty::match_type, +}; +use rustc_errors::Applicability; +use rustc_hir::{Body, Closure, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Detect uses of `lines.filter_map(Result::ok)` or `lines.flat_map(Result::ok)` + /// when `lines` has type `std::io::Lines`. + /// + /// ### Why is this bad? + /// `Lines` instances might produce a never-ending stream of `Err`, in which case + /// `filter_map(Result::ok)` will enter an infinite loop while waiting for an + /// `Ok` variant. Calling `next()` once is sufficient to enter the infinite loop, + /// even in the absence of explicit loops in the user code. + /// + /// This situation can arise when working with user-provided paths. On some platforms, + /// `std::fs::File::open(path)` might return `Ok(fs)` even when `path` is a directory, + /// but any later attempt to read from `fs` will return an error. + /// + /// ### Known problems + /// This lint suggests replacing `filter_map()` or `flat_map()` applied to a `Lines` + /// instance in all cases. There two cases where the suggestion might not be + /// appropriate or necessary: + /// + /// - If the `Lines` instance can never produce any error, or if an error is produced + /// only once just before terminating the iterator, using `map_while()` is not + /// necessary but will not do any harm. + /// - If the `Lines` instance can produce intermittent errors then recover and produce + /// successful results, using `map_while()` would stop at the first error. + /// + /// ### Example + /// ```rust + /// # use std::{fs::File, io::{self, BufRead, BufReader}}; + /// # let _ = || -> io::Result<()> { + /// let mut lines = BufReader::new(File::open("some-path")?).lines().filter_map(Result::ok); + /// // If "some-path" points to a directory, the next statement never terminates: + /// let first_line: Option = lines.next(); + /// # Ok(()) }; + /// ``` + /// Use instead: + /// ```rust + /// # use std::{fs::File, io::{self, BufRead, BufReader}}; + /// # let _ = || -> io::Result<()> { + /// let mut lines = BufReader::new(File::open("some-path")?).lines().map_while(Result::ok); + /// let first_line: Option = lines.next(); + /// # Ok(()) }; + /// ``` + #[clippy::version = "1.70.0"] + pub LINES_FILTER_MAP_OK, + suspicious, + "filtering `std::io::Lines` with `filter_map()` or `flat_map()` might cause an infinite loop" +} +declare_lint_pass!(LinesFilterMapOk => [LINES_FILTER_MAP_OK]); + +impl LateLintPass<'_> for LinesFilterMapOk { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::MethodCall(fm_method, fm_receiver, [fm_arg], fm_span) = expr.kind && + is_trait_method(cx, expr, sym::Iterator) && + (fm_method.ident.as_str() == "filter_map" || fm_method.ident.as_str() == "flat_map") && + match_type(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), &paths::STD_IO_LINES) + { + let lint = match &fm_arg.kind { + // Detect `Result::ok` + ExprKind::Path(qpath) => + cx.qpath_res(qpath, fm_arg.hir_id).opt_def_id().map(|did| + match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)).unwrap_or_default(), + // Detect `|x| x.ok()` + ExprKind::Closure(Closure { body, .. }) => + if let Body { params: [param], value, .. } = cx.tcx.hir().body(*body) && + let ExprKind::MethodCall(method, receiver, [], _) = value.kind && + path_to_local_id(receiver, param.pat.hir_id) && + let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id) + { + is_diag_item_method(cx, method_did, sym::Result) && method.ident.as_str() == "ok" + } else { + false + } + _ => false, + }; + if lint { + span_lint_and_then(cx, + LINES_FILTER_MAP_OK, + fm_span, + &format!("`{}()` will run forever if the iterator repeatedly produces an `Err`", fm_method.ident), + |diag| { + diag.span_note( + fm_receiver.span, + "this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error"); + diag.span_suggestion(fm_span, "replace with", "map_while(Result::ok)", Applicability::MaybeIncorrect); + }); + } + } + } +} diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index c919575bfe90..9be2d0eae80a 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -23,6 +23,7 @@ pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"]; pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"]; pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"]; pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"]; +pub const CORE_RESULT_OK_METHOD: [&str; 4] = ["core", "result", "Result", "ok"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"]; pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"]; pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"]; @@ -113,6 +114,7 @@ pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"]; pub const CONVERT_IDENTITY: [&str; 3] = ["core", "convert", "identity"]; pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"]; +pub const STD_IO_LINES: [&str; 3] = ["std", "io", "Lines"]; pub const STD_IO_SEEK: [&str; 3] = ["std", "io", "Seek"]; pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"]; pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"]; diff --git a/tests/ui/lines_filter_map_ok.fixed b/tests/ui/lines_filter_map_ok.fixed new file mode 100644 index 000000000000..f4033cd8ed85 --- /dev/null +++ b/tests/ui/lines_filter_map_ok.fixed @@ -0,0 +1,29 @@ +// run-rustfix + +#![allow(unused, clippy::map_identity)] +#![warn(clippy::lines_filter_map_ok)] + +use std::io::{self, BufRead, BufReader}; + +fn main() -> io::Result<()> { + let f = std::fs::File::open("/")?; + // Lint + BufReader::new(f).lines().map_while(Result::ok).for_each(|_| ()); + // Lint + let f = std::fs::File::open("/")?; + BufReader::new(f).lines().map_while(Result::ok).for_each(|_| ()); + let s = "foo\nbar\nbaz\n"; + // Lint + io::stdin().lines().map_while(Result::ok).for_each(|_| ()); + // Lint + io::stdin().lines().map_while(Result::ok).for_each(|_| ()); + // Do not lint (not a `Lines` iterator) + io::stdin() + .lines() + .map(std::convert::identity) + .filter_map(|x| x.ok()) + .for_each(|_| ()); + // Do not lint (not a `Result::ok()` extractor) + io::stdin().lines().filter_map(|x| x.err()).for_each(|_| ()); + Ok(()) +} diff --git a/tests/ui/lines_filter_map_ok.rs b/tests/ui/lines_filter_map_ok.rs new file mode 100644 index 000000000000..7e11816b2acd --- /dev/null +++ b/tests/ui/lines_filter_map_ok.rs @@ -0,0 +1,29 @@ +// run-rustfix + +#![allow(unused, clippy::map_identity)] +#![warn(clippy::lines_filter_map_ok)] + +use std::io::{self, BufRead, BufReader}; + +fn main() -> io::Result<()> { + let f = std::fs::File::open("/")?; + // Lint + BufReader::new(f).lines().filter_map(Result::ok).for_each(|_| ()); + // Lint + let f = std::fs::File::open("/")?; + BufReader::new(f).lines().flat_map(Result::ok).for_each(|_| ()); + let s = "foo\nbar\nbaz\n"; + // Lint + io::stdin().lines().filter_map(Result::ok).for_each(|_| ()); + // Lint + io::stdin().lines().filter_map(|x| x.ok()).for_each(|_| ()); + // Do not lint (not a `Lines` iterator) + io::stdin() + .lines() + .map(std::convert::identity) + .filter_map(|x| x.ok()) + .for_each(|_| ()); + // Do not lint (not a `Result::ok()` extractor) + io::stdin().lines().filter_map(|x| x.err()).for_each(|_| ()); + Ok(()) +} diff --git a/tests/ui/lines_filter_map_ok.stderr b/tests/ui/lines_filter_map_ok.stderr new file mode 100644 index 000000000000..cddd403d589c --- /dev/null +++ b/tests/ui/lines_filter_map_ok.stderr @@ -0,0 +1,51 @@ +error: `filter_map()` will run forever if the iterator repeatedly produces an `Err` + --> $DIR/lines_filter_map_ok.rs:11:31 + | +LL | BufReader::new(f).lines().filter_map(Result::ok).for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)` + | +note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error + --> $DIR/lines_filter_map_ok.rs:11:5 + | +LL | BufReader::new(f).lines().filter_map(Result::ok).for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::lines-filter-map-ok` implied by `-D warnings` + +error: `flat_map()` will run forever if the iterator repeatedly produces an `Err` + --> $DIR/lines_filter_map_ok.rs:14:31 + | +LL | BufReader::new(f).lines().flat_map(Result::ok).for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)` + | +note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error + --> $DIR/lines_filter_map_ok.rs:14:5 + | +LL | BufReader::new(f).lines().flat_map(Result::ok).for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `filter_map()` will run forever if the iterator repeatedly produces an `Err` + --> $DIR/lines_filter_map_ok.rs:17:25 + | +LL | io::stdin().lines().filter_map(Result::ok).for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)` + | +note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error + --> $DIR/lines_filter_map_ok.rs:17:5 + | +LL | io::stdin().lines().filter_map(Result::ok).for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^ + +error: `filter_map()` will run forever if the iterator repeatedly produces an `Err` + --> $DIR/lines_filter_map_ok.rs:19:25 + | +LL | io::stdin().lines().filter_map(|x| x.ok()).for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)` + | +note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error + --> $DIR/lines_filter_map_ok.rs:19:5 + | +LL | io::stdin().lines().filter_map(|x| x.ok()).for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + From 86230dcde6f68e049c0eb67e805d410fe0872422 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Sat, 1 Apr 2023 03:52:58 +0100 Subject: [PATCH 057/272] Bless --- .../macros/macro-path-prelude-fail-4.stderr | 10 ++++++---- .../macro-namespace-reserved-2.stderr | 20 +++++++++++-------- .../tool-attributes-misplaced-2.stderr | 10 ++++++---- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/tests/ui/macros/macro-path-prelude-fail-4.stderr b/tests/ui/macros/macro-path-prelude-fail-4.stderr index cefe655b0f78..0dd67e6726c8 100644 --- a/tests/ui/macros/macro-path-prelude-fail-4.stderr +++ b/tests/ui/macros/macro-path-prelude-fail-4.stderr @@ -2,11 +2,13 @@ error: expected derive macro, found built-in attribute `inline` --> $DIR/macro-path-prelude-fail-4.rs:1:10 | LL | #[derive(inline)] - | ^^^^^^ - | | - | not a derive macro - | help: Remove from the surrounding `derive()` + | ^^^^^^ not a derive macro | +help: Remove from the surrounding `derive()` + --> $DIR/macro-path-prelude-fail-4.rs:1:10 + | +LL | #[derive(inline)] + | ^^^^^^ = help: Add as non-Derive macro `#[inline]` diff --git a/tests/ui/proc-macro/macro-namespace-reserved-2.stderr b/tests/ui/proc-macro/macro-namespace-reserved-2.stderr index 01814a302374..d0f829b50918 100644 --- a/tests/ui/proc-macro/macro-namespace-reserved-2.stderr +++ b/tests/ui/proc-macro/macro-namespace-reserved-2.stderr @@ -56,11 +56,13 @@ error: expected derive macro, found attribute macro `my_macro_attr` --> $DIR/macro-namespace-reserved-2.rs:53:10 | LL | #[derive(my_macro_attr)] - | ^^^^^^^^^^^^^ - | | - | not a derive macro - | help: Remove from the surrounding `derive()` + | ^^^^^^^^^^^^^ not a derive macro | +help: Remove from the surrounding `derive()` + --> $DIR/macro-namespace-reserved-2.rs:53:10 + | +LL | #[derive(my_macro_attr)] + | ^^^^^^^^^^^^^ = help: Add as non-Derive macro `#[my_macro_attr]` @@ -92,11 +94,13 @@ error: expected derive macro, found macro `crate::my_macro` --> $DIR/macro-namespace-reserved-2.rs:50:10 | LL | #[derive(crate::my_macro)] - | ^^^^^^^^^^^^^^^ - | | - | not a derive macro - | help: Remove from the surrounding `derive()` + | ^^^^^^^^^^^^^^^ not a derive macro | +help: Remove from the surrounding `derive()` + --> $DIR/macro-namespace-reserved-2.rs:50:10 + | +LL | #[derive(crate::my_macro)] + | ^^^^^^^^^^^^^^^ = help: Add as non-Derive macro `#[crate::my_macro]` diff --git a/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr b/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr index c1ed2618b2af..b1ecd5289388 100644 --- a/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr +++ b/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr @@ -2,11 +2,13 @@ error: expected derive macro, found tool attribute `rustfmt::skip` --> $DIR/tool-attributes-misplaced-2.rs:1:10 | LL | #[derive(rustfmt::skip)] - | ^^^^^^^^^^^^^ - | | - | not a derive macro - | help: Remove from the surrounding `derive()` + | ^^^^^^^^^^^^^ not a derive macro | +help: Remove from the surrounding `derive()` + --> $DIR/tool-attributes-misplaced-2.rs:1:10 + | +LL | #[derive(rustfmt::skip)] + | ^^^^^^^^^^^^^ = help: Add as non-Derive macro `#[rustfmt::skip]` From b2856a763e2dcb4ffeaf918a7c0d54f6e950cc21 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Fri, 24 Mar 2023 22:39:26 +0100 Subject: [PATCH 058/272] Add `tests_outside_test_module` lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/tests_outside_test_module.rs | 101 ++++++++++++++++++ tests/ui/tests_outside_test_module.rs | 18 ++++ tests/ui/tests_outside_test_module.stderr | 11 ++ 6 files changed, 134 insertions(+) create mode 100644 clippy_lints/src/tests_outside_test_module.rs create mode 100644 tests/ui/tests_outside_test_module.rs create mode 100644 tests/ui/tests_outside_test_module.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 239631777e9a..ba10cb53ec92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4936,6 +4936,7 @@ Released 2018-09-13 [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment [`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr +[`tests_outside_test_module`]: https://rust-lang.github.io/rust-clippy/master/index.html#tests_outside_test_module [`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some [`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display [`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 7836e5ccb9a6..b45105570335 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -577,6 +577,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::swap_ptr_to_ref::SWAP_PTR_TO_REF_INFO, 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::to_digit_is_some::TO_DIGIT_IS_SOME_INFO, crate::trailing_empty_array::TRAILING_EMPTY_ARRAY_INFO, crate::trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ce055f16240b..c63abf0979de 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -291,6 +291,7 @@ mod swap; mod swap_ptr_to_ref; mod tabs_in_doc_comments; mod temporary_assignment; +mod tests_outside_test_module; mod to_digit_is_some; mod trailing_empty_array; mod trait_bounds; @@ -951,6 +952,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); store.register_late_pass(|_| Box::new(lines_filter_map_ok::LinesFilterMapOk)); + store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule::new())); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/tests_outside_test_module.rs b/clippy_lints/src/tests_outside_test_module.rs new file mode 100644 index 000000000000..d14a292a52ff --- /dev/null +++ b/clippy_lints/src/tests_outside_test_module.rs @@ -0,0 +1,101 @@ +use clippy_utils::{diagnostics::span_lint_and_note, is_in_cfg_test, is_in_test_function, is_test_module_or_function}; +use rustc_data_structures::sync::par_for_each_in; +use rustc_hir::{intravisit::FnKind, Body, FnDecl, HirId, ItemKind, Mod}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{def_id::LocalDefId, Span}; + +declare_clippy_lint! { + /// ### What it does + /// + /// Triggers when a testing function (marked with the `#[test]` attribute) isn't inside a testing module (marked with `#[cfg(test)]`). + /// + /// ### Why is this bad? + /// + /// The idiomatic (and more performant) way of writing tests is inside a testing module (flagged with `#[cfg(test)]`), having test functions outside of this module is confusing and may lead to them being "hidden". + /// + /// ### Example + /// ```rust + /// #[test] + /// fn my_cool_test() { + /// // [...] + /// } + /// + /// #[cfg(test)] + /// mod tests { + /// // [...] + /// } + /// + /// ``` + /// Use instead: + /// ```rust + /// #[cfg(test)] + /// mod tests { + /// #[test] + /// fn my_cool_test() { + /// // [...] + /// } + /// } + /// ``` + #[clippy::version = "1.70.0"] + pub TESTS_OUTSIDE_TEST_MODULE, + restriction, + "The test function `my_cool_test` is outside the testing module `tests`." +} + +pub(crate) struct TestsOutsideTestModule { + pub test_mod_exists: bool, +} + +impl TestsOutsideTestModule { + pub fn new() -> Self { + Self { test_mod_exists: false } + } +} + +impl_lint_pass!(TestsOutsideTestModule => [TESTS_OUTSIDE_TEST_MODULE]); + +impl LateLintPass<'_> for TestsOutsideTestModule { + fn check_mod(&mut self, cx: &LateContext<'_>, _: &Mod<'_>, _: HirId) { + self.test_mod_exists = false; + + // par_for_each_item uses Fn, while par_for_each_in uses FnMut + par_for_each_in(cx.tcx.hir_crate_items(()).items(), |itemid| { + let item = cx.tcx.hir().item(itemid); + if_chain! { + if matches!(item.kind, ItemKind::Mod(_)); + if is_test_module_or_function(cx.tcx, item); + then { + self.test_mod_exists = true; + } + } + }); + } + + fn check_fn( + &mut self, + cx: &LateContext<'_>, + kind: FnKind<'_>, + _: &FnDecl<'_>, + body: &Body<'_>, + sp: Span, + _: LocalDefId, + ) { + if_chain! { + if !matches!(kind, FnKind::Closure); + if self.test_mod_exists; + if is_in_test_function(cx.tcx, body.id().hir_id); + if !is_in_cfg_test(cx.tcx, body.id().hir_id); + then { + span_lint_and_note( + cx, + TESTS_OUTSIDE_TEST_MODULE, + sp, + "this function marked with #[test] is outside a #[cfg(test)] module", + None, + "move it to a testing module marked with #[cfg(test)]", + ); + } + } + } +} diff --git a/tests/ui/tests_outside_test_module.rs b/tests/ui/tests_outside_test_module.rs new file mode 100644 index 000000000000..1982b1d0107f --- /dev/null +++ b/tests/ui/tests_outside_test_module.rs @@ -0,0 +1,18 @@ +// compile-flags: --test +#![allow(unused)] +#![warn(clippy::tests_outside_test_module)] + +fn main() { + // test code goes here +} + +// Should lint +#[test] +fn my_test() {} + +#[cfg(test)] +mod tests { + // Should not lint + #[test] + fn my_test() {} +} diff --git a/tests/ui/tests_outside_test_module.stderr b/tests/ui/tests_outside_test_module.stderr new file mode 100644 index 000000000000..125a79d6edfe --- /dev/null +++ b/tests/ui/tests_outside_test_module.stderr @@ -0,0 +1,11 @@ +error: this function marked with #[test] is outside a #[cfg(test)] module + --> $DIR/tests_outside_test_module.rs:11:1 + | +LL | fn my_test() {} + | ^^^^^^^^^^^^^^^ + | + = note: move it to a testing module marked with #[cfg(test)] + = note: `-D clippy::tests-outside-test-module` implied by `-D warnings` + +error: aborting due to previous error + From bbfbecd59ff99b51d1ccf7764641ef32209b9dad Mon Sep 17 00:00:00 2001 From: Mu42 Date: Sun, 2 Apr 2023 10:48:01 +0800 Subject: [PATCH 059/272] Do not repeat idx --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 11 ++-- tests/ui/argument-suggestions/109831.rs | 9 ++++ tests/ui/argument-suggestions/109831.stderr | 51 +++++++++++++++++++ 3 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 tests/ui/argument-suggestions/109831.rs create mode 100644 tests/ui/argument-suggestions/109831.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 61338ac613ae..32c603e48974 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1156,14 +1156,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // ``` // which includes the replacement of the first two `()` for the correct type, and the // removal of the last `()`. - let mut prev = -1; + let mut idx = -1; for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() { // We want to point not at the *current* argument expression index, but rather at the // index position where it *should have been*, which is *after* the previous one. - if let Some(provided_idx) = provided_idx { - prev = provided_idx.index() as i64; - } - let idx = ProvidedIdx::from_usize((prev + 1) as usize); + idx = match provided_idx { + Some(provided_idx) => provided_idx.index() as i64 + 1, + None => idx + 1, + }; + let idx = ProvidedIdx::from_usize(idx as usize); if let None = provided_idx && let Some((_, arg_span)) = provided_arg_tys.get(idx) { diff --git a/tests/ui/argument-suggestions/109831.rs b/tests/ui/argument-suggestions/109831.rs new file mode 100644 index 000000000000..2e8ae40f6305 --- /dev/null +++ b/tests/ui/argument-suggestions/109831.rs @@ -0,0 +1,9 @@ +struct A; +struct B; + +fn f(b1: B, b2: B, a2: C) {} //~ ERROR E0412 + +fn main() { + f(A, A, B, C); //~ ERROR E0425 + //~^ ERROR E0061 +} diff --git a/tests/ui/argument-suggestions/109831.stderr b/tests/ui/argument-suggestions/109831.stderr new file mode 100644 index 000000000000..861f6d67baf2 --- /dev/null +++ b/tests/ui/argument-suggestions/109831.stderr @@ -0,0 +1,51 @@ +error[E0412]: cannot find type `C` in this scope + --> $DIR/109831.rs:4:24 + | +LL | struct A; + | --------- similarly named struct `A` defined here +... +LL | fn f(b1: B, b2: B, a2: C) {} + | ^ + | +help: a struct with a similar name exists + | +LL | fn f(b1: B, b2: B, a2: A) {} + | ~ +help: you might be missing a type parameter + | +LL | fn f(b1: B, b2: B, a2: C) {} + | +++ + +error[E0425]: cannot find value `C` in this scope + --> $DIR/109831.rs:7:16 + | +LL | struct A; + | --------- similarly named unit struct `A` defined here +... +LL | f(A, A, B, C); + | ^ help: a unit struct with a similar name exists: `A` + +error[E0061]: this function takes 3 arguments but 4 arguments were supplied + --> $DIR/109831.rs:7:5 + | +LL | f(A, A, B, C); + | ^ - - - unexpected argument + | | | + | | expected `B`, found `A` + | expected `B`, found `A` + | +note: function defined here + --> $DIR/109831.rs:4:4 + | +LL | fn f(b1: B, b2: B, a2: C) {} + | ^ ----- ----- ----- +help: remove the extra argument + | +LL - f(A, A, B, C); +LL + f(/* B */, /* B */, B); + | + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0061, E0412, E0425. +For more information about an error, try `rustc --explain E0061`. From 80e428553144d441893fc07ea2b88081d93806fe Mon Sep 17 00:00:00 2001 From: Mu42 Date: Sun, 2 Apr 2023 11:41:50 +0800 Subject: [PATCH 060/272] Make each idx is used once --- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 17 ++++++++--------- .../{109831.rs => issue-109831.rs} | 0 .../{109831.stderr => issue-109831.stderr} | 8 ++++---- 3 files changed, 12 insertions(+), 13 deletions(-) rename tests/ui/argument-suggestions/{109831.rs => issue-109831.rs} (100%) rename tests/ui/argument-suggestions/{109831.stderr => issue-109831.stderr} (90%) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 32c603e48974..6bcc2bae98a7 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1156,18 +1156,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // ``` // which includes the replacement of the first two `()` for the correct type, and the // removal of the last `()`. - let mut idx = -1; + let mut prev = -1; for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() { // We want to point not at the *current* argument expression index, but rather at the // index position where it *should have been*, which is *after* the previous one. - idx = match provided_idx { - Some(provided_idx) => provided_idx.index() as i64 + 1, - None => idx + 1, - }; - let idx = ProvidedIdx::from_usize(idx as usize); - if let None = provided_idx - && let Some((_, arg_span)) = provided_arg_tys.get(idx) - { + if let Some(provided_idx) = provided_idx { + prev = provided_idx.index() as i64; + continue; + } + let idx = ProvidedIdx::from_usize((prev + 1) as usize); + if let Some((_, arg_span)) = provided_arg_tys.get(idx) { + prev += 1; // There is a type that was *not* found anywhere, so it isn't a move, but a // replacement and we look at what type it should have been. This will allow us // To suggest a multipart suggestion when encountering `foo(1, "")` where the def diff --git a/tests/ui/argument-suggestions/109831.rs b/tests/ui/argument-suggestions/issue-109831.rs similarity index 100% rename from tests/ui/argument-suggestions/109831.rs rename to tests/ui/argument-suggestions/issue-109831.rs diff --git a/tests/ui/argument-suggestions/109831.stderr b/tests/ui/argument-suggestions/issue-109831.stderr similarity index 90% rename from tests/ui/argument-suggestions/109831.stderr rename to tests/ui/argument-suggestions/issue-109831.stderr index 861f6d67baf2..7b9a3c9ef2c6 100644 --- a/tests/ui/argument-suggestions/109831.stderr +++ b/tests/ui/argument-suggestions/issue-109831.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `C` in this scope - --> $DIR/109831.rs:4:24 + --> $DIR/issue-109831.rs:4:24 | LL | struct A; | --------- similarly named struct `A` defined here @@ -17,7 +17,7 @@ LL | fn f(b1: B, b2: B, a2: C) {} | +++ error[E0425]: cannot find value `C` in this scope - --> $DIR/109831.rs:7:16 + --> $DIR/issue-109831.rs:7:16 | LL | struct A; | --------- similarly named unit struct `A` defined here @@ -26,7 +26,7 @@ LL | f(A, A, B, C); | ^ help: a unit struct with a similar name exists: `A` error[E0061]: this function takes 3 arguments but 4 arguments were supplied - --> $DIR/109831.rs:7:5 + --> $DIR/issue-109831.rs:7:5 | LL | f(A, A, B, C); | ^ - - - unexpected argument @@ -35,7 +35,7 @@ LL | f(A, A, B, C); | expected `B`, found `A` | note: function defined here - --> $DIR/109831.rs:4:4 + --> $DIR/issue-109831.rs:4:4 | LL | fn f(b1: B, b2: B, a2: C) {} | ^ ----- ----- ----- From 05650b7215bfda4c03cab8acc16b83e67139d7de Mon Sep 17 00:00:00 2001 From: Caio Date: Sun, 2 Apr 2023 07:50:25 -0300 Subject: [PATCH 061/272] [arithmetic_side_effects] Fix #10583 --- .../src/operators/arithmetic_side_effects.rs | 12 ++++++++++-- tests/ui/arithmetic_side_effects.rs | 4 ++++ tests/ui/arithmetic_side_effects.stderr | 14 +++++++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index 25e8de948637..e5713735672d 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -154,10 +154,18 @@ impl ArithmeticSideEffects { Self::literal_integer(cx, actual_rhs), ) { (None, None) => false, - (None, Some(n)) | (Some(n), None) => match (&op.node, n) { + (None, Some(n)) => match (&op.node, n) { // Division and module are always valid if applied to non-zero integers (hir::BinOpKind::Div | hir::BinOpKind::Rem, local_n) if local_n != 0 => true, - // Addition or subtracting zeros is always a no-op + // Adding or subtracting zeros is always a no-op + (hir::BinOpKind::Add | hir::BinOpKind::Sub, 0) + // Multiplication by 1 or 0 will never overflow + | (hir::BinOpKind::Mul, 0 | 1) + => true, + _ => false, + }, + (Some(n), None) => match (&op.node, n) { + // Adding or subtracting zeros is always a no-op (hir::BinOpKind::Add | hir::BinOpKind::Sub, 0) // Multiplication by 1 or 0 will never overflow | (hir::BinOpKind::Mul, 0 | 1) diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs index ee7d2ba444b2..3c06676d7228 100644 --- a/tests/ui/arithmetic_side_effects.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -425,4 +425,8 @@ pub fn integer_arithmetic() { i ^= i; } +pub fn issue_10583(a: u16) -> u16 { + 10 / a +} + fn main() {} diff --git a/tests/ui/arithmetic_side_effects.stderr b/tests/ui/arithmetic_side_effects.stderr index 3895f08964ce..2c8ee2884e73 100644 --- a/tests/ui/arithmetic_side_effects.stderr +++ b/tests/ui/arithmetic_side_effects.stderr @@ -576,6 +576,12 @@ error: arithmetic operation that can potentially result in unexpected side-effec LL | i * 2; | ^^^^^ +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:394:5 + | +LL | 1 % i / 2; + | ^^^^^ + error: arithmetic operation that can potentially result in unexpected side-effects --> $DIR/arithmetic_side_effects.rs:395:5 | @@ -642,5 +648,11 @@ error: arithmetic operation that can potentially result in unexpected side-effec LL | i %= var2; | ^^^^^^^^^ -error: aborting due to 107 previous errors +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:429:5 + | +LL | 10 / a + | ^^^^^^ + +error: aborting due to 109 previous errors From 36047b0216b9fb4741e8927c7e6b644727e02fdf Mon Sep 17 00:00:00 2001 From: blyxyas Date: Sun, 2 Apr 2023 16:18:03 +0200 Subject: [PATCH 062/272] Fix `nonminimal_bool` `#[allow]` attributes. --- clippy_lints/src/booleans.rs | 39 +++++++++++++++++++----------------- tests/ui/nonminimal_bool.rs | 18 +++++++++++++++++ 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 29fde9336c0b..455f0df7cd0a 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -7,7 +7,7 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, Level}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; @@ -430,23 +430,25 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { } } let nonminimal_bool_lint = |suggestions: Vec<_>| { - span_lint_hir_and_then( - self.cx, - NONMINIMAL_BOOL, - e.hir_id, - e.span, - "this boolean expression can be simplified", - |diag| { - diag.span_suggestions( - e.span, - "try", - suggestions.into_iter(), - // nonminimal_bool can produce minimal but - // not human readable expressions (#3141) - Applicability::Unspecified, - ); - }, - ); + if self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, e.hir_id).0 != Level::Allow { + span_lint_hir_and_then( + self.cx, + NONMINIMAL_BOOL, + e.hir_id, + e.span, + "this boolean expression can be simplified", + |diag| { + diag.span_suggestions( + e.span, + "try", + suggestions.into_iter(), + // nonminimal_bool can produce minimal but + // not human readable expressions (#3141) + Applicability::Unspecified, + ); + }, + ); + } }; if improvements.is_empty() { let mut visitor = NotSimplificationVisitor { cx: self.cx }; @@ -498,6 +500,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> { if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind && !inner.span.from_expansion() && let Some(suggestion) = simplify_not(self.cx, inner) + && self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow { span_lint_and_sugg( self.cx, diff --git a/tests/ui/nonminimal_bool.rs b/tests/ui/nonminimal_bool.rs index 3b5a374b4a7b..80cc7c60f56e 100644 --- a/tests/ui/nonminimal_bool.rs +++ b/tests/ui/nonminimal_bool.rs @@ -92,3 +92,21 @@ fn issue_10523_2() { } if a!() {} } + +fn issue_10435() { + let x = vec![0]; + let y = vec![1]; + let z = vec![2]; + + // vvv Should not lint + #[allow(clippy::nonminimal_bool)] + if !x.is_empty() && !(y.is_empty() || z.is_empty()) { + println!("{}", line!()); + } + + // vvv Should not lint (#10435 talks about a bug where it lints) + #[allow(clippy::nonminimal_bool)] + if !(x == [0]) { + println!("{}", line!()); + } +} From 48be303272e8eb620665b73a7bd87cdb6508f6f1 Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Sun, 2 Apr 2023 07:30:42 -0700 Subject: [PATCH 063/272] Add riscv relax target feature --- compiler/rustc_codegen_ssa/src/target_features.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 754b085f1a83..611dd3d1cd18 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -251,6 +251,7 @@ const RISCV_ALLOWED_FEATURES: &[(&str, Option)] = &[ ("e", Some(sym::riscv_target_feature)), ("f", Some(sym::riscv_target_feature)), ("m", Some(sym::riscv_target_feature)), + ("relax", Some(sym::riscv_target_feature)), ("v", Some(sym::riscv_target_feature)), ("zba", Some(sym::riscv_target_feature)), ("zbb", Some(sym::riscv_target_feature)), From 56207b8fafac6f6697751084f0914e1dbc0381ce Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Sun, 2 Apr 2023 19:01:52 +0100 Subject: [PATCH 064/272] Skip help messages if macro span is from macro --- compiler/rustc_resolve/src/macros.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 39e30767da27..b595dc068018 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -548,10 +548,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { err.span_label(path.span, format!("not {} {}", article, expected)); - if kind == MacroKind::Derive && ext.macro_kind() != MacroKind::Derive { + if !path.span.from_expansion() { // Suggest moving the macro out of the derive() as the macro isn't Derive - err.span_help(path.span, "Remove from the surrounding `derive()`"); - err.help(format!("Add as non-Derive macro\n`#[{}]`", path_str)); + if kind == MacroKind::Derive && ext.macro_kind() != MacroKind::Derive { + err.span_help(path.span, "Remove from the surrounding `derive()`"); + err.help(format!("Add as non-Derive macro\n`#[{}]`", path_str)); + } } err.emit(); From e2742a0ea24b4c596514021d0c94ff5a78ff0757 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Mon, 3 Apr 2023 01:27:53 +0200 Subject: [PATCH 065/272] Fix `double_must_use` for async functions --- clippy_lints/src/functions/must_use.rs | 7 ++++--- tests/ui/double_must_use.rs | 6 ++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 1e9e826631c3..56acd31b1d2d 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -23,7 +23,8 @@ use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT}; pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { let attrs = cx.tcx.hir().attrs(item.hir_id()); let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); - if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind { + if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind && !sig.header.is_async() /* (#10486) */ { + let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if let Some(attr) = attr { @@ -43,7 +44,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_> } pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { - if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind { + if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind && !sig.header.is_async() /* (#10486) */ { let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir().attrs(item.hir_id()); @@ -65,7 +66,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp } pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { - if let hir::TraitItemKind::Fn(ref sig, ref eid) = item.kind { + if let hir::TraitItemKind::Fn(ref sig, ref eid) = item.kind && !sig.header.is_async() /* (#10486) */ { let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); diff --git a/tests/ui/double_must_use.rs b/tests/ui/double_must_use.rs index 05e087b08bc1..a4cd8630de59 100644 --- a/tests/ui/double_must_use.rs +++ b/tests/ui/double_must_use.rs @@ -21,6 +21,12 @@ pub fn must_use_with_note() -> Result<(), ()> { unimplemented!(); } +// vvvv Should not lint (#10486) +#[must_use] +async fn async_must_use() -> usize { + unimplemented!(); +} + fn main() { must_use_result(); must_use_tuple(); From d60274355894c0e0768b034ab538aa0625fc2a91 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Mon, 3 Apr 2023 15:15:43 +0200 Subject: [PATCH 066/272] only focus on `double_must_use` + Add `Result<(), ()>` test --- clippy_lints/src/functions/must_use.rs | 17 +++++++++-------- tests/ui/double_must_use.rs | 5 +++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 56acd31b1d2d..ab68d7a3726f 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -1,3 +1,4 @@ +use hir::FnSig; use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir::def_id::DefIdSet; @@ -23,12 +24,11 @@ use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT}; pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { let attrs = cx.tcx.hir().attrs(item.hir_id()); let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); - if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind && !sig.header.is_async() /* (#10486) */ { - + if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind { let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if let Some(attr) = attr { - check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); + check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, sig); } else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { check_must_use_candidate( cx, @@ -44,13 +44,13 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_> } pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { - if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind && !sig.header.is_async() /* (#10486) */ { + if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind { let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir().attrs(item.hir_id()); let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let Some(attr) = attr { - check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); + check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, sig); } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none() { check_must_use_candidate( cx, @@ -66,14 +66,14 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp } pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { - if let hir::TraitItemKind::Fn(ref sig, ref eid) = item.kind && !sig.header.is_async() /* (#10486) */ { + if let hir::TraitItemKind::Fn(ref sig, ref eid) = item.kind { let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir().attrs(item.hir_id()); let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let Some(attr) = attr { - check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); + check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, sig); } else if let hir::TraitFn::Provided(eid) = *eid { let body = cx.tcx.hir().body(eid); if attr.is_none() && is_public && !is_proc_macro(attrs) { @@ -98,6 +98,7 @@ fn check_needless_must_use( item_span: Span, fn_header_span: Span, attr: &Attribute, + sig: &FnSig<'_>, ) { if in_external_macro(cx.sess(), item_span) { return; @@ -112,7 +113,7 @@ fn check_needless_must_use( diag.span_suggestion(attr.span, "remove the attribute", "", Applicability::MachineApplicable); }, ); - } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) { + } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) && !sig.header.is_async() { span_lint_and_help( cx, DOUBLE_MUST_USE, diff --git a/tests/ui/double_must_use.rs b/tests/ui/double_must_use.rs index a4cd8630de59..26a387b3cf04 100644 --- a/tests/ui/double_must_use.rs +++ b/tests/ui/double_must_use.rs @@ -27,6 +27,11 @@ async fn async_must_use() -> usize { unimplemented!(); } +#[must_use] +async fn async_must_use_result() -> Result<(), ()> { + Ok(()) +} + fn main() { must_use_result(); must_use_tuple(); From afdfbf8fdea085f62ec64537135170a748c991d4 Mon Sep 17 00:00:00 2001 From: bhould287 Date: Sat, 1 Apr 2023 21:30:39 +0100 Subject: [PATCH 067/272] Show multiple clippy.toml warnings with `sess.warn` instead of `eprintln!` --- clippy_lints/src/lib.rs | 14 +++++++++----- clippy_lints/src/utils/conf.rs | 19 ++++++++++--------- src/driver.rs | 2 +- .../warn/src/main.stderr | 6 ++++-- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ce055f16240b..51e21765953c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -348,13 +348,17 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Se } #[doc(hidden)] -pub fn read_conf(sess: &Session, path: &io::Result>) -> Conf { +pub fn read_conf(sess: &Session, path: &io::Result<(Option, Vec)>) -> Conf { + if let Ok((_, warnings)) = path { + for warning in warnings { + sess.warn(warning); + } + } let file_name = match path { - Ok(Some(path)) => path, - Ok(None) => return Conf::default(), + Ok((Some(path), _)) => path, + Ok((None, _)) => return Conf::default(), Err(error) => { - sess.struct_err(format!("error finding Clippy's configuration file: {error}")) - .emit(); + sess.err(format!("error finding Clippy's configuration file: {error}")); return Conf::default(); }, }; diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index f75a5cf7196a..25626897b510 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -470,7 +470,7 @@ define_Conf! { /// # Errors /// /// Returns any unexpected filesystem error encountered when searching for the config file -pub fn lookup_conf_file() -> io::Result> { +pub fn lookup_conf_file() -> io::Result<(Option, Vec)> { /// Possible filename to search for. const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"]; @@ -481,6 +481,7 @@ pub fn lookup_conf_file() -> io::Result> { .map_or_else(|| PathBuf::from("."), PathBuf::from); let mut found_config: Option = None; + let mut warnings = vec![]; loop { for config_file_name in &CONFIG_FILE_NAMES { @@ -491,12 +492,12 @@ pub fn lookup_conf_file() -> io::Result> { Ok(md) if md.is_dir() => {}, Ok(_) => { // warn if we happen to find two config files #8323 - if let Some(ref found_config_) = found_config { - eprintln!( - "Using config file `{}`\nWarning: `{}` will be ignored.", - found_config_.display(), - config_file.display(), - ); + if let Some(ref found_config) = found_config { + warnings.push(format!( + "using config file `{}`, `{}` will be ignored", + found_config.display(), + config_file.display() + )); } else { found_config = Some(config_file); } @@ -506,12 +507,12 @@ pub fn lookup_conf_file() -> io::Result> { } if found_config.is_some() { - return Ok(found_config); + return Ok((found_config, warnings)); } // If the current directory has no parent, we're done searching. if !current.pop() { - return Ok(None); + return Ok((None, warnings)); } } } diff --git a/src/driver.rs b/src/driver.rs index f08393c303ef..39f2bf9aa199 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -130,7 +130,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { #[allow(rustc::bad_opt_access)] fn config(&mut self, config: &mut interface::Config) { let conf_path = clippy_lints::lookup_conf_file(); - let conf_path_string = if let Ok(Some(path)) = &conf_path { + let conf_path_string = if let Ok((Some(path), _)) = &conf_path { path.to_str().map(String::from) } else { None diff --git a/tests/ui-cargo/multiple_config_files/warn/src/main.stderr b/tests/ui-cargo/multiple_config_files/warn/src/main.stderr index 98697e001f99..aa1b3c638a03 100644 --- a/tests/ui-cargo/multiple_config_files/warn/src/main.stderr +++ b/tests/ui-cargo/multiple_config_files/warn/src/main.stderr @@ -1,2 +1,4 @@ -Using config file `$SRC_DIR/.clippy.toml` -Warning: `$SRC_DIR/clippy.toml` will be ignored. +warning: using config file `$SRC_DIR/.clippy.toml`, `$SRC_DIR/clippy.toml` will be ignored + +warning: 1 warning emitted + From a37eb4dfc97cdcbd177ccc0fda1909014b145635 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Mon, 3 Apr 2023 16:01:30 +0200 Subject: [PATCH 068/272] Fix false negative on `Result<(), ()>` --- clippy_lints/src/functions/must_use.rs | 12 +++++++++++- tests/ui/double_must_use.stderr | 10 +++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index ab68d7a3726f..d0ad26282642 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -3,6 +3,7 @@ use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir::def_id::DefIdSet; use rustc_hir::{self as hir, def::Res, QPath}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LintContext}; use rustc_middle::{ lint::in_external_macro, @@ -113,7 +114,16 @@ fn check_needless_must_use( diag.span_suggestion(attr.span, "remove the attribute", "", Applicability::MachineApplicable); }, ); - } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) && !sig.header.is_async() { + } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) { + // Ignore async functions unless Future::Output type is a must_use type + if sig.header.is_async() { + let infcx = cx.tcx.infer_ctxt().build(); + if let Some(future_ty) = infcx.get_impl_future_output_ty(return_ty(cx, item_id)) + && !is_must_use_ty(cx, future_ty) { + return; + } + } + span_lint_and_help( cx, DOUBLE_MUST_USE, diff --git a/tests/ui/double_must_use.stderr b/tests/ui/double_must_use.stderr index 3d34557a881b..49ab2ea3e12b 100644 --- a/tests/ui/double_must_use.stderr +++ b/tests/ui/double_must_use.stderr @@ -23,5 +23,13 @@ LL | pub fn must_use_array() -> [Result<(), ()>; 1] { | = help: either add some descriptive text or remove the attribute -error: aborting due to 3 previous errors +error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]` + --> $DIR/double_must_use.rs:31:1 + | +LL | async fn async_must_use_result() -> Result<(), ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: either add some descriptive text or remove the attribute + +error: aborting due to 4 previous errors From 9f1a3a131b3a32ac86f5d230357fff94b17c34cb Mon Sep 17 00:00:00 2001 From: fleetingbytes <7075397+fleetingbytes@users.noreply.github.com> Date: Mon, 3 Apr 2023 16:09:15 +0200 Subject: [PATCH 069/272] Update env.rs Remove `Errors` section from `var_os` documentation --- library/std/src/env.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 183f9ab3b08f..3fcf96c761bf 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -242,16 +242,6 @@ fn _var(key: &OsStr) -> Result { /// is valid Unicode. If you want to have an error on invalid UTF-8, /// use the [`var`] function instead. /// -/// # Errors -/// -/// This function returns an error if the environment variable isn't set. -/// -/// This function may return an error if the environment variable's name contains -/// the equal sign character (`=`) or the NUL character. -/// -/// This function may return an error if the environment variable's value contains -/// the NUL character. -/// /// # Examples /// /// ``` From c252f0d4044876509e08be27f82dbf0f33bc5cc2 Mon Sep 17 00:00:00 2001 From: fleetingbytes <7075397+fleetingbytes@users.noreply.github.com> Date: Mon, 3 Apr 2023 16:46:43 +0200 Subject: [PATCH 070/272] add situation where var_os returns None Re-introduced some of the former errors as situations where `None` is returned. --- library/std/src/env.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 3fcf96c761bf..63338bd5876b 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -236,7 +236,13 @@ fn _var(key: &OsStr) -> Result { } /// Fetches the environment variable `key` from the current process, returning -/// [`None`] if the variable isn't set or there's another error. +/// [`None`] in the following situations: +/// +/// - the environment variable isn't set +/// - the environment variable's name contains +/// the equal sign character (`=`) or the NUL character +/// +/// If this is not desired, consider using [`var_os`]. /// /// Note that the method will not check if the environment variable /// is valid Unicode. If you want to have an error on invalid UTF-8, From 73f40d429317e7c9c87de0cf828d02b0442a25da Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 3 Apr 2023 16:37:42 +0200 Subject: [PATCH 071/272] Add codegen tests for issues fixed by LLVM 16 Fixes #75978. Fixes #99960. Fixes #101048. Fixes #101082. Fixes #101814. Fixes #103132. Fixes #103327. --- tests/codegen/issues/issue-101048.rs | 13 +++++++++++++ tests/codegen/issues/issue-101082.rs | 16 ++++++++++++++++ tests/codegen/issues/issue-101814.rs | 19 +++++++++++++++++++ tests/codegen/issues/issue-103132.rs | 16 ++++++++++++++++ tests/codegen/issues/issue-103327.rs | 18 ++++++++++++++++++ tests/codegen/issues/issue-75978.rs | 19 +++++++++++++++++++ tests/codegen/issues/issue-99960.rs | 15 +++++++++++++++ 7 files changed, 116 insertions(+) create mode 100644 tests/codegen/issues/issue-101048.rs create mode 100644 tests/codegen/issues/issue-101082.rs create mode 100644 tests/codegen/issues/issue-101814.rs create mode 100644 tests/codegen/issues/issue-103132.rs create mode 100644 tests/codegen/issues/issue-103327.rs create mode 100644 tests/codegen/issues/issue-75978.rs create mode 100644 tests/codegen/issues/issue-99960.rs diff --git a/tests/codegen/issues/issue-101048.rs b/tests/codegen/issues/issue-101048.rs new file mode 100644 index 000000000000..efa4db93ec21 --- /dev/null +++ b/tests/codegen/issues/issue-101048.rs @@ -0,0 +1,13 @@ +// compile-flags: -O +// min-llvm-version: 16 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn all_zero(data: &[u64]) -> bool { + // CHECK-LABEL: @all_zero( + // CHECK: [[PHI:%.*]] = phi i1 + // CHECK-NOT: phi i8 + // CHECK-NOT: zext + data.iter().copied().fold(true, |acc, x| acc & (x == 0)) +} diff --git a/tests/codegen/issues/issue-101082.rs b/tests/codegen/issues/issue-101082.rs new file mode 100644 index 000000000000..effe8f4a60e3 --- /dev/null +++ b/tests/codegen/issues/issue-101082.rs @@ -0,0 +1,16 @@ +// compile-flags: -O +// min-llvm-version: 16 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test() -> usize { + // CHECK-LABEL: @test( + // CHECK: ret i64 165 + let values = [23, 16, 54, 3, 60, 9]; + let mut acc = 0; + for item in values { + acc += item; + } + acc +} diff --git a/tests/codegen/issues/issue-101814.rs b/tests/codegen/issues/issue-101814.rs new file mode 100644 index 000000000000..4e4745ed633d --- /dev/null +++ b/tests/codegen/issues/issue-101814.rs @@ -0,0 +1,19 @@ +// compile-flags: -O +// min-llvm-version: 16 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test(a: [i32; 10]) -> i32 { + // CHECK-LABEL: @test( + // CHECK: [[L1:%.+]] = load i32 + // CHECK: [[L2:%.+]] = load i32 + // CHECK: [[R:%.+]] = add i32 [[L1]], [[L2]] + // CHECK: ret i32 [[R]] + let mut sum = 0; + for v in a.iter().skip(8) { + sum += v; + } + + sum +} diff --git a/tests/codegen/issues/issue-103132.rs b/tests/codegen/issues/issue-103132.rs new file mode 100644 index 000000000000..cc87d7cd2b9d --- /dev/null +++ b/tests/codegen/issues/issue-103132.rs @@ -0,0 +1,16 @@ +// compile-flags: -O -C overflow-checks +// min-llvm-version: 16 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test(arr: &[u8], weight: u32) { + // CHECK-LABEL: @test( + // CHECK-NOT: panic + let weight = weight.min(256 * 256 * 256); + + for x in arr { + assert!(weight <= 256 * 256 * 256); + let result = *x as u32 * weight; + } +} diff --git a/tests/codegen/issues/issue-103327.rs b/tests/codegen/issues/issue-103327.rs new file mode 100644 index 000000000000..cee00faccc81 --- /dev/null +++ b/tests/codegen/issues/issue-103327.rs @@ -0,0 +1,18 @@ +// compile-flags: -O +// min-llvm-version: 16 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test(a: i32, b: i32) -> bool { + // CHECK-LABEL: @test( + // CHECK: ret i1 true + let c1 = (a >= 0) && (a <= 10); + let c2 = (b >= 0) && (b <= 20); + + if c1 & c2 { + a + 100 != b + } else { + true + } +} diff --git a/tests/codegen/issues/issue-75978.rs b/tests/codegen/issues/issue-75978.rs new file mode 100644 index 000000000000..f335e92c3dc4 --- /dev/null +++ b/tests/codegen/issues/issue-75978.rs @@ -0,0 +1,19 @@ +// compile-flags: -O +// min-llvm-version: 16 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test() -> u32 { + // CHECK-LABEL: @test( + // CHECK: ret i32 13 + let s = [1, 2, 3, 4, 5, 6, 7]; + + let mut iter = s.iter(); + let mut sum = 0; + while let Some(_) = iter.next() { + sum += iter.next().map_or(1, |&x| x) + } + + sum +} diff --git a/tests/codegen/issues/issue-99960.rs b/tests/codegen/issues/issue-99960.rs new file mode 100644 index 000000000000..e9c9367fa64b --- /dev/null +++ b/tests/codegen/issues/issue-99960.rs @@ -0,0 +1,15 @@ +// compile-flags: -O +// min-llvm-version: 16 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test(dividend: i64, divisor: i64) -> Option { + // CHECK-LABEL: @test( + // CHECK-NOT: panic + if dividend > i64::min_value() && divisor != 0 { + Some(dividend / divisor) + } else { + None + } +} From 5618c8efd7925b6f1b5d8e5b30228f065606e841 Mon Sep 17 00:00:00 2001 From: fleetingbytes <7075397+fleetingbytes@users.noreply.github.com> Date: Mon, 3 Apr 2023 17:13:30 +0200 Subject: [PATCH 072/272] remove self-reference in var_os doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: León Orell Valerian Liehr --- library/std/src/env.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 63338bd5876b..c9f8e617df60 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -242,7 +242,6 @@ fn _var(key: &OsStr) -> Result { /// - the environment variable's name contains /// the equal sign character (`=`) or the NUL character /// -/// If this is not desired, consider using [`var_os`]. /// /// Note that the method will not check if the environment variable /// is valid Unicode. If you want to have an error on invalid UTF-8, From 3b22352d0d16034e112e58b032f1bf0fc1c818ba Mon Sep 17 00:00:00 2001 From: bhould287 Date: Sat, 1 Apr 2023 21:29:05 +0100 Subject: [PATCH 073/272] Fix bug with getting parent directories in `lookup_conf_file` --- clippy_lints/src/utils/conf.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 25626897b510..896a01af37d9 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -478,7 +478,8 @@ pub fn lookup_conf_file() -> io::Result<(Option, Vec)> { // If neither of those exist, use ".". let mut current = env::var_os("CLIPPY_CONF_DIR") .or_else(|| env::var_os("CARGO_MANIFEST_DIR")) - .map_or_else(|| PathBuf::from("."), PathBuf::from); + .map_or_else(|| PathBuf::from("."), PathBuf::from) + .canonicalize()?; let mut found_config: Option = None; let mut warnings = vec![]; From a450557a54b871ce182900cde3894a3494876e1e Mon Sep 17 00:00:00 2001 From: fleetingbytes <7075397+fleetingbytes@users.noreply.github.com> Date: Mon, 3 Apr 2023 17:17:43 +0200 Subject: [PATCH 074/272] Remove redundant empty line one is enough --- library/std/src/env.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index c9f8e617df60..1345469d8b32 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -242,7 +242,6 @@ fn _var(key: &OsStr) -> Result { /// - the environment variable's name contains /// the equal sign character (`=`) or the NUL character /// -/// /// Note that the method will not check if the environment variable /// is valid Unicode. If you want to have an error on invalid UTF-8, /// use the [`var`] function instead. From bd2a5b2322729137b26b899947e777c41c9aae96 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Mon, 3 Apr 2023 18:42:00 +0200 Subject: [PATCH 075/272] Remove check for `#[cfg(test)]` --- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/tests_outside_test_module.rs | 36 +++---------------- 2 files changed, 5 insertions(+), 33 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c63abf0979de..c16d66215189 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -952,7 +952,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); store.register_late_pass(|_| Box::new(lines_filter_map_ok::LinesFilterMapOk)); - store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule::new())); + store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/tests_outside_test_module.rs b/clippy_lints/src/tests_outside_test_module.rs index d14a292a52ff..e454008c68d9 100644 --- a/clippy_lints/src/tests_outside_test_module.rs +++ b/clippy_lints/src/tests_outside_test_module.rs @@ -1,8 +1,7 @@ -use clippy_utils::{diagnostics::span_lint_and_note, is_in_cfg_test, is_in_test_function, is_test_module_or_function}; -use rustc_data_structures::sync::par_for_each_in; -use rustc_hir::{intravisit::FnKind, Body, FnDecl, HirId, ItemKind, Mod}; +use clippy_utils::{diagnostics::span_lint_and_note, is_in_cfg_test, is_in_test_function}; +use rustc_hir::{intravisit::FnKind, Body, FnDecl}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{def_id::LocalDefId, Span}; declare_clippy_lint! { @@ -43,35 +42,9 @@ declare_clippy_lint! { "The test function `my_cool_test` is outside the testing module `tests`." } -pub(crate) struct TestsOutsideTestModule { - pub test_mod_exists: bool, -} - -impl TestsOutsideTestModule { - pub fn new() -> Self { - Self { test_mod_exists: false } - } -} - -impl_lint_pass!(TestsOutsideTestModule => [TESTS_OUTSIDE_TEST_MODULE]); +declare_lint_pass!(TestsOutsideTestModule => [TESTS_OUTSIDE_TEST_MODULE]); impl LateLintPass<'_> for TestsOutsideTestModule { - fn check_mod(&mut self, cx: &LateContext<'_>, _: &Mod<'_>, _: HirId) { - self.test_mod_exists = false; - - // par_for_each_item uses Fn, while par_for_each_in uses FnMut - par_for_each_in(cx.tcx.hir_crate_items(()).items(), |itemid| { - let item = cx.tcx.hir().item(itemid); - if_chain! { - if matches!(item.kind, ItemKind::Mod(_)); - if is_test_module_or_function(cx.tcx, item); - then { - self.test_mod_exists = true; - } - } - }); - } - fn check_fn( &mut self, cx: &LateContext<'_>, @@ -83,7 +56,6 @@ impl LateLintPass<'_> for TestsOutsideTestModule { ) { if_chain! { if !matches!(kind, FnKind::Closure); - if self.test_mod_exists; if is_in_test_function(cx.tcx, body.id().hir_id); if !is_in_cfg_test(cx.tcx, body.id().hir_id); then { From 4cb73cc7d014d9848c0e00531cbd9dcc561e4253 Mon Sep 17 00:00:00 2001 From: fleetingbytes <7075397+fleetingbytes@users.noreply.github.com> Date: Mon, 3 Apr 2023 19:30:20 +0200 Subject: [PATCH 076/272] Preserve potential mood for equal or NUL sign Original `var_os` description said that it _may_ return an error if the value contains `=` or NUL. Let's make no promises on the `None` return value in these situation either, keep it in the [potential mood](https://en.wikipedia.org/wiki/Grammatical_mood#Potential). --- library/std/src/env.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 1345469d8b32..51e5c60ed294 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -236,11 +236,9 @@ fn _var(key: &OsStr) -> Result { } /// Fetches the environment variable `key` from the current process, returning -/// [`None`] in the following situations: -/// -/// - the environment variable isn't set -/// - the environment variable's name contains -/// the equal sign character (`=`) or the NUL character +/// [`None`] if the environment variable isn't set. It may return `None` also +/// if the environment variable's name contains +/// the equal sign character (`=`) or the NUL character. /// /// Note that the method will not check if the environment variable /// is valid Unicode. If you want to have an error on invalid UTF-8, From c96c30aeedd753b4e7f4eaa51f7589fed09f40a1 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Mon, 3 Apr 2023 21:09:53 +0200 Subject: [PATCH 077/272] test that modifications to the source don't become visible after io::copy --- library/std/src/sys/unix/kernel_copy/tests.rs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/library/std/src/sys/unix/kernel_copy/tests.rs b/library/std/src/sys/unix/kernel_copy/tests.rs index 3fe849e23e2e..a524270e3fb8 100644 --- a/library/std/src/sys/unix/kernel_copy/tests.rs +++ b/library/std/src/sys/unix/kernel_copy/tests.rs @@ -83,6 +83,48 @@ fn copies_append_mode_sink() -> Result<()> { Ok(()) } +#[test] +fn dont_splice_pipes_from_files() -> Result<()> { + // splicing to a pipe and then modifying the source could lead to changes + // becoming visible in an unexpected order. + + use crate::io::SeekFrom; + use crate::os::unix::fs::FileExt; + use crate::process::{ChildStdin, ChildStdout}; + use crate::sys_common::FromInner; + + let (read_end, write_end) = crate::sys::pipe::anon_pipe()?; + + let mut read_end = ChildStdout::from_inner(read_end); + let mut write_end = ChildStdin::from_inner(write_end); + + let tmp_path = tmpdir(); + let file = tmp_path.join("to_be_modified"); + let mut file = + crate::fs::OpenOptions::new().create_new(true).read(true).write(true).open(file)?; + + const SZ: usize = libc::PIPE_BUF as usize; + + // put data in page cache + let mut buf: [u8; SZ] = [0x01; SZ]; + file.write_all(&buf).unwrap(); + + // copy page into pipe + file.seek(SeekFrom::Start(0)).unwrap(); + assert!(io::copy(&mut file, &mut write_end).unwrap() == SZ as u64); + + // modify file + buf[0] = 0x02; + file.write_at(&buf, 0).unwrap(); + + // read from pipe + read_end.read_exact(buf.as_mut_slice()).unwrap(); + + assert_eq!(buf[0], 0x01, "data in pipe should reflect the original, not later modifications"); + + Ok(()) +} + #[bench] fn bench_file_to_file_copy(b: &mut test::Bencher) { const BYTES: usize = 128 * 1024; From 171ccb54f06a168f10249b6cbfc22b1cb66ee125 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Mon, 20 Feb 2023 20:56:50 +0100 Subject: [PATCH 078/272] avoid zero-copy ops for File->Pipe and File->Socket in io::copy --- library/std/src/sys/unix/kernel_copy.rs | 62 ++++++++++++++++++------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs index 73b9bef7e2ac..16c8e0c0ebfc 100644 --- a/library/std/src/sys/unix/kernel_copy.rs +++ b/library/std/src/sys/unix/kernel_copy.rs @@ -17,11 +17,9 @@ //! Once it has obtained all necessary pieces and brought any wrapper types into a state where they //! can be safely bypassed it will attempt to use the `copy_file_range(2)`, //! `sendfile(2)` or `splice(2)` syscalls to move data directly between file descriptors. -//! Since those syscalls have requirements that cannot be fully checked in advance and -//! gathering additional information about file descriptors would require additional syscalls -//! anyway it simply attempts to use them one after another (guided by inaccurate hints) to -//! figure out which one works and falls back to the generic read-write copy loop if none of them -//! does. +//! Since those syscalls have requirements that cannot be fully checked in advance it attempts +//! to use them one after another (guided by hints) to figure out which one works and +//! falls back to the generic read-write copy loop if none of them does. //! Once a working syscall is found for a pair of file descriptors it will be called in a loop //! until the copy operation is completed. //! @@ -84,14 +82,10 @@ pub(crate) fn copy_spec( /// The methods on this type only provide hints, due to `AsRawFd` and `FromRawFd` the inferred /// type may be wrong. enum FdMeta { - /// We obtained the FD from a type that can contain any type of `FileType` and queried the metadata - /// because it is cheaper than probing all possible syscalls (reader side) Metadata(Metadata), Socket, Pipe, - /// We don't have any metadata, e.g. because the original type was `File` which can represent - /// any `FileType` and we did not query the metadata either since it did not seem beneficial - /// (writer side) + /// We don't have any metadata because the stat syscall failed NoneObtained, } @@ -131,6 +125,39 @@ impl FdMeta { } } +/// Returns true either if changes made to the source after a sendfile/splice call won't become +/// visible in the sink or the source has explicitly opted into such behavior (e.g. by splicing +/// a file into a pipe, the pipe being the source in this case). +/// +/// This will prevent File -> Pipe and File -> Socket splicing/sendfile optimizations to uphold +/// the Read/Write API semantics of io::copy. +/// +/// Note: This is not 100% airtight, the caller can use the RawFd conversion methods to turn a +/// regular file into a TcpSocket which will be treated as a socket here without checking. +fn safe_kernel_copy(source: &FdMeta, sink: &FdMeta) -> bool { + match (source, sink) { + // Data arriving from a socket is safe because the sender can't modify the socket buffer. + // Data arriving from a pipe is safe(-ish) because either the sender *copied* + // the bytes into the pipe OR explicitly performed an operation that enables zero-copy, + // thus promising not to modify the data later. + (FdMeta::Socket, _) => true, + (FdMeta::Pipe, _) => true, + (FdMeta::Metadata(meta), _) + if meta.file_type().is_fifo() || meta.file_type().is_socket() => + { + true + } + // Data going into non-pipes/non-sockets is safe because the "later changes may become visible" issue + // only happens for pages sitting in send buffers or pipes. + (_, FdMeta::Metadata(meta)) + if !meta.file_type().is_fifo() && !meta.file_type().is_socket() => + { + true + } + _ => false, + } +} + struct CopyParams(FdMeta, Option); struct Copier<'a, 'b, R: Read + ?Sized, W: Write + ?Sized> { @@ -186,7 +213,8 @@ impl SpecCopy for Copier<'_, '_, R, W> { // So we just try and fallback if needed. // If current file offsets + write sizes overflow it may also fail, we do not try to fix that and instead // fall back to the generic copy loop. - if input_meta.potential_sendfile_source() { + if input_meta.potential_sendfile_source() && safe_kernel_copy(&input_meta, &output_meta) + { let result = sendfile_splice(SpliceMode::Sendfile, readfd, writefd, max_write); result.update_take(reader); @@ -197,7 +225,9 @@ impl SpecCopy for Copier<'_, '_, R, W> { } } - if input_meta.maybe_fifo() || output_meta.maybe_fifo() { + if (input_meta.maybe_fifo() || output_meta.maybe_fifo()) + && safe_kernel_copy(&input_meta, &output_meta) + { let result = sendfile_splice(SpliceMode::Splice, readfd, writefd, max_write); result.update_take(reader); @@ -298,13 +328,13 @@ impl CopyRead for &File { impl CopyWrite for File { fn properties(&self) -> CopyParams { - CopyParams(FdMeta::NoneObtained, Some(self.as_raw_fd())) + CopyParams(fd_to_meta(self), Some(self.as_raw_fd())) } } impl CopyWrite for &File { fn properties(&self) -> CopyParams { - CopyParams(FdMeta::NoneObtained, Some(self.as_raw_fd())) + CopyParams(fd_to_meta(*self), Some(self.as_raw_fd())) } } @@ -401,13 +431,13 @@ impl CopyRead for StdinLock<'_> { impl CopyWrite for StdoutLock<'_> { fn properties(&self) -> CopyParams { - CopyParams(FdMeta::NoneObtained, Some(self.as_raw_fd())) + CopyParams(fd_to_meta(self), Some(self.as_raw_fd())) } } impl CopyWrite for StderrLock<'_> { fn properties(&self) -> CopyParams { - CopyParams(FdMeta::NoneObtained, Some(self.as_raw_fd())) + CopyParams(fd_to_meta(self), Some(self.as_raw_fd())) } } From 87b3ae3909d24829da338b40fa0c24e073c3a64d Mon Sep 17 00:00:00 2001 From: Tam Pham Date: Mon, 3 Apr 2023 21:09:06 -0500 Subject: [PATCH 079/272] Make "unneccesary visibility qualifier" error much more clear --- compiler/rustc_ast_passes/messages.ftl | 7 ++-- .../rustc_ast_passes/src/ast_validation.rs | 33 +++++++++++-------- compiler/rustc_ast_passes/src/errors.rs | 14 ++++---- .../src/error_codes/E0449.md | 29 +++++++++++----- 4 files changed, 51 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 747bd52b22c7..a349fe6a3c44 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -17,9 +17,10 @@ ast_passes_keyword_lifetime = ast_passes_invalid_label = invalid label name `{$name}` -ast_passes_invalid_visibility = - unnecessary visibility qualifier - .implied = `pub` not permitted here because it's implied +ast_passes_visibility_not_permitted = + visibility qualifiers are not permitted here + .enum_variant = enum variants and their fields always share the visibility of the enum they are in + .trait_impl = trait items always share the visibility of their trait .individual_impl_items = place qualifiers on individual impl items instead .individual_foreign_items = place qualifiers on individual foreign items instead diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 44b6c77fc419..924b843d97f1 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -240,16 +240,12 @@ impl<'a> AstValidator<'a> { } } - fn invalid_visibility(&self, vis: &Visibility, note: Option) { + fn visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote) { if let VisibilityKind::Inherited = vis.kind { return; } - self.session.emit_err(errors::InvalidVisibility { - span: vis.span, - implied: vis.kind.is_pub().then_some(vis.span), - note, - }); + self.session.emit_err(errors::VisibilityNotPermitted { span: vis.span, note }); } fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option, bool)) { @@ -819,7 +815,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { items, }) => { self.with_in_trait_impl(true, Some(*constness), |this| { - this.invalid_visibility(&item.vis, None); + this.visibility_not_permitted( + &item.vis, + errors::VisibilityNotPermittedNote::TraitImpl, + ); if let TyKind::Err = self_ty.kind { this.err_handler().emit_err(errors::ObsoleteAuto { span: item.span }); } @@ -866,9 +865,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { only_trait: only_trait.then_some(()), }; - self.invalid_visibility( + self.visibility_not_permitted( &item.vis, - Some(errors::InvalidVisibilityNote::IndividualImplItems), + errors::VisibilityNotPermittedNote::IndividualImplItems, ); if let &Unsafe::Yes(span) = unsafety { self.err_handler().emit_err(errors::InherentImplCannotUnsafe { @@ -924,9 +923,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => { let old_item = mem::replace(&mut self.extern_mod, Some(item)); - self.invalid_visibility( + self.visibility_not_permitted( &item.vis, - Some(errors::InvalidVisibilityNote::IndividualForeignItems), + errors::VisibilityNotPermittedNote::IndividualForeignItems, ); if let &Unsafe::Yes(span) = unsafety { self.err_handler().emit_err(errors::UnsafeItem { span, kind: "extern block" }); @@ -940,9 +939,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ItemKind::Enum(def, _) => { for variant in &def.variants { - self.invalid_visibility(&variant.vis, None); + self.visibility_not_permitted( + &variant.vis, + errors::VisibilityNotPermittedNote::EnumVariant, + ); for field in variant.data.fields() { - self.invalid_visibility(&field.vis, None); + self.visibility_not_permitted( + &field.vis, + errors::VisibilityNotPermittedNote::EnumVariant, + ); } } } @@ -1303,7 +1308,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } if ctxt == AssocCtxt::Trait || self.in_trait_impl { - self.invalid_visibility(&item.vis, None); + self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl); if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind { self.check_trait_fn_not_const(sig.header.constness); } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index d007097d9181..27bbd237961a 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -42,18 +42,20 @@ pub struct InvalidLabel { } #[derive(Diagnostic)] -#[diag(ast_passes_invalid_visibility, code = "E0449")] -pub struct InvalidVisibility { +#[diag(ast_passes_visibility_not_permitted, code = "E0449")] +pub struct VisibilityNotPermitted { #[primary_span] pub span: Span, - #[label(ast_passes_implied)] - pub implied: Option, #[subdiagnostic] - pub note: Option, + pub note: VisibilityNotPermittedNote, } #[derive(Subdiagnostic)] -pub enum InvalidVisibilityNote { +pub enum VisibilityNotPermittedNote { + #[note(ast_passes_enum_variant)] + EnumVariant, + #[note(ast_passes_trait_impl)] + TraitImpl, #[note(ast_passes_individual_impl_items)] IndividualImplItems, #[note(ast_passes_individual_foreign_items)] diff --git a/compiler/rustc_error_codes/src/error_codes/E0449.md b/compiler/rustc_error_codes/src/error_codes/E0449.md index 9afc67689bf8..a5876e075284 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0449.md +++ b/compiler/rustc_error_codes/src/error_codes/E0449.md @@ -1,4 +1,6 @@ -A visibility qualifier was used when it was unnecessary. +A visibility qualifier was used where one is not permitted. Visibility +qualifiers are not permitted on enum variants, trait items, impl blocks, and +extern blocks, as they already share the visibility of the parent item. Erroneous code examples: @@ -9,15 +11,18 @@ trait Foo { fn foo(); } -pub impl Bar {} // error: unnecessary visibility qualifier +enum Baz { + pub Qux, // error: visibility qualifiers are not permitted here +} -pub impl Foo for Bar { // error: unnecessary visibility qualifier - pub fn foo() {} // error: unnecessary visibility qualifier +pub impl Bar {} // error: visibility qualifiers are not permitted here + +pub impl Foo for Bar { // error: visibility qualifiers are not permitted here + pub fn foo() {} // error: visibility qualifiers are not permitted here } ``` -To fix this error, please remove the visibility qualifier when it is not -required. Example: +To fix this error, simply remove the visibility qualifier. Example: ``` struct Bar; @@ -26,12 +31,18 @@ trait Foo { fn foo(); } +enum Baz { + // Enum variants share the visibility of the enum they are in, so + // `pub` is not allowed here + Qux, +} + // Directly implemented methods share the visibility of the type itself, -// so `pub` is unnecessary here +// so `pub` is not allowed here impl Bar {} -// Trait methods share the visibility of the trait, so `pub` is -// unnecessary in either case +// Trait methods share the visibility of the trait, so `pub` is not +// allowed in either case impl Foo for Bar { fn foo() {} } From 4e5c120f33780c22923539f8a1e75b3959626cb3 Mon Sep 17 00:00:00 2001 From: Tam Pham Date: Mon, 3 Apr 2023 22:28:55 -0500 Subject: [PATCH 080/272] Update ui tests involving invalid visibility qualifiers --- tests/ui/error-codes/E0449.stderr | 16 ++-- tests/ui/issues/issue-28433.rs | 4 +- tests/ui/issues/issue-28433.stderr | 10 +- tests/ui/parser/assoc-static-semantic-fail.rs | 4 +- .../parser/assoc-static-semantic-fail.stderr | 10 +- tests/ui/parser/default.rs | 2 +- tests/ui/parser/default.stderr | 6 +- tests/ui/parser/trait-pub-assoc-const.rs | 2 +- tests/ui/parser/trait-pub-assoc-const.stderr | 6 +- tests/ui/parser/trait-pub-assoc-ty.rs | 2 +- tests/ui/parser/trait-pub-assoc-ty.stderr | 6 +- tests/ui/parser/trait-pub-method.rs | 2 +- tests/ui/parser/trait-pub-method.stderr | 6 +- tests/ui/privacy/issue-29161.rs | 2 +- tests/ui/privacy/issue-29161.stderr | 6 +- tests/ui/privacy/priv-in-bad-locations.rs | 8 +- tests/ui/privacy/priv-in-bad-locations.stderr | 20 ++-- tests/ui/privacy/privacy-sanity.rs | 36 +++---- tests/ui/privacy/privacy-sanity.stderr | 96 ++++++++++++------- tests/ui/privacy/useless-pub.rs | 6 +- tests/ui/privacy/useless-pub.stderr | 18 ++-- 21 files changed, 162 insertions(+), 106 deletions(-) diff --git a/tests/ui/error-codes/E0449.stderr b/tests/ui/error-codes/E0449.stderr index 8221a5e0ad67..cf41bcce8c20 100644 --- a/tests/ui/error-codes/E0449.stderr +++ b/tests/ui/error-codes/E0449.stderr @@ -1,22 +1,26 @@ -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/E0449.rs:7:1 | LL | pub impl Bar {} - | ^^^ `pub` not permitted here because it's implied + | ^^^ | = note: place qualifiers on individual impl items instead -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/E0449.rs:9:1 | LL | pub impl Foo for Bar { - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/E0449.rs:10:5 | LL | pub fn foo() {} - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait error: aborting due to 3 previous errors diff --git a/tests/ui/issues/issue-28433.rs b/tests/ui/issues/issue-28433.rs index 8d05c32d5de9..2298ad240d56 100644 --- a/tests/ui/issues/issue-28433.rs +++ b/tests/ui/issues/issue-28433.rs @@ -1,9 +1,9 @@ enum Bird { pub Duck, - //~^ ERROR unnecessary visibility qualifier + //~^ ERROR visibility qualifiers are not permitted here Goose, pub(crate) Dove - //~^ ERROR unnecessary visibility qualifier + //~^ ERROR visibility qualifiers are not permitted here } diff --git a/tests/ui/issues/issue-28433.stderr b/tests/ui/issues/issue-28433.stderr index 9f5f6333602f..5fb8a89621c2 100644 --- a/tests/ui/issues/issue-28433.stderr +++ b/tests/ui/issues/issue-28433.stderr @@ -1,14 +1,18 @@ -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/issue-28433.rs:2:5 | LL | pub Duck, - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: enum variants and their fields always share the visibility of the enum they are in -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/issue-28433.rs:5:5 | LL | pub(crate) Dove | ^^^^^^^^^^ + | + = note: enum variants and their fields always share the visibility of the enum they are in error: aborting due to 2 previous errors diff --git a/tests/ui/parser/assoc-static-semantic-fail.rs b/tests/ui/parser/assoc-static-semantic-fail.rs index a8759d2090d0..403160f1253a 100644 --- a/tests/ui/parser/assoc-static-semantic-fail.rs +++ b/tests/ui/parser/assoc-static-semantic-fail.rs @@ -31,7 +31,7 @@ trait T { //~| ERROR a static item cannot be `default` pub(crate) default static TD: u8; //~^ ERROR associated `static` items are not allowed - //~| ERROR unnecessary visibility qualifier + //~| ERROR visibility qualifiers are not permitted here //~| ERROR a static item cannot be `default` } @@ -47,6 +47,6 @@ impl T for S { pub default static TD: u8; //~^ ERROR associated `static` items are not allowed //~| ERROR associated constant in `impl` without body - //~| ERROR unnecessary visibility qualifier + //~| ERROR visibility qualifiers are not permitted here //~| ERROR a static item cannot be `default` } diff --git a/tests/ui/parser/assoc-static-semantic-fail.stderr b/tests/ui/parser/assoc-static-semantic-fail.stderr index 8a74f49b95cc..8178bd223732 100644 --- a/tests/ui/parser/assoc-static-semantic-fail.stderr +++ b/tests/ui/parser/assoc-static-semantic-fail.stderr @@ -134,11 +134,13 @@ LL | pub(crate) default static ID: u8; | | | help: provide a definition for the constant: `= ;` -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/assoc-static-semantic-fail.rs:32:5 | LL | pub(crate) default static TD: u8; | ^^^^^^^^^^ + | + = note: trait items always share the visibility of their trait error: associated constant in `impl` without body --> $DIR/assoc-static-semantic-fail.rs:41:5 @@ -156,11 +158,13 @@ LL | pub default static TD: u8; | | | help: provide a definition for the constant: `= ;` -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/assoc-static-semantic-fail.rs:47:5 | LL | pub default static TD: u8; - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/assoc-static-semantic-fail.rs:3:12 diff --git a/tests/ui/parser/default.rs b/tests/ui/parser/default.rs index 52338c1f13aa..d1058ceb2a1c 100644 --- a/tests/ui/parser/default.rs +++ b/tests/ui/parser/default.rs @@ -14,7 +14,7 @@ impl Foo for u8 { } impl Foo for u16 { - pub default fn foo() -> T { //~ ERROR unnecessary visibility qualifier + pub default fn foo() -> T { //~ ERROR visibility qualifiers are not permitted here T::default() } } diff --git a/tests/ui/parser/default.stderr b/tests/ui/parser/default.stderr index 37aa48ccf52d..e6330f368d91 100644 --- a/tests/ui/parser/default.stderr +++ b/tests/ui/parser/default.stderr @@ -17,11 +17,13 @@ LL | default pub fn foo() -> T { T::default() } LL | } | - item list ends here -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/default.rs:17:5 | LL | pub default fn foo() -> T { - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/default.rs:3:12 diff --git a/tests/ui/parser/trait-pub-assoc-const.rs b/tests/ui/parser/trait-pub-assoc-const.rs index 219ffa309c25..7953e12ecdb8 100644 --- a/tests/ui/parser/trait-pub-assoc-const.rs +++ b/tests/ui/parser/trait-pub-assoc-const.rs @@ -1,6 +1,6 @@ trait Foo { pub const Foo: u32; - //~^ ERROR unnecessary visibility qualifier + //~^ ERROR visibility qualifiers are not permitted here } fn main() {} diff --git a/tests/ui/parser/trait-pub-assoc-const.stderr b/tests/ui/parser/trait-pub-assoc-const.stderr index efd09a0364ee..c14a2f2eea52 100644 --- a/tests/ui/parser/trait-pub-assoc-const.stderr +++ b/tests/ui/parser/trait-pub-assoc-const.stderr @@ -1,8 +1,10 @@ -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/trait-pub-assoc-const.rs:2:5 | LL | pub const Foo: u32; - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait error: aborting due to previous error diff --git a/tests/ui/parser/trait-pub-assoc-ty.rs b/tests/ui/parser/trait-pub-assoc-ty.rs index a78dfbdcddaa..5d9434edc105 100644 --- a/tests/ui/parser/trait-pub-assoc-ty.rs +++ b/tests/ui/parser/trait-pub-assoc-ty.rs @@ -1,6 +1,6 @@ trait Foo { pub type Foo; - //~^ ERROR unnecessary visibility qualifier + //~^ ERROR visibility qualifiers are not permitted here } fn main() {} diff --git a/tests/ui/parser/trait-pub-assoc-ty.stderr b/tests/ui/parser/trait-pub-assoc-ty.stderr index e76373f5c5f8..7f6e7350ca7a 100644 --- a/tests/ui/parser/trait-pub-assoc-ty.stderr +++ b/tests/ui/parser/trait-pub-assoc-ty.stderr @@ -1,8 +1,10 @@ -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/trait-pub-assoc-ty.rs:2:5 | LL | pub type Foo; - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait error: aborting due to previous error diff --git a/tests/ui/parser/trait-pub-method.rs b/tests/ui/parser/trait-pub-method.rs index 1f6ee028a174..c8f33e782e23 100644 --- a/tests/ui/parser/trait-pub-method.rs +++ b/tests/ui/parser/trait-pub-method.rs @@ -1,6 +1,6 @@ trait Foo { pub fn foo(); - //~^ ERROR unnecessary visibility qualifier + //~^ ERROR visibility qualifiers are not permitted here } fn main() {} diff --git a/tests/ui/parser/trait-pub-method.stderr b/tests/ui/parser/trait-pub-method.stderr index 0e3fe027cb5f..2bf1d468a853 100644 --- a/tests/ui/parser/trait-pub-method.stderr +++ b/tests/ui/parser/trait-pub-method.stderr @@ -1,8 +1,10 @@ -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/trait-pub-method.rs:2:5 | LL | pub fn foo(); - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait error: aborting due to previous error diff --git a/tests/ui/privacy/issue-29161.rs b/tests/ui/privacy/issue-29161.rs index d80405aa8562..5c926dee05b2 100644 --- a/tests/ui/privacy/issue-29161.rs +++ b/tests/ui/privacy/issue-29161.rs @@ -2,7 +2,7 @@ mod a { struct A; impl Default for A { - pub fn default() -> A { //~ ERROR unnecessary visibility qualifier + pub fn default() -> A { //~ ERROR visibility qualifiers are not permitted here A } } diff --git a/tests/ui/privacy/issue-29161.stderr b/tests/ui/privacy/issue-29161.stderr index 7ce95e4b0df8..1a6c80499a1b 100644 --- a/tests/ui/privacy/issue-29161.stderr +++ b/tests/ui/privacy/issue-29161.stderr @@ -1,8 +1,10 @@ -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/issue-29161.rs:5:9 | LL | pub fn default() -> A { - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait error[E0603]: struct `A` is private --> $DIR/issue-29161.rs:13:8 diff --git a/tests/ui/privacy/priv-in-bad-locations.rs b/tests/ui/privacy/priv-in-bad-locations.rs index 76af8c6cde80..32c5b801fda8 100644 --- a/tests/ui/privacy/priv-in-bad-locations.rs +++ b/tests/ui/privacy/priv-in-bad-locations.rs @@ -1,4 +1,4 @@ -pub extern "C" { //~ ERROR unnecessary visibility qualifier +pub extern "C" { //~ ERROR visibility qualifiers are not permitted here pub fn bar(); } @@ -8,10 +8,10 @@ trait A { struct B; -pub impl B {} //~ ERROR unnecessary visibility qualifier +pub impl B {} //~ ERROR visibility qualifiers are not permitted here -pub impl A for B { //~ ERROR unnecessary visibility qualifier - pub fn foo(&self) {} //~ ERROR unnecessary visibility qualifier +pub impl A for B { //~ ERROR visibility qualifiers are not permitted here + pub fn foo(&self) {} //~ ERROR visibility qualifiers are not permitted here } pub fn main() {} diff --git a/tests/ui/privacy/priv-in-bad-locations.stderr b/tests/ui/privacy/priv-in-bad-locations.stderr index 75bd2fe47b75..70dab5bfe13d 100644 --- a/tests/ui/privacy/priv-in-bad-locations.stderr +++ b/tests/ui/privacy/priv-in-bad-locations.stderr @@ -1,30 +1,34 @@ -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/priv-in-bad-locations.rs:1:1 | LL | pub extern "C" { - | ^^^ `pub` not permitted here because it's implied + | ^^^ | = note: place qualifiers on individual foreign items instead -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/priv-in-bad-locations.rs:11:1 | LL | pub impl B {} - | ^^^ `pub` not permitted here because it's implied + | ^^^ | = note: place qualifiers on individual impl items instead -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/priv-in-bad-locations.rs:13:1 | LL | pub impl A for B { - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/priv-in-bad-locations.rs:14:5 | LL | pub fn foo(&self) {} - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait error: aborting due to 4 previous errors diff --git a/tests/ui/privacy/privacy-sanity.rs b/tests/ui/privacy/privacy-sanity.rs index 8bbf1ab5d1f3..6622089dda6d 100644 --- a/tests/ui/privacy/privacy-sanity.rs +++ b/tests/ui/privacy/privacy-sanity.rs @@ -10,17 +10,17 @@ pub struct S { } struct Ts(pub u8); -pub impl Tr for S { //~ ERROR unnecessary visibility qualifier - pub fn f() {} //~ ERROR unnecessary visibility qualifier - pub const C: u8 = 0; //~ ERROR unnecessary visibility qualifier - pub type T = u8; //~ ERROR unnecessary visibility qualifier +pub impl Tr for S { //~ ERROR visibility qualifiers are not permitted here + pub fn f() {} //~ ERROR visibility qualifiers are not permitted here + pub const C: u8 = 0; //~ ERROR visibility qualifiers are not permitted here + pub type T = u8; //~ ERROR visibility qualifiers are not permitted here } -pub impl S { //~ ERROR unnecessary visibility qualifier +pub impl S { //~ ERROR visibility qualifiers are not permitted here pub fn f() {} pub const C: u8 = 0; // pub type T = u8; } -pub extern "C" { //~ ERROR unnecessary visibility qualifier +pub extern "C" { //~ ERROR visibility qualifiers are not permitted here pub fn f(); pub static St: u8; } @@ -36,17 +36,17 @@ const MAIN: u8 = { } struct Ts(pub u8); - pub impl Tr for S { //~ ERROR unnecessary visibility qualifier - pub fn f() {} //~ ERROR unnecessary visibility qualifier - pub const C: u8 = 0; //~ ERROR unnecessary visibility qualifier - pub type T = u8; //~ ERROR unnecessary visibility qualifier + pub impl Tr for S { //~ ERROR visibility qualifiers are not permitted here + pub fn f() {} //~ ERROR visibility qualifiers are not permitted here + pub const C: u8 = 0; //~ ERROR visibility qualifiers are not permitted here + pub type T = u8; //~ ERROR visibility qualifiers are not permitted here } - pub impl S { //~ ERROR unnecessary visibility qualifier + pub impl S { //~ ERROR visibility qualifiers are not permitted here pub fn f() {} pub const C: u8 = 0; // pub type T = u8; } - pub extern "C" { //~ ERROR unnecessary visibility qualifier + pub extern "C" { //~ ERROR visibility qualifiers are not permitted here pub fn f(); pub static St: u8; } @@ -65,17 +65,17 @@ fn main() { } struct Ts(pub u8); - pub impl Tr for S { //~ ERROR unnecessary visibility qualifier - pub fn f() {} //~ ERROR unnecessary visibility qualifier - pub const C: u8 = 0; //~ ERROR unnecessary visibility qualifier - pub type T = u8; //~ ERROR unnecessary visibility qualifier + pub impl Tr for S { //~ ERROR visibility qualifiers are not permitted here + pub fn f() {} //~ ERROR visibility qualifiers are not permitted here + pub const C: u8 = 0; //~ ERROR visibility qualifiers are not permitted here + pub type T = u8; //~ ERROR visibility qualifiers are not permitted here } - pub impl S { //~ ERROR unnecessary visibility qualifier + pub impl S { //~ ERROR visibility qualifiers are not permitted here pub fn f() {} pub const C: u8 = 0; // pub type T = u8; } - pub extern "C" { //~ ERROR unnecessary visibility qualifier + pub extern "C" { //~ ERROR visibility qualifiers are not permitted here pub fn f(); pub static St: u8; } diff --git a/tests/ui/privacy/privacy-sanity.stderr b/tests/ui/privacy/privacy-sanity.stderr index c92553fd1a16..a537f8c19010 100644 --- a/tests/ui/privacy/privacy-sanity.stderr +++ b/tests/ui/privacy/privacy-sanity.stderr @@ -1,120 +1,144 @@ -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:13:1 | LL | pub impl Tr for S { - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:14:5 | LL | pub fn f() {} - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:15:5 | LL | pub const C: u8 = 0; - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:16:5 | LL | pub type T = u8; - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:18:1 | LL | pub impl S { - | ^^^ `pub` not permitted here because it's implied + | ^^^ | = note: place qualifiers on individual impl items instead -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:23:1 | LL | pub extern "C" { - | ^^^ `pub` not permitted here because it's implied + | ^^^ | = note: place qualifiers on individual foreign items instead -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:39:5 | LL | pub impl Tr for S { - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:40:9 | LL | pub fn f() {} - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:41:9 | LL | pub const C: u8 = 0; - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:42:9 | LL | pub type T = u8; - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:44:5 | LL | pub impl S { - | ^^^ `pub` not permitted here because it's implied + | ^^^ | = note: place qualifiers on individual impl items instead -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:49:5 | LL | pub extern "C" { - | ^^^ `pub` not permitted here because it's implied + | ^^^ | = note: place qualifiers on individual foreign items instead -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:68:5 | LL | pub impl Tr for S { - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:69:9 | LL | pub fn f() {} - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:70:9 | LL | pub const C: u8 = 0; - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:71:9 | LL | pub type T = u8; - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:73:5 | LL | pub impl S { - | ^^^ `pub` not permitted here because it's implied + | ^^^ | = note: place qualifiers on individual impl items instead -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/privacy-sanity.rs:78:5 | LL | pub extern "C" { - | ^^^ `pub` not permitted here because it's implied + | ^^^ | = note: place qualifiers on individual foreign items instead diff --git a/tests/ui/privacy/useless-pub.rs b/tests/ui/privacy/useless-pub.rs index fde7cd5d89d9..e4b671142f9f 100644 --- a/tests/ui/privacy/useless-pub.rs +++ b/tests/ui/privacy/useless-pub.rs @@ -5,12 +5,12 @@ pub trait E { } impl E for A { - pub fn foo(&self) {} //~ ERROR: unnecessary visibility qualifier + pub fn foo(&self) {} //~ ERROR: visibility qualifiers are not permitted here } enum Foo { - V1 { pub f: i32 }, //~ ERROR unnecessary visibility qualifier - V2(pub i32), //~ ERROR unnecessary visibility qualifier + V1 { pub f: i32 }, //~ ERROR visibility qualifiers are not permitted here + V2(pub i32), //~ ERROR visibility qualifiers are not permitted here } fn main() {} diff --git a/tests/ui/privacy/useless-pub.stderr b/tests/ui/privacy/useless-pub.stderr index 14c4983ae29b..73497e3fed5b 100644 --- a/tests/ui/privacy/useless-pub.stderr +++ b/tests/ui/privacy/useless-pub.stderr @@ -1,20 +1,26 @@ -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/useless-pub.rs:8:5 | LL | pub fn foo(&self) {} - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: trait items always share the visibility of their trait -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/useless-pub.rs:12:10 | LL | V1 { pub f: i32 }, - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: enum variants and their fields always share the visibility of the enum they are in -error[E0449]: unnecessary visibility qualifier +error[E0449]: visibility qualifiers are not permitted here --> $DIR/useless-pub.rs:13:8 | LL | V2(pub i32), - | ^^^ `pub` not permitted here because it's implied + | ^^^ + | + = note: enum variants and their fields always share the visibility of the enum they are in error: aborting due to 3 previous errors From c12748fab3a14beae4958f13551e7e6c52298490 Mon Sep 17 00:00:00 2001 From: feniljain Date: Sat, 1 Apr 2023 16:33:17 +0530 Subject: [PATCH 081/272] fix(needless_return): do not trigger on ambiguous match arms return --- clippy_lints/src/returns.rs | 32 +++++++++++++++++++++++++------- tests/ui/needless_return.fixed | 6 +++--- tests/ui/needless_return.stderr | 12 ++++++------ 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index f0d7dd23a678..b8172b74dc01 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -9,7 +9,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, MatchSource, PatKind, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{self, subst::GenericArgKind, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; @@ -175,7 +175,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { } else { RetReplacement::Empty }; - check_final_expr(cx, body.value, vec![], replacement); + check_final_expr(cx, body.value, vec![], replacement, None); }, FnKind::ItemFn(..) | FnKind::Method(..) => { check_block_return(cx, &body.value.kind, sp, vec![]); @@ -188,11 +188,11 @@ impl<'tcx> LateLintPass<'tcx> for Return { fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, sp: Span, mut semi_spans: Vec) { if let ExprKind::Block(block, _) = expr_kind { if let Some(block_expr) = block.expr { - check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty); + check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty, None); } else if let Some(stmt) = block.stmts.iter().last() { match stmt.kind { StmtKind::Expr(expr) => { - check_final_expr(cx, expr, semi_spans, RetReplacement::Empty); + check_final_expr(cx, expr, semi_spans, RetReplacement::Empty, None); }, StmtKind::Semi(semi_expr) => { // Remove ending semicolons and any whitespace ' ' in between. @@ -202,7 +202,7 @@ fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, span_find_starting_semi(cx.sess().source_map(), semi_span.with_hi(sp.hi())); semi_spans.push(semi_span_to_remove); } - check_final_expr(cx, semi_expr, semi_spans, RetReplacement::Empty); + check_final_expr(cx, semi_expr, semi_spans, RetReplacement::Empty, None); }, _ => (), } @@ -216,6 +216,7 @@ fn check_final_expr<'tcx>( semi_spans: Vec, /* containing all the places where we would need to remove semicolons if finding an * needless return */ replacement: RetReplacement<'tcx>, + match_ty_opt: Option>, ) { let peeled_drop_expr = expr.peel_drop_temps(); match &peeled_drop_expr.kind { @@ -244,7 +245,22 @@ fn check_final_expr<'tcx>( RetReplacement::Expr(snippet, applicability) } } else { - replacement + match match_ty_opt { + Some(match_ty) => { + match match_ty.kind() { + // If the code got till here with + // tuple not getting detected before it, + // then we are sure it's going to be Unit + // type + ty::Tuple(_) => RetReplacement::Unit, + // We don't want to anything in this case + // cause we can't predict what the user would + // want here + _ => return, + } + }, + None => replacement, + } }; if !cx.tcx.hir().attrs(expr.hir_id).is_empty() { @@ -268,8 +284,9 @@ fn check_final_expr<'tcx>( // note, if without else is going to be a type checking error anyways // (except for unit type functions) so we don't match it ExprKind::Match(_, arms, MatchSource::Normal) => { + let match_ty = cx.typeck_results().expr_ty(peeled_drop_expr); for arm in arms.iter() { - check_final_expr(cx, arm.body, semi_spans.clone(), RetReplacement::Unit); + check_final_expr(cx, arm.body, semi_spans.clone(), RetReplacement::Empty, Some(match_ty)); } }, // if it's a whole block, check it @@ -293,6 +310,7 @@ fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, semi_spans: Vec, if ret_span.from_expansion() { return; } + let applicability = replacement.applicability().unwrap_or(Applicability::MachineApplicable); let return_replacement = replacement.to_string(); let sugg_help = replacement.sugg_help(); diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 0f525dd294c9..38ae448618c0 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -81,7 +81,7 @@ fn test_void_if_fun(b: bool) { fn test_void_match(x: u32) { match x { 0 => (), - _ => (), + _ =>(), } } @@ -91,7 +91,7 @@ fn test_nested_match(x: u32) { 1 => { let _ = 42; }, - _ => (), + _ =>(), } } @@ -196,7 +196,7 @@ async fn async_test_void_if_fun(b: bool) { async fn async_test_void_match(x: u32) { match x { 0 => (), - _ => (), + _ =>(), } } diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 87d0cd3e14cf..5d471a3c5214 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -118,10 +118,10 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:87:14 + --> $DIR/needless_return.rs:87:13 | LL | _ => return, - | ^^^^^^ + | ^^^^^^^ | = help: replace `return` with a unit value @@ -136,10 +136,10 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:98:14 + --> $DIR/needless_return.rs:98:13 | LL | _ => return, - | ^^^^^^ + | ^^^^^^^ | = help: replace `return` with a unit value @@ -296,10 +296,10 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:207:14 + --> $DIR/needless_return.rs:207:13 | LL | _ => return, - | ^^^^^^ + | ^^^^^^^ | = help: replace `return` with a unit value From ad26dab27cd314d13e64fe5b49cfa5260a57ab53 Mon Sep 17 00:00:00 2001 From: zhaixiaojuan Date: Thu, 12 May 2022 21:17:31 +0800 Subject: [PATCH 082/272] Initial support for loongarch64-unknown-linux-gnu --- .../src/spec/loongarch64_unknown_linux_gnu.rs | 17 ++++ compiler/rustc_target/src/spec/mod.rs | 1 + src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 1 + .../src/platform-support/loongarch-linux.md | 92 +++++++++++++++++++ tests/ui/check-cfg/compact-values.stderr | 2 +- 6 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_target/src/spec/loongarch64_unknown_linux_gnu.rs create mode 100644 src/doc/rustc/src/platform-support/loongarch-linux.md diff --git a/compiler/rustc_target/src/spec/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/loongarch64_unknown_linux_gnu.rs new file mode 100644 index 000000000000..db8b9c70e670 --- /dev/null +++ b/compiler/rustc_target/src/spec/loongarch64_unknown_linux_gnu.rs @@ -0,0 +1,17 @@ +use crate::spec::{Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "loongarch64-unknown-linux-gnu".into(), + pointer_width: 64, + data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(), + arch: "loongarch64".into(), + options: TargetOptions { + cpu: "generic".into(), + features: "+f,+d".into(), + llvm_abiname: "lp64d".into(), + max_atomic_width: Some(64), + ..super::linux_gnu_base::opts() + }, + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 2553b11d8789..c92a796c70e0 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1021,6 +1021,7 @@ supported_targets! { ("x86_64-unknown-linux-gnux32", x86_64_unknown_linux_gnux32), ("i686-unknown-linux-gnu", i686_unknown_linux_gnu), ("i586-unknown-linux-gnu", i586_unknown_linux_gnu), + ("loongarch64-unknown-linux-gnu", loongarch64_unknown_linux_gnu), ("m68k-unknown-linux-gnu", m68k_unknown_linux_gnu), ("mips-unknown-linux-gnu", mips_unknown_linux_gnu), ("mips64-unknown-linux-gnuabi64", mips64_unknown_linux_gnuabi64), diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 752f1cc4aba0..bbf53a09ce89 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -28,6 +28,7 @@ - [\*-android and \*-androideabi](platform-support/android.md) - [\*-unknown-fuchsia](platform-support/fuchsia.md) - [\*-kmc-solid_\*](platform-support/kmc-solid.md) + - [loongarch\*-unknown-linux-\*](platform-support/loongarch-linux.md) - [m68k-unknown-linux-gnu](platform-support/m68k-unknown-linux-gnu.md) - [mips64-openwrt-linux-musl](platform-support/mips64-openwrt-linux-musl.md) - [mipsel-sony-psx](platform-support/mipsel-sony-psx.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 2d74a2240969..f9de456d17e5 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -263,6 +263,7 @@ target | std | host | notes `i686-uwp-windows-gnu` | ? | | `i686-uwp-windows-msvc` | ? | | `i686-wrs-vxworks` | ? | | +[`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | ? | | LoongArch64 Linux (LP64D ABI) [`m68k-unknown-linux-gnu`](platform-support/m68k-unknown-linux-gnu.md) | ? | | Motorola 680x0 Linux `mips-unknown-linux-uclibc` | ✓ | | MIPS Linux with uClibc [`mips64-openwrt-linux-musl`](platform-support/mips64-openwrt-linux-musl.md) | ? | | MIPS64 for OpenWrt Linux MUSL diff --git a/src/doc/rustc/src/platform-support/loongarch-linux.md b/src/doc/rustc/src/platform-support/loongarch-linux.md new file mode 100644 index 000000000000..e046ec244ece --- /dev/null +++ b/src/doc/rustc/src/platform-support/loongarch-linux.md @@ -0,0 +1,92 @@ +# loongarch\*-unknown-linux-\* + +**Tier: 3** + +[LoongArch] is a new RISC ISA developed by Loongson Technology Corporation Limited. + +[LoongArch]: https://loongson.github.io/LoongArch-Documentation/README-EN.html + +The target name follow this format: `--, where `` specifies the CPU family/model, `` specifies the vendor and `` the operating system name. +While the integer base ABI is implied by the machine field, the floating point base ABI type is encoded into the os field of the specifier using the string suffix ``. + +| `` | `Description` | +|------------------------|--------------------------------------------------------------------| +| f64 | The base ABI use 64-bits FPRs for parameter passing.(lp64d)| +| f32 | The base ABI uses 32-bit FPRs for parameter passing. (lp64f)| +| sf | The base ABI uses no FPR for parameter passing. (lp64s) | + +|`ABI type(Base ABI/ABI extension)`| `C library` | `kernel` | `target tuple` | +|----------------------------------|-------------|----------|----------------------------------| +| lp64d/base | glibc | linux | loongarch64-unknown-linux-gnu | +| lp64f/base | glibc | linux | loongarch64-unknown-linux-gnuf32 | +| lp64s/base | glibc | linux | loongarch64-unknown-linux-gnusf | +| lp64d/base | musl libc | linux | loongarch64-unknown-linux-musl| +| lp64f/base | musl libc | linux | loongarch64-unknown-linux-muslf32| +| lp64s/base | musl libc | linux | loongarch64-unknown-linux-muslsf | + +## Target maintainers + +- [ZHAI xiaojuan](https://github.com/zhaixiaojuan) `zhaixiaojuan@loongson.cn` +- [WANG rui](https://github.com/heiher) `wangrui@loongson.cn` +- [ZHAI xiang](https://github.com/xiangzhai) `zhaixiang@loongson.cn` +- [WANG Xuerui](https://github.com/xen0n) `git@xen0n.name` + +## Requirements + +This target is cross-compiled. +A GNU toolchain for LoongArch target is required. It can be downloaded from https://github.com/loongson/build-tools/releases, or built from the source code of GCC (12.1.0 or later) and Binutils (2.40 or later). + +## Building the target + +The target can be built by enabling it for a `rustc` build. + +```toml +[build] +target = ["loongarch64-unknown-linux-gnu"] +``` + +Make sure `loongarch64-unknown-linux-gnu-gcc` can be searched from the directories specified in`$PATH`. Alternatively, you can use GNU LoongArch Toolchain by adding the following to `config.toml`: + +```toml +[target.loongarch64-unknown-linux-gnu] +# ADJUST THIS PATH TO POINT AT YOUR TOOLCHAIN +cc = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc" +cxx = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-g++" +ar = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-ar" +ranlib = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-ranlib" +linker = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc" +``` + +## Cross-compilation + +This target can be cross-compiled on a `x86_64-unknown-linux-gnu` host. Cross-compilation on other hosts may work but is not tested. + +## Testing +To test a cross-compiled binary on your build system, install the qemu binary that supports the LoongArch architecture and execute the following commands. +```text +CC_loongarch64_unknown_linux_gnu=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc \ +CXX_loongarch64_unknown_linux_gnu=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-g++ \ +AR_loongarch64_unknown_linux_gnu=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc-ar \ +CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNUN_LINKER=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc \ +# SET TARGET SYSTEM LIBRARY PATH +CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNUN_RUNNER="qemu-loongarch64 -L /TOOLCHAIN_PATH/TARGET_LIBRAY_PATH" \ +cargo run --target loongarch64-unknown-linux-gnu --release +``` +Tested on x86 architecture, other architectures not tested. + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for this target, you will either need to build Rust with the target enabled (see "Building the target" above), or build your own copy of `std` by using `build-std` or similar. + +If `rustc` has support for that target and the library artifacts are available, then Rust static libraries can be built for that target: + +```shell +$ rustc --target loongarch64-unknown-linux-gnu your-code.rs --crate-type staticlib +$ ls libyour_code.a +``` + +On Rust Nightly it's possible to build without the target artifacts available: + +```text +cargo build -Z build-std --target loongarch64-unknown-linux-gnu +``` diff --git a/tests/ui/check-cfg/compact-values.stderr b/tests/ui/check-cfg/compact-values.stderr index 9864aa385f99..5ca4d3b3de74 100644 --- a/tests/ui/check-cfg/compact-values.stderr +++ b/tests/ui/check-cfg/compact-values.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition value LL | #[cfg(target(os = "linux", arch = "X"))] | ^^^^^^^^^^ | - = note: expected values for `target_arch` are: aarch64, arm, avr, bpf, hexagon, m68k, mips, mips64, msp430, nvptx64, powerpc, powerpc64, riscv32, riscv64, s390x, sparc, sparc64, wasm32, wasm64, x86, x86_64 + = note: expected values for `target_arch` are: aarch64, arm, avr, bpf, hexagon, loongarch64, m68k, mips, mips64, msp430, nvptx64, powerpc, powerpc64, riscv32, riscv64, s390x, sparc, sparc64, wasm32, wasm64, x86, x86_64 = note: `#[warn(unexpected_cfgs)]` on by default warning: 1 warning emitted From a5e23115bdd3b4655d2bad6076c69c90eec6f12d Mon Sep 17 00:00:00 2001 From: zhaixiaojuan Date: Wed, 6 Jul 2022 18:29:04 +0800 Subject: [PATCH 083/272] library/std: Add support for loongarch64 --- library/std/src/env.rs | 1 + library/std/src/os/linux/raw.rs | 1 + library/std/src/sys/common/alloc.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 183f9ab3b08f..3014fe6e2fc2 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -895,6 +895,7 @@ pub mod consts { /// - x86_64 /// - arm /// - aarch64 + /// - loongarch64 /// - m68k /// - mips /// - mips64 diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs index f46028c3a96c..c55ca8ba26e2 100644 --- a/library/std/src/os/linux/raw.rs +++ b/library/std/src/os/linux/raw.rs @@ -231,6 +231,7 @@ mod arch { } #[cfg(any( + target_arch = "loongarch64", target_arch = "mips64", target_arch = "s390x", target_arch = "sparc64", diff --git a/library/std/src/sys/common/alloc.rs b/library/std/src/sys/common/alloc.rs index 403a5e627f1e..a5fcbdf39c6c 100644 --- a/library/std/src/sys/common/alloc.rs +++ b/library/std/src/sys/common/alloc.rs @@ -22,6 +22,7 @@ pub const MIN_ALIGN: usize = 8; #[cfg(any( target_arch = "x86_64", target_arch = "aarch64", + target_arch = "loongarch64", target_arch = "mips64", target_arch = "s390x", target_arch = "sparc64", From 50be2a30cb8d5141e45c1528b7f538094174941f Mon Sep 17 00:00:00 2001 From: zhaixiaojuan Date: Wed, 6 Jul 2022 18:41:14 +0800 Subject: [PATCH 084/272] library/unwind: Add definitions for loongarch64 --- library/unwind/src/libunwind.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index eeeed3afcd30..f6a68073b2f7 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -75,6 +75,9 @@ pub const unwinder_private_data_size: usize = 20; #[cfg(all(target_arch = "hexagon", target_os = "linux"))] pub const unwinder_private_data_size: usize = 35; +#[cfg(target_arch = "loongarch64")] +pub const unwinder_private_data_size: usize = 2; + #[repr(C)] pub struct _Unwind_Exception { pub exception_class: _Unwind_Exception_Class, From f465bc7874012fdd019d8025861e6dae1e996d5e Mon Sep 17 00:00:00 2001 From: zhaixiaojuan Date: Thu, 7 Jul 2022 10:38:18 +0800 Subject: [PATCH 085/272] rustdoc: Add human-readable cfg string for loongarch64 --- src/librustdoc/clean/cfg.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index dd58a5b51fc1..5177cffe6bae 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -517,6 +517,7 @@ impl<'a> fmt::Display for Display<'a> { "aarch64" => "AArch64", "arm" => "ARM", "asmjs" => "JavaScript", + "loongarch64" => "LoongArch LA64", "m68k" => "M68k", "mips" => "MIPS", "mips64" => "MIPS-64", From 10f7ba562a2f84ff2cfc6d5beec795c24c7e15cd Mon Sep 17 00:00:00 2001 From: zhaixiaojuan Date: Thu, 7 Jul 2022 11:35:08 +0800 Subject: [PATCH 086/272] Add LLVM target and cputype matching for loongarch64 --- src/bootstrap/bootstrap.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 013d1ab525b0..cd59484398c3 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -304,6 +304,7 @@ def default_build_triple(verbose): 'i486': 'i686', 'i686': 'i686', 'i786': 'i686', + 'loongarch64': 'loongarch64', 'm68k': 'm68k', 'powerpc': 'powerpc', 'powerpc64': 'powerpc64', From ccf54177990bd569ec1903735e2c55b6b68471a8 Mon Sep 17 00:00:00 2001 From: zhaixiaojuan Date: Thu, 7 Jul 2022 15:46:10 +0800 Subject: [PATCH 087/272] Enable loongarch64 LLVM target --- compiler/rustc_llvm/build.rs | 1 + compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 7 +++++++ compiler/rustc_llvm/src/lib.rs | 8 ++++++++ config.example.toml | 2 +- src/bootstrap/llvm.rs | 2 +- 5 files changed, 18 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index f8e9ec535e45..b0783d75d475 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -10,6 +10,7 @@ const OPTIONAL_COMPONENTS: &[&str] = &[ "aarch64", "amdgpu", "avr", + "loongarch", "m68k", "mips", "powerpc", diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index e604e44a7157..d48b3a30fc16 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -146,6 +146,12 @@ extern "C" void LLVMTimeTraceProfilerFinish(const char* FileName) { #define SUBTARGET_HEXAGON #endif +#ifdef LLVM_COMPONENT_LOONGARCH +#define SUBTARGET_LOONGARCH SUBTARGET(LoongArch) +#else +#define SUBTARGET_LOONGARCH +#endif + #define GEN_SUBTARGETS \ SUBTARGET_X86 \ SUBTARGET_ARM \ @@ -159,6 +165,7 @@ extern "C" void LLVMTimeTraceProfilerFinish(const char* FileName) { SUBTARGET_SPARC \ SUBTARGET_HEXAGON \ SUBTARGET_RISCV \ + SUBTARGET_LOONGARCH \ #define SUBTARGET(x) \ namespace llvm { \ diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index 8542dcf5bf0f..06351731bdec 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -102,6 +102,14 @@ pub fn initialize_available_targets() { LLVMInitializeM68kAsmPrinter, LLVMInitializeM68kAsmParser ); + init_target!( + llvm_component = "loongarch", + LLVMInitializeLoongArchTargetInfo, + LLVMInitializeLoongArchTarget, + LLVMInitializeLoongArchTargetMC, + LLVMInitializeLoongArchAsmPrinter, + LLVMInitializeLoongArchAsmParser + ); init_target!( llvm_component = "mips", LLVMInitializeMipsTargetInfo, diff --git a/config.example.toml b/config.example.toml index 5ef83760aed2..27b6781ca355 100644 --- a/config.example.toml +++ b/config.example.toml @@ -88,7 +88,7 @@ changelog-seen = 2 # the resulting rustc being unable to compile for the disabled architectures. # # To add support for new targets, see https://rustc-dev-guide.rust-lang.org/building/new-target.html. -#targets = "AArch64;ARM;BPF;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86" +#targets = "AArch64;ARM;BPF;Hexagon;LoongArch;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86" # LLVM experimental targets to build support for. These targets are specified in # the same format as above, but since these targets are experimental, they are diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index de06f8ca8c0b..55b2da7872d2 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -291,7 +291,7 @@ impl Step for Llvm { let llvm_targets = match &builder.config.llvm_targets { Some(s) => s, None => { - "AArch64;ARM;BPF;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;\ + "AArch64;ARM;BPF;Hexagon;LoongArch;MSP430;Mips;NVPTX;PowerPC;RISCV;\ Sparc;SystemZ;WebAssembly;X86" } }; From ca8cad789675b8d8350090c4b8c3a3365d6bcd5b Mon Sep 17 00:00:00 2001 From: zhaixiaojuan Date: Wed, 10 Aug 2022 17:32:53 +0800 Subject: [PATCH 088/272] Add loongarch64 to exception list --- src/bootstrap/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 20b92b294fec..61d764c05c7e 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -129,7 +129,8 @@ const EXTRA_CHECK_CFGS: &[(Option, &'static str, Option<&[&'static str]>)] /* Extra values not defined in the built-in targets yet, but used in std */ (Some(Mode::Std), "target_env", Some(&["libnx"])), // (Some(Mode::Std), "target_os", Some(&[])), - (Some(Mode::Std), "target_arch", Some(&["asmjs", "spirv", "nvptx", "xtensa"])), + // #[cfg(bootstrap)] loongarch64 + (Some(Mode::Std), "target_arch", Some(&["asmjs", "spirv", "nvptx", "xtensa", "loongarch64"])), /* Extra names used by dependencies */ // FIXME: Used by serde_json, but we should not be triggering on external dependencies. (Some(Mode::Rustc), "no_btreemap_remove_entry", None), From b7c5323d42a661665c97e2e14223ac57068775db Mon Sep 17 00:00:00 2001 From: zhaixiaojuan Date: Fri, 3 Feb 2023 11:37:31 +0800 Subject: [PATCH 089/272] Add loongarch64 to fn create_object_file --- compiler/rustc_codegen_ssa/src/back/metadata.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 4ab56699922f..19485175fd1c 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -128,6 +128,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option Architecture::Msp430, "hexagon" => Architecture::Hexagon, "bpf" => Architecture::Bpf, + "loongarch64" => Architecture::LoongArch64, // Unsupported architecture. _ => return None, }; From 737e1d25692ff57699fddb379d62dd6ec1cb2006 Mon Sep 17 00:00:00 2001 From: zhaixiaojuan Date: Fri, 3 Feb 2023 11:47:27 +0800 Subject: [PATCH 090/272] loongarch64: calculate the ELF header flags --- compiler/rustc_codegen_ssa/src/back/metadata.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 19485175fd1c..8ee7d8cf6d02 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -192,6 +192,10 @@ pub(crate) fn create_object_file(sess: &Session) -> Option { + // Source: https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html#_e_flags_identifies_abi_type_and_version + elf::EF_LARCH_OBJABI_V1 | elf::EF_LARCH_ABI_DOUBLE_FLOAT + } _ => 0, }; // adapted from LLVM's `MCELFObjectTargetWriter::getOSABI` From b2f919182045773ee2a4091ef071ffd3183efe45 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Tue, 4 Apr 2023 11:42:32 +0200 Subject: [PATCH 091/272] Fix formatting and lint description --- clippy_lints/src/tests_outside_test_module.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/tests_outside_test_module.rs b/clippy_lints/src/tests_outside_test_module.rs index e454008c68d9..0a0a77082e02 100644 --- a/clippy_lints/src/tests_outside_test_module.rs +++ b/clippy_lints/src/tests_outside_test_module.rs @@ -6,13 +6,11 @@ use rustc_span::{def_id::LocalDefId, Span}; declare_clippy_lint! { /// ### What it does - /// - /// Triggers when a testing function (marked with the `#[test]` attribute) isn't inside a testing module (marked with `#[cfg(test)]`). - /// + /// Triggers when a testing function (marked with the `#[test]` attribute) isn't inside a testing module + /// (marked with `#[cfg(test)]`). /// ### Why is this bad? - /// - /// The idiomatic (and more performant) way of writing tests is inside a testing module (flagged with `#[cfg(test)]`), having test functions outside of this module is confusing and may lead to them being "hidden". - /// + /// The idiomatic (and more performant) way of writing tests is inside a testing module (flagged with `#[cfg(test)]`), + /// having test functions outside of this module is confusing and may lead to them being "hidden". /// ### Example /// ```rust /// #[test] @@ -39,7 +37,7 @@ declare_clippy_lint! { #[clippy::version = "1.70.0"] pub TESTS_OUTSIDE_TEST_MODULE, restriction, - "The test function `my_cool_test` is outside the testing module `tests`." + "A test function is outside the testing module." } declare_lint_pass!(TestsOutsideTestModule => [TESTS_OUTSIDE_TEST_MODULE]); From a6beddcc5a3419c7a829e654e9ce10f4a789bf31 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 29 Mar 2023 08:37:47 +0000 Subject: [PATCH 092/272] rust-analyzer guided enum variant structification --- clippy_lints/src/redundant_static_lifetimes.rs | 4 ++-- clippy_utils/src/ast_utils.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 44bf824aa0e2..d2f03f2a97fb 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; -use rustc_ast::ast::{Item, ItemKind, Ty, TyKind}; +use rustc_ast::ast::{Item, ItemKind, Ty, TyKind, Static}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -106,7 +106,7 @@ impl EarlyLintPass for RedundantStaticLifetimes { // #2438) } - if let ItemKind::Static(ref var_type, _, _) = item.kind { + if let ItemKind::Static(Static(ref var_type, _, _)) = item.kind { Self::visit_type(var_type, cx, "statics have by default a `'static` lifetime"); } } diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index d2dedc204395..30be129ad75a 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -286,7 +286,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { match (l, r) { (ExternCrate(l), ExternCrate(r)) => l == r, (Use(l), Use(r)) => eq_use_tree(l, r), - (Static(lt, lm, le), Static(rt, rm, re)) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), + (Static(ast::Static(lt, lm, le)), Static(ast::Static(rt, rm, re))) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), (Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), ( Fn(box ast::Fn { From 929696d75473d990f8fb5c9f3058501b04b12a7e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 29 Mar 2023 08:50:04 +0000 Subject: [PATCH 093/272] rust-analyzer guided tuple field to named field --- clippy_lints/src/redundant_static_lifetimes.rs | 2 +- clippy_utils/src/ast_utils.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index d2f03f2a97fb..434f00113319 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -106,7 +106,7 @@ impl EarlyLintPass for RedundantStaticLifetimes { // #2438) } - if let ItemKind::Static(Static(ref var_type, _, _)) = item.kind { + if let ItemKind::Static(Static{ ty: ref var_type,.. }) = item.kind { Self::visit_type(var_type, cx, "statics have by default a `'static` lifetime"); } } diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 30be129ad75a..258207639a17 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -286,7 +286,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { match (l, r) { (ExternCrate(l), ExternCrate(r)) => l == r, (Use(l), Use(r)) => eq_use_tree(l, r), - (Static(ast::Static(lt, lm, le)), Static(ast::Static(rt, rm, re))) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), + (Static(ast::Static{ ty: lt, mutability: lm, expr: le}), Static(ast::Static { ty: rt, mutability: rm, expr: re})) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), (Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), ( Fn(box ast::Fn { From ff7636db6a1350fe626b2172e367e721593505ed Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 29 Mar 2023 09:20:45 +0000 Subject: [PATCH 094/272] Split out ast::ItemKind::Const into its own struct --- clippy_lints/src/redundant_static_lifetimes.rs | 4 ++-- clippy_utils/src/ast_utils.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 434f00113319..d41f79f81315 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; -use rustc_ast::ast::{Item, ItemKind, Ty, TyKind, Static}; +use rustc_ast::ast::{Item, ItemKind, Ty, TyKind, Static, ConstItem}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -100,7 +100,7 @@ impl EarlyLintPass for RedundantStaticLifetimes { } if !item.span.from_expansion() { - if let ItemKind::Const(_, ref var_type, _) = item.kind { + if let ItemKind::Const(ConstItem { ty: ref var_type, .. }) = item.kind { Self::visit_type(var_type, cx, "constants have by default a `'static` lifetime"); // Don't check associated consts because `'static` cannot be elided on those (issue // #2438) diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 258207639a17..be841098dba3 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -287,7 +287,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { (ExternCrate(l), ExternCrate(r)) => l == r, (Use(l), Use(r)) => eq_use_tree(l, r), (Static(ast::Static{ ty: lt, mutability: lm, expr: le}), Static(ast::Static { ty: rt, mutability: rm, expr: re})) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), - (Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), + (Const(ast::ConstItem { defaultness: ld, ty: lt, expr: le}), Const(ast::ConstItem { defaultness: rd, ty: rt, expr: re} )) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), ( Fn(box ast::Fn { defaultness: ld, @@ -451,7 +451,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { use AssocItemKind::*; match (l, r) { - (Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), + (Const(ast::ConstItem { defaultness: ld, ty: lt, expr: le}), Const(ast::ConstItem { defaultness: rd, ty: rt, expr: re})) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), ( Fn(box ast::Fn { defaultness: ld, From 6117c063063211196e775b131c8b83e2e6d2c126 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 4 Apr 2023 14:38:46 +0200 Subject: [PATCH 095/272] incr.comp.: Make sure dependencies are recorded when feeding queries during eval-always queries. --- compiler/rustc_passes/src/hir_id_validator.rs | 54 +++++++++---------- .../rustc_query_system/src/dep_graph/graph.rs | 44 +++++++++++---- .../issue-108481-feed-eval-always.rs | 16 ++++++ 3 files changed, 76 insertions(+), 38 deletions(-) create mode 100644 tests/incremental/issue-108481-feed-eval-always.rs diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index 9418f3cd322a..49aa1da01a23 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -8,34 +8,34 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; pub fn check_crate(tcx: TyCtxt<'_>) { - tcx.dep_graph.assert_ignored(); - - if tcx.sess.opts.unstable_opts.hir_stats { - crate::hir_stats::print_hir_stats(tcx); - } - - #[cfg(debug_assertions)] - { - let errors = Lock::new(Vec::new()); - - tcx.hir().par_for_each_module(|module_id| { - let mut v = HirIdValidator { - tcx, - owner: None, - hir_ids_seen: Default::default(), - errors: &errors, - }; - - tcx.hir().visit_item_likes_in_module(module_id, &mut v); - }); - - let errors = errors.into_inner(); - - if !errors.is_empty() { - let message = errors.iter().fold(String::new(), |s1, s2| s1 + "\n" + s2); - tcx.sess.delay_span_bug(rustc_span::DUMMY_SP, &message); + tcx.dep_graph.with_ignore(|| { + if tcx.sess.opts.unstable_opts.hir_stats { + crate::hir_stats::print_hir_stats(tcx); } - } + + #[cfg(debug_assertions)] + { + let errors = Lock::new(Vec::new()); + + tcx.hir().par_for_each_module(|module_id| { + let mut v = HirIdValidator { + tcx, + owner: None, + hir_ids_seen: Default::default(), + errors: &errors, + }; + + tcx.hir().visit_item_likes_in_module(module_id, &mut v); + }); + + let errors = errors.into_inner(); + + if !errors.is_empty() { + let message = errors.iter().fold(String::new(), |s1, s2| s1 + "\n" + s2); + tcx.sess.delay_span_bug(rustc_span::DUMMY_SP, &message); + } + } + }) } struct HirIdValidator<'a, 'hir> { diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 2ff7de8cb9ef..172667e5bdd3 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -143,7 +143,7 @@ impl DepGraph { assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE); // Instantiate a dependy-less red node only once for anonymous queries. - let (_red_node_index, _prev_and_index) = current.intern_node( + let (red_node_index, red_node_prev_index_and_color) = current.intern_node( profiler, &prev_graph, DepNode { kind: DepKind::RED, hash: Fingerprint::ZERO.into() }, @@ -151,8 +151,21 @@ impl DepGraph { None, false, ); - assert_eq!(_red_node_index, DepNodeIndex::FOREVER_RED_NODE); - assert!(matches!(_prev_and_index, None | Some((_, DepNodeColor::Red)))); + assert_eq!(red_node_index, DepNodeIndex::FOREVER_RED_NODE); + match red_node_prev_index_and_color { + None => { + // This is expected when we have no previous compilation session. + assert!(prev_graph_node_count == 0); + } + Some((prev_red_node_index, DepNodeColor::Red)) => { + assert_eq!(prev_red_node_index.as_usize(), red_node_index.as_usize()); + colors.insert(prev_red_node_index, DepNodeColor::Red); + } + Some((_, DepNodeColor::Green(_))) => { + // There must be a logic error somewhere if we hit this branch. + panic!("DepNodeIndex::FOREVER_RED_NODE evaluated to DepNodeColor::Green") + } + } DepGraph { data: Some(Lrc::new(DepGraphData { @@ -353,10 +366,8 @@ impl DepGraphData { })) }; - let task_deps_ref = match &task_deps { - Some(deps) => TaskDepsRef::Allow(deps), - None => TaskDepsRef::Ignore, - }; + let task_deps_ref = + task_deps.as_ref().map(TaskDepsRef::Allow).unwrap_or(TaskDepsRef::EvalAlways); let result = K::with_deps(task_deps_ref, || task(cx, arg)); let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads); @@ -461,6 +472,11 @@ impl DepGraph { K::read_deps(|task_deps| { let mut task_deps = match task_deps { TaskDepsRef::Allow(deps) => deps.lock(), + TaskDepsRef::EvalAlways => { + // We don't need to record dependencies of eval_always + // queries. They are re-evaluated unconditionally anyway. + return; + } TaskDepsRef::Ignore => return, TaskDepsRef::Forbid => { panic!("Illegal read of: {dep_node_index:?}") @@ -556,7 +572,10 @@ impl DepGraph { let mut edges = SmallVec::new(); K::read_deps(|task_deps| match task_deps { TaskDepsRef::Allow(deps) => edges.extend(deps.lock().reads.iter().copied()), - TaskDepsRef::Ignore => {} // During HIR lowering, we have no dependencies. + TaskDepsRef::EvalAlways => { + edges.push(DepNodeIndex::FOREVER_RED_NODE); + } + TaskDepsRef::Ignore => {} TaskDepsRef::Forbid => { panic!("Cannot summarize when dependencies are not recorded.") } @@ -1349,10 +1368,13 @@ pub enum TaskDepsRef<'a, K: DepKind> { /// `TaskDeps`. This is used when executing a 'normal' query /// (no `eval_always` modifier) Allow(&'a Lock>), - /// New dependencies are ignored. This is used when - /// executing an `eval_always` query, since there's no + /// This is used when executing an `eval_always` query. We don't /// need to track dependencies for a query that's always - /// re-executed. This is also used for `dep_graph.with_ignore` + /// re-executed -- but we need to know that this is an `eval_always` + /// query in order to emit dependencies to `DepNodeIndex::FOREVER_RED_NODE` + /// when directly feeding other queries. + EvalAlways, + /// New dependencies are ignored. This is also used for `dep_graph.with_ignore`. Ignore, /// Any attempt to add new dependencies will cause a panic. /// This is used when decoding a query result from disk, diff --git a/tests/incremental/issue-108481-feed-eval-always.rs b/tests/incremental/issue-108481-feed-eval-always.rs new file mode 100644 index 000000000000..8f346a7207e7 --- /dev/null +++ b/tests/incremental/issue-108481-feed-eval-always.rs @@ -0,0 +1,16 @@ +// revisions: cpass1 cpass2 + +#![crate_type = "rlib"] + +use std::fmt::Debug; + +// MCVE kindly provided by Nilstrieb at +// https://github.com/rust-lang/rust/issues/108481#issuecomment-1493080185 + +#[derive(Debug)] +pub struct ConstGeneric { + _p: [(); CHUNK_SIZE], +} + +#[cfg(cpass1)] +impl ConstGeneric {} From e610ddfa5ef4c6d1cd82c1cb7ab0092b799e7b00 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 29 Mar 2023 12:34:05 +0000 Subject: [PATCH 096/272] box a bunch of large types --- clippy_lints/src/redundant_static_lifetimes.rs | 4 ++-- clippy_utils/src/ast_utils.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index d41f79f81315..aa47f3aed54d 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -100,13 +100,13 @@ impl EarlyLintPass for RedundantStaticLifetimes { } if !item.span.from_expansion() { - if let ItemKind::Const(ConstItem { ty: ref var_type, .. }) = item.kind { + if let ItemKind::Const(box ConstItem { ty: ref var_type, .. }) = item.kind { Self::visit_type(var_type, cx, "constants have by default a `'static` lifetime"); // Don't check associated consts because `'static` cannot be elided on those (issue // #2438) } - if let ItemKind::Static(Static{ ty: ref var_type,.. }) = item.kind { + if let ItemKind::Static(box Static { ty: ref var_type,.. }) = item.kind { Self::visit_type(var_type, cx, "statics have by default a `'static` lifetime"); } } diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index be841098dba3..0d2a7440c465 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -286,8 +286,8 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { match (l, r) { (ExternCrate(l), ExternCrate(r)) => l == r, (Use(l), Use(r)) => eq_use_tree(l, r), - (Static(ast::Static{ ty: lt, mutability: lm, expr: le}), Static(ast::Static { ty: rt, mutability: rm, expr: re})) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), - (Const(ast::ConstItem { defaultness: ld, ty: lt, expr: le}), Const(ast::ConstItem { defaultness: rd, ty: rt, expr: re} )) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), + (Static(box ast::Static{ ty: lt, mutability: lm, expr: le}), Static(box ast::Static { ty: rt, mutability: rm, expr: re})) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), + (Const(box ast::ConstItem { defaultness: ld, ty: lt, expr: le}), Const(box ast::ConstItem { defaultness: rd, ty: rt, expr: re} )) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), ( Fn(box ast::Fn { defaultness: ld, @@ -451,7 +451,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { use AssocItemKind::*; match (l, r) { - (Const(ast::ConstItem { defaultness: ld, ty: lt, expr: le}), Const(ast::ConstItem { defaultness: rd, ty: rt, expr: re})) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), + (Const(box ast::ConstItem { defaultness: ld, ty: lt, expr: le}), Const(box ast::ConstItem { defaultness: rd, ty: rt, expr: re})) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), ( Fn(box ast::Fn { defaultness: ld, From e9c7fb10b92c47e9bb2713fae5ef74a07efce92d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 29 Mar 2023 14:14:11 +0000 Subject: [PATCH 097/272] Rename `ast::Static` to `ast::StaticItem` to match `ast::ConstItem` --- clippy_lints/src/redundant_static_lifetimes.rs | 4 ++-- clippy_utils/src/ast_utils.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index aa47f3aed54d..11b908e7e53d 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; -use rustc_ast::ast::{Item, ItemKind, Ty, TyKind, Static, ConstItem}; +use rustc_ast::ast::{Item, ItemKind, Ty, TyKind, StaticItem, ConstItem}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -106,7 +106,7 @@ impl EarlyLintPass for RedundantStaticLifetimes { // #2438) } - if let ItemKind::Static(box Static { ty: ref var_type,.. }) = item.kind { + if let ItemKind::Static(box StaticItem { ty: ref var_type,.. }) = item.kind { Self::visit_type(var_type, cx, "statics have by default a `'static` lifetime"); } } diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 0d2a7440c465..c5b58b0c060c 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -286,7 +286,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { match (l, r) { (ExternCrate(l), ExternCrate(r)) => l == r, (Use(l), Use(r)) => eq_use_tree(l, r), - (Static(box ast::Static{ ty: lt, mutability: lm, expr: le}), Static(box ast::Static { ty: rt, mutability: rm, expr: re})) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), + (Static(box ast::StaticItem { ty: lt, mutability: lm, expr: le}), Static(box ast::StaticItem { ty: rt, mutability: rm, expr: re})) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), (Const(box ast::ConstItem { defaultness: ld, ty: lt, expr: le}), Const(box ast::ConstItem { defaultness: rd, ty: rt, expr: re} )) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), ( Fn(box ast::Fn { From 37f55691f46741d783ba482d42f1cf5ef60593a9 Mon Sep 17 00:00:00 2001 From: IQuant Date: Thu, 23 Feb 2023 16:38:12 +0300 Subject: [PATCH 098/272] Ported FunctionPointerSuggestion --- compiler/rustc_infer/messages.ftl | 5 ++ compiler/rustc_infer/src/errors/mod.rs | 60 +++++++++++++++++++ .../src/infer/error_reporting/suggest.rs | 31 ++++------ 3 files changed, 75 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index 15780898dc6a..9d5933d5ab5a 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -348,3 +348,8 @@ infer_prlf_known_limitation = this is a known limitation that will be removed in infer_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds .label = opaque type defined here + +infer_fps_use_ref = consider using a reference +infer_fps_remove_ref = consider removing the reference +infer_fps_cast = consider casting to a fn pointer +infer_fps_items_are_distinct = fn items are distinct from fn pointers diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 6bbd3fd3e6e7..8c4f44a5b803 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1157,3 +1157,63 @@ pub struct OpaqueCapturesLifetime<'tcx> { pub opaque_ty_span: Span, pub opaque_ty: Ty<'tcx>, } + +#[derive(Subdiagnostic)] +pub enum FunctionPointerSuggestion<'a> { + #[suggestion( + infer_fps_use_ref, + code = "&{fn_name}", + style = "verbose", + applicability = "maybe-incorrect" + )] + UseRef { + #[primary_span] + span: Span, + #[skip_arg] + fn_name: String, + }, + #[suggestion( + infer_fps_remove_ref, + code = "{fn_name}", + style = "verbose", + applicability = "maybe-incorrect" + )] + RemoveRef { + #[primary_span] + span: Span, + #[skip_arg] + fn_name: String, + }, + #[suggestion( + infer_fps_cast, + code = "&({fn_name} as {sig})", + style = "verbose", + applicability = "maybe-incorrect" + )] + CastRef { + #[primary_span] + span: Span, + #[skip_arg] + fn_name: String, + #[skip_arg] + sig: Binder<'a, FnSig<'a>>, + }, + #[suggestion( + infer_fps_cast, + code = "{fn_name} as {sig}", + style = "verbose", + applicability = "maybe-incorrect" + )] + Cast { + #[primary_span] + span: Span, + #[skip_arg] + fn_name: String, + #[skip_arg] + sig: Binder<'a, FnSig<'a>>, + }, +} + +#[derive(Subdiagnostic)] +#[note(infer_fps_items_are_distinct)] +pub struct FnItemsAreDistinct; diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 8ad143247e81..e4b3cf6905d5 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -13,7 +13,8 @@ use rustc_span::{sym, BytePos, Span}; use rustc_target::abi::FieldIdx; use crate::errors::{ - ConsiderAddingAwait, SuggAddLetForLetChains, SuggestRemoveSemiOrReturnBinding, + ConsiderAddingAwait, FnItemsAreDistinct, FunctionPointerSuggestion, SuggAddLetForLetChains, + SuggestRemoveSemiOrReturnBinding, }; use super::TypeErrCtxt; @@ -362,31 +363,19 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { return; } - let (msg, sug) = match (expected.is_ref(), found.is_ref()) { - (true, false) => { - let msg = "consider using a reference"; - let sug = format!("&{fn_name}"); - (msg, sug) - } - (false, true) => { - let msg = "consider removing the reference"; - let sug = format!("{fn_name}"); - (msg, sug) - } + let sugg = match (expected.is_ref(), found.is_ref()) { + (true, false) => FunctionPointerSuggestion::UseRef { span, fn_name }, + (false, true) => FunctionPointerSuggestion::RemoveRef { span, fn_name }, (true, true) => { - diag.note("fn items are distinct from fn pointers"); - let msg = "consider casting to a fn pointer"; - let sug = format!("&({fn_name} as {sig})"); - (msg, sug) + diag.subdiagnostic(FnItemsAreDistinct); + FunctionPointerSuggestion::CastRef { span, fn_name, sig: *sig } } (false, false) => { - diag.note("fn items are distinct from fn pointers"); - let msg = "consider casting to a fn pointer"; - let sug = format!("{fn_name} as {sig}"); - (msg, sug) + diag.subdiagnostic(FnItemsAreDistinct); + FunctionPointerSuggestion::Cast { span, fn_name, sig: *sig } } }; - diag.span_suggestion_verbose(span, msg, sug, Applicability::MaybeIncorrect); + diag.subdiagnostic(sugg); } (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => { let expected_sig = From b36abea285e7615f12c079c40d3a68c9eee15c8d Mon Sep 17 00:00:00 2001 From: IQuant Date: Fri, 3 Mar 2023 15:41:22 +0300 Subject: [PATCH 099/272] Migrate SuggestAsRefWhereAppropriate --- compiler/rustc_infer/messages.ftl | 7 ++ compiler/rustc_infer/src/errors/mod.rs | 72 +++++++++++++++++ .../src/infer/error_reporting/suggest.rs | 81 ++++++++++++------- 3 files changed, 131 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index 9d5933d5ab5a..2cdc513d73c7 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -353,3 +353,10 @@ infer_fps_use_ref = consider using a reference infer_fps_remove_ref = consider removing the reference infer_fps_cast = consider casting to a fn pointer infer_fps_items_are_distinct = fn items are distinct from fn pointers +infer_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}` + +infer_fn_uniq_types = different fn items have unique types, even if their signatures are the same +infer_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}` + +infer_sarwa_option = you can convert from `&Option` to `Option<&T>` using `.as_ref()` +infer_sarwa_result = you can convert from `&Result` to `Result<&T, &E>` using `.as_ref()` diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 8c4f44a5b803..481199d99eae 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1158,6 +1158,14 @@ pub struct OpaqueCapturesLifetime<'tcx> { pub opaque_ty: Ty<'tcx>, } +pub struct DiagArg(pub T); + +impl IntoDiagnosticArg for DiagArg { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + self.0.to_string().into_diagnostic_arg() + } +} + #[derive(Subdiagnostic)] pub enum FunctionPointerSuggestion<'a> { #[suggestion( @@ -1212,8 +1220,72 @@ pub enum FunctionPointerSuggestion<'a> { #[skip_arg] sig: Binder<'a, FnSig<'a>>, }, + #[suggestion( + infer_fps_cast_both, + code = "{fn_name} as {found_sig}", + style = "hidden", + applicability = "maybe-incorrect" + )] + CastBoth { + #[primary_span] + span: Span, + #[skip_arg] + fn_name: String, + #[skip_arg] + found_sig: Binder<'a, FnSig<'a>>, + expected_sig: DiagArg>>, + }, + #[suggestion( + infer_fps_cast_both, + code = "&({fn_name} as {found_sig})", + style = "hidden", + applicability = "maybe-incorrect" + )] + CastBothRef { + #[primary_span] + span: Span, + #[skip_arg] + fn_name: String, + #[skip_arg] + found_sig: Binder<'a, FnSig<'a>>, + expected_sig: DiagArg>>, + }, } #[derive(Subdiagnostic)] #[note(infer_fps_items_are_distinct)] pub struct FnItemsAreDistinct; + +#[derive(Subdiagnostic)] +#[note(infer_fn_uniq_types)] +pub struct FnUniqTypes; + +#[derive(Subdiagnostic)] +#[help(infer_fn_uniq_types)] +pub struct FnConsiderCasting { + pub casting: String, +} + +#[derive(Subdiagnostic)] +pub enum SuggestAsRefWhereAppropriate<'a> { + #[suggestion( + infer_sarwa_option, + code = "{snippet}.as_ref()", + applicability = "machine-applicable" + )] + Option { + #[primary_span] + span: Span, + snippet: &'a str, + }, + #[suggestion( + infer_sarwa_result, + code = "{snippet}.as_ref()", + applicability = "machine-applicable" + )] + Result { + #[primary_span] + span: Span, + snippet: &'a str, + }, +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index e4b3cf6905d5..2d173e9d5776 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -13,12 +13,19 @@ use rustc_span::{sym, BytePos, Span}; use rustc_target::abi::FieldIdx; use crate::errors::{ - ConsiderAddingAwait, FnItemsAreDistinct, FunctionPointerSuggestion, SuggAddLetForLetChains, + ConsiderAddingAwait, DiagArg, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes, + FunctionPointerSuggestion, SuggAddLetForLetChains, SuggestAsRefWhereAppropriate, SuggestRemoveSemiOrReturnBinding, }; use super::TypeErrCtxt; +#[derive(Clone, Copy)] +pub enum SuggestAsRefKind { + Option, + Result, +} + impl<'tcx> TypeErrCtxt<'_, 'tcx> { pub(super) fn suggest_remove_semi_or_return_binding( &self, @@ -322,15 +329,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { diag: &mut Diagnostic, ) { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) - && let Some(msg) = self.should_suggest_as_ref(exp_found.expected, exp_found.found) + && let Some(msg) = self.should_suggest_as_ref_kind(exp_found.expected, exp_found.found) { - diag.span_suggestion( - span, - msg, - // HACK: fix issue# 100605, suggesting convert from &Option to Option<&T>, remove the extra `&` - format!("{}.as_ref()", snippet.trim_start_matches('&')), - Applicability::MachineApplicable, - ); + // HACK: fix issue# 100605, suggesting convert from &Option to Option<&T>, remove the extra `&` + let snippet = snippet.trim_start_matches('&'); + let subdiag = match msg { + SuggestAsRefKind::Option => SuggestAsRefWhereAppropriate::Option { span, snippet }, + SuggestAsRefKind::Result => SuggestAsRefWhereAppropriate::Result { span, snippet }, + }; + diag.subdiagnostic(subdiag); } } @@ -384,7 +391,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &(self.normalize_fn_sig)(self.tcx.fn_sig(*did2).subst(self.tcx, substs2)); if self.same_type_modulo_infer(*expected_sig, *found_sig) { - diag.note("different fn items have unique types, even if their signatures are the same"); + diag.subdiagnostic(FnUniqTypes); } if !self.same_type_modulo_infer(*found_sig, *expected_sig) @@ -398,16 +405,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let fn_name = self.tcx.def_path_str_with_substs(*did2, substs2); let sug = if found.is_ref() { - format!("&({fn_name} as {found_sig})") + FunctionPointerSuggestion::CastBothRef { + span, + fn_name, + found_sig: *found_sig, + expected_sig: DiagArg(*expected_sig), + } } else { - format!("{fn_name} as {found_sig}") + FunctionPointerSuggestion::CastBoth { + span, + fn_name, + found_sig: *found_sig, + expected_sig: DiagArg(*expected_sig), + } }; - let msg = format!( - "consider casting both fn items to fn pointers using `as {expected_sig}`" - ); - - diag.span_suggestion_hidden(span, msg, sug, Applicability::MaybeIncorrect); + diag.subdiagnostic(sug); } (ty::FnDef(did, substs), ty::FnPtr(sig)) => { let expected_sig = @@ -426,7 +439,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { format!("{fn_name} as {found_sig}") }; - diag.help(&format!("consider casting the fn item to a fn pointer: `{}`", casting)); + diag.subdiagnostic(FnConsiderCasting { casting }); } _ => { return; @@ -434,23 +447,19 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; } - pub fn should_suggest_as_ref(&self, expected: Ty<'tcx>, found: Ty<'tcx>) -> Option<&str> { + pub fn should_suggest_as_ref_kind( + &self, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) -> Option { if let (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) = (expected.kind(), found.kind()) { if let ty::Adt(found_def, found_substs) = *found_ty.kind() { if exp_def == &found_def { let have_as_ref = &[ - ( - sym::Option, - "you can convert from `&Option` to `Option<&T>` using \ - `.as_ref()`", - ), - ( - sym::Result, - "you can convert from `&Result` to \ - `Result<&T, &E>` using `.as_ref()`", - ), + (sym::Option, SuggestAsRefKind::Option), + (sym::Result, SuggestAsRefKind::Result), ]; if let Some(msg) = have_as_ref.iter().find_map(|(name, msg)| { self.tcx.is_diagnostic_item(*name, exp_def.did()).then_some(msg) @@ -484,6 +493,20 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { None } + // FIXME: Remove once rustc_hir_typeck is migrated to Diagnostics + pub fn should_suggest_as_ref(&self, expected: Ty<'tcx>, found: Ty<'tcx>) -> Option<&str> { + match self.should_suggest_as_ref_kind(expected, found) { + Some(SuggestAsRefKind::Option) => Some( + "you can convert from `&Option` to `Option<&T>` using \ + `.as_ref()`", + ), + Some(SuggestAsRefKind::Result) => Some( + "you can convert from `&Result` to \ + `Result<&T, &E>` using `.as_ref()`", + ), + None => None, + } + } /// Try to find code with pattern `if Some(..) = expr` /// use a `visitor` to mark the `if` which its span contains given error span, /// and then try to find a assignment in the `cond` part, which span is equal with error span From d56b304bc8bd603d5f4298793f33f1cbb6c9d0d1 Mon Sep 17 00:00:00 2001 From: IQuant Date: Fri, 3 Mar 2023 16:17:53 +0300 Subject: [PATCH 100/272] Migrate SuggestAccessingField --- compiler/rustc_infer/messages.ftl | 2 ++ compiler/rustc_infer/src/errors/mod.rs | 28 +++++++++++++++++++ .../src/infer/error_reporting/suggest.rs | 27 ++++-------------- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index 2cdc513d73c7..17de77b74a84 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -360,3 +360,5 @@ infer_fn_consider_casting = consider casting the fn item to a fn pointer: `{$cas infer_sarwa_option = you can convert from `&Option` to `Option<&T>` using `.as_ref()` infer_sarwa_result = you can convert from `&Result` to `Result<&T, &E>` using `.as_ref()` + +infer_suggest_accessing_field = you might have meant to use field `{$name}` whose type is `{$ty}` diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 481199d99eae..25c4e9a55f84 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1289,3 +1289,31 @@ pub enum SuggestAsRefWhereAppropriate<'a> { snippet: &'a str, }, } + +#[derive(Subdiagnostic)] +pub enum SuggestAccessingField<'a> { + #[suggestion( + infer_suggest_accessing_field, + code = "{snippet}.{name}", + applicability = "maybe-incorrect" + )] + Safe { + #[primary_span] + span: Span, + snippet: String, + name: Symbol, + ty: Ty<'a>, + }, + #[suggestion( + infer_suggest_accessing_field, + code = "unsafe {{ {snippet}.{name} }}", + applicability = "maybe-incorrect" + )] + Unsafe { + #[primary_span] + span: Span, + snippet: String, + name: Symbol, + ty: Ty<'a>, + }, +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 2d173e9d5776..88d7cab0e4c9 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -14,8 +14,8 @@ use rustc_target::abi::FieldIdx; use crate::errors::{ ConsiderAddingAwait, DiagArg, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes, - FunctionPointerSuggestion, SuggAddLetForLetChains, SuggestAsRefWhereAppropriate, - SuggestRemoveSemiOrReturnBinding, + FunctionPointerSuggestion, SuggAddLetForLetChains, SuggestAccessingField, + SuggestAsRefWhereAppropriate, SuggestRemoveSemiOrReturnBinding, }; use super::TypeErrCtxt; @@ -264,15 +264,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - pub fn suggest_await_on_future(&self, diag: &mut Diagnostic, sp: Span) { - diag.span_suggestion_verbose( - sp.shrink_to_hi(), - "consider `await`ing on the `Future`", - ".await", - Applicability::MaybeIncorrect, - ); - } - pub(super) fn suggest_accessing_field_where_appropriate( &self, cause: &ObligationCause<'tcx>, @@ -299,21 +290,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if let ObligationCauseCode::Pattern { span: Some(span), .. } = *cause.code() { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { let suggestion = if expected_def.is_struct() { - format!("{}.{}", snippet, name) + SuggestAccessingField::Safe { span, snippet, name, ty } } else if expected_def.is_union() { - format!("unsafe {{ {}.{} }}", snippet, name) + SuggestAccessingField::Unsafe { span, snippet, name, ty } } else { return; }; - diag.span_suggestion( - span, - &format!( - "you might have meant to use field `{}` whose type is `{}`", - name, ty - ), - suggestion, - Applicability::MaybeIncorrect, - ); + diag.subdiagnostic(suggestion); } } } From 23b8567a78bd3899dd963e83ed2d698c044c877f Mon Sep 17 00:00:00 2001 From: IQuant Date: Fri, 3 Mar 2023 17:49:51 +0300 Subject: [PATCH 101/272] Migrate SuggestBoxingForReturnImplTrait, Fix typo in infer_fn_consider_casting --- compiler/rustc_infer/messages.ftl | 3 ++ compiler/rustc_infer/src/errors/mod.rs | 20 ++++++++++- .../src/infer/error_reporting/suggest.rs | 36 +++++++++---------- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index 17de77b74a84..2534c1cbdab5 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -362,3 +362,6 @@ infer_sarwa_option = you can convert from `&Option` to `Option<&T>` using `.a infer_sarwa_result = you can convert from `&Result` to `Result<&T, &E>` using `.as_ref()` infer_suggest_accessing_field = you might have meant to use field `{$name}` whose type is `{$ty}` + +infer_sbfrit_change_return_type = you could change the return type to be a boxed trait object +infer_sbfrit_box_return_expr = if you change the return type to expect trait objects, box the returned expressions \ No newline at end of file diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 25c4e9a55f84..5d72ad6fa055 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1261,7 +1261,7 @@ pub struct FnItemsAreDistinct; pub struct FnUniqTypes; #[derive(Subdiagnostic)] -#[help(infer_fn_uniq_types)] +#[help(infer_fn_consider_casting)] pub struct FnConsiderCasting { pub casting: String, } @@ -1317,3 +1317,21 @@ pub enum SuggestAccessingField<'a> { ty: Ty<'a>, }, } + +#[derive(Subdiagnostic)] +pub enum SuggestBoxingForReturnImplTrait { + #[multipart_suggestion(infer_sbfrit_change_return_type, applicability = "maybe-incorrect")] + ChangeReturnType { + #[suggestion_part(code = "Box, + #[suggestion_part(code = ")")] + ends: Vec, + }, +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 88d7cab0e4c9..82ee365f3a09 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -15,7 +15,8 @@ use rustc_target::abi::FieldIdx; use crate::errors::{ ConsiderAddingAwait, DiagArg, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes, FunctionPointerSuggestion, SuggAddLetForLetChains, SuggestAccessingField, - SuggestAsRefWhereAppropriate, SuggestRemoveSemiOrReturnBinding, + SuggestAsRefWhereAppropriate, SuggestBoxingForReturnImplTrait, + SuggestRemoveSemiOrReturnBinding, }; use super::TypeErrCtxt; @@ -80,25 +81,20 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { return_sp: Span, arm_spans: impl Iterator, ) { - err.multipart_suggestion( - "you could change the return type to be a boxed trait object", - vec![ - (return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box".to_string()), - ], - Applicability::MaybeIncorrect, - ); - let sugg = arm_spans - .flat_map(|sp| { - [(sp.shrink_to_lo(), "Box::new(".to_string()), (sp.shrink_to_hi(), ")".to_string())] - .into_iter() - }) - .collect::>(); - err.multipart_suggestion( - "if you change the return type to expect trait objects, box the returned expressions", - sugg, - Applicability::MaybeIncorrect, - ); + let sugg = SuggestBoxingForReturnImplTrait::ChangeReturnType { + start_sp: return_sp.with_hi(return_sp.lo() + BytePos(4)), + end_sp: return_sp.shrink_to_hi(), + }; + err.subdiagnostic(sugg); + + let mut starts = Vec::new(); + let mut ends = Vec::new(); + for span in arm_spans { + starts.push(span.shrink_to_lo()); + ends.push(span.shrink_to_hi()); + } + let sugg = SuggestBoxingForReturnImplTrait::BoxReturnExpr { starts, ends }; + err.subdiagnostic(sugg); } pub(super) fn suggest_tuple_pattern( From d18adb7d560ce39c836b98a702c14ef2ae3a28a1 Mon Sep 17 00:00:00 2001 From: IQuant Date: Fri, 3 Mar 2023 18:56:45 +0300 Subject: [PATCH 102/272] Migrate SuggestTuplePattern --- compiler/rustc_infer/messages.ftl | 5 ++- compiler/rustc_infer/src/errors/mod.rs | 36 ++++++++++++++++++ .../src/infer/error_reporting/suggest.rs | 37 +++++++------------ 3 files changed, 54 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index 2534c1cbdab5..cde0f8e35d06 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -364,4 +364,7 @@ infer_sarwa_result = you can convert from `&Result` to `Result<&T, &E>` us infer_suggest_accessing_field = you might have meant to use field `{$name}` whose type is `{$ty}` infer_sbfrit_change_return_type = you could change the return type to be a boxed trait object -infer_sbfrit_box_return_expr = if you change the return type to expect trait objects, box the returned expressions \ No newline at end of file +infer_sbfrit_box_return_expr = if you change the return type to expect trait objects, box the returned expressions + +infer_stp_wrap_one = try wrapping the pattern in `{$variant}` +infer_stp_wrap_many = try wrapping the pattern in a variant of `{$path}` diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 5d72ad6fa055..439d8a381e43 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1335,3 +1335,39 @@ pub enum SuggestBoxingForReturnImplTrait { ends: Vec, }, } + +#[derive(Subdiagnostic)] +#[multipart_suggestion(infer_stp_wrap_one, applicability = "maybe-incorrect")] +pub struct SuggestTuplePatternOne { + pub variant: String, + #[suggestion_part(code = "{variant}(")] + pub span_low: Span, + #[suggestion_part(code = ")")] + pub span_high: Span, +} + +pub struct SuggestTuplePatternMany { + pub path: String, + pub cause_span: Span, + pub compatible_variants: Vec, +} + +impl AddToDiagnostic for SuggestTuplePatternMany { + fn add_to_diagnostic_with(self, diag: &mut rustc_errors::Diagnostic, f: F) + where + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, + { + diag.set_arg("path", self.path); + let message = f(diag, crate::fluent_generated::infer_stp_wrap_many.into()); + diag.multipart_suggestions( + message, + self.compatible_variants.into_iter().map(|variant| { + vec![ + (self.cause_span.shrink_to_lo(), format!("{}(", variant)), + (self.cause_span.shrink_to_hi(), ")".to_string()), + ] + }), + rustc_errors::Applicability::MaybeIncorrect, + ); + } +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 82ee365f3a09..e7f5fdaef746 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -1,7 +1,7 @@ use hir::def::CtorKind; use hir::intravisit::{walk_expr, walk_stmt, Visitor}; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_middle::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, @@ -16,7 +16,7 @@ use crate::errors::{ ConsiderAddingAwait, DiagArg, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes, FunctionPointerSuggestion, SuggAddLetForLetChains, SuggestAccessingField, SuggestAsRefWhereAppropriate, SuggestBoxingForReturnImplTrait, - SuggestRemoveSemiOrReturnBinding, + SuggestRemoveSemiOrReturnBinding, SuggestTuplePatternMany, SuggestTuplePatternOne, }; use super::TypeErrCtxt; @@ -134,30 +134,21 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { match &compatible_variants[..] { [] => {} [variant] => { - diag.multipart_suggestion_verbose( - &format!("try wrapping the pattern in `{}`", variant), - vec![ - (cause.span.shrink_to_lo(), format!("{}(", variant)), - (cause.span.shrink_to_hi(), ")".to_string()), - ], - Applicability::MaybeIncorrect, - ); + let sugg = SuggestTuplePatternOne { + variant: variant.to_owned(), + span_low: cause.span.shrink_to_lo(), + span_high: cause.span.shrink_to_hi(), + }; + diag.subdiagnostic(sugg); } _ => { // More than one matching variant. - diag.multipart_suggestions( - &format!( - "try wrapping the pattern in a variant of `{}`", - self.tcx.def_path_str(expected_adt.did()) - ), - compatible_variants.into_iter().map(|variant| { - vec![ - (cause.span.shrink_to_lo(), format!("{}(", variant)), - (cause.span.shrink_to_hi(), ")".to_string()), - ] - }), - Applicability::MaybeIncorrect, - ); + let sugg = SuggestTuplePatternMany { + path: self.tcx.def_path_str(expected_adt.did()), + cause_span: cause.span, + compatible_variants, + }; + diag.subdiagnostic(sugg); } } } From b610ce72cec5e450410c50418117a608c5d2ef6a Mon Sep 17 00:00:00 2001 From: IQuant Date: Fri, 3 Mar 2023 22:03:12 +0300 Subject: [PATCH 103/272] Migrate TupleTrailingCommaSuggestion --- compiler/rustc_infer/messages.ftl | 2 ++ compiler/rustc_infer/src/errors/mod.rs | 16 ++++++++++++ .../src/infer/error_reporting/mod.rs | 25 ++++++++----------- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index cde0f8e35d06..0f33660e50c7 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -368,3 +368,5 @@ infer_sbfrit_box_return_expr = if you change the return type to expect trait obj infer_stp_wrap_one = try wrapping the pattern in `{$variant}` infer_stp_wrap_many = try wrapping the pattern in a variant of `{$path}` + +infer_tuple_trailing_comma = use a trailing comma to create a tuple with one element diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 439d8a381e43..6432ae7d3f8a 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1371,3 +1371,19 @@ impl AddToDiagnostic for SuggestTuplePatternMany { ); } } + +#[derive(Subdiagnostic)] +pub enum TupleTrailingCommaSuggestion { + #[suggestion(infer_tuple_trailing_comma, code = ",", applicability = "machine-applicable")] + OnlyComma { + #[primary_span] + span: Span, + }, + #[multipart_suggestion(infer_tuple_trailing_comma, applicability = "machine-applicable")] + AlsoParentheses { + #[suggestion_part(code = "(")] + span_low: Span, + #[suggestion_part(code = ",)")] + span_high: Span, + }, +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index c9956b60a56d..a4345d3ab21c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -50,6 +50,7 @@ use super::region_constraints::GenericKind; use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs}; use crate::errors; +use crate::errors::TupleTrailingCommaSuggestion; use crate::infer; use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type; use crate::infer::ExpectedFound; @@ -2110,22 +2111,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) else { return }; - let msg = "use a trailing comma to create a tuple with one element"; - if code.starts_with('(') && code.ends_with(')') { + let sugg = if code.starts_with('(') && code.ends_with(')') { let before_close = span.hi() - BytePos::from_u32(1); - err.span_suggestion( - span.with_hi(before_close).shrink_to_hi(), - msg, - ",", - Applicability::MachineApplicable, - ); + TupleTrailingCommaSuggestion::OnlyComma { + span: span.with_hi(before_close).shrink_to_hi(), + } } else { - err.multipart_suggestion( - msg, - vec![(span.shrink_to_lo(), "(".into()), (span.shrink_to_hi(), ",)".into())], - Applicability::MachineApplicable, - ); - } + TupleTrailingCommaSuggestion::AlsoParentheses { + span_low: span.shrink_to_lo(), + span_high: span.shrink_to_hi(), + } + }; + err.subdiagnostic(sugg); } fn values_str( From ab11b4389e9236bec5f8fa679900ca7156567a7f Mon Sep 17 00:00:00 2001 From: IQuant Date: Fri, 3 Mar 2023 23:33:39 +0300 Subject: [PATCH 104/272] FailureCode::Error0038 is unreachable, so can be removed --- compiler/rustc_infer/src/infer/error_reporting/mod.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index a4345d3ab21c..de9aa45c315b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -54,7 +54,6 @@ use crate::errors::TupleTrailingCommaSuggestion; use crate::infer; use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type; use crate::infer::ExpectedFound; -use crate::traits::error_reporting::report_object_safety_error; use crate::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, PredicateObligation, @@ -1912,10 +1911,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let span = trace.cause.span(); let failure_code = trace.cause.as_failure_code(terr); let mut diag = match failure_code { - FailureCode::Error0038(did) => { - let violations = self.tcx.object_safety_violations(did); - report_object_safety_error(self.tcx, span, did, violations) - } FailureCode::Error0317(failure_str) => { struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str) } @@ -2825,7 +2820,6 @@ impl<'tcx> InferCtxt<'tcx> { } pub enum FailureCode { - Error0038(DefId), Error0317(&'static str), Error0580(&'static str), Error0308(&'static str), From 1f09bc77c1b72ccd0a037cb0d5729749d3acb304 Mon Sep 17 00:00:00 2001 From: IQuant Date: Sat, 4 Mar 2023 13:35:30 +0300 Subject: [PATCH 105/272] Migrate (most of) report_and_explain_type_error --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- compiler/rustc_infer/messages.ftl | 22 + compiler/rustc_infer/src/errors/mod.rs | 173 ++++++- .../src/infer/error_reporting/mod.rs | 437 +++++++++--------- .../src/infer/error_reporting/suggest.rs | 14 +- 5 files changed, 408 insertions(+), 240 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 61338ac613ae..9bdce1ee071a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -768,7 +768,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (provided_ty, provided_span) = provided_arg_tys[*provided_idx]; let trace = mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty); - if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) { + if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) { self.err_ctxt().report_and_explain_type_error(trace, *e).emit(); return true; } diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index 0f33660e50c7..163992658e1b 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -370,3 +370,25 @@ infer_stp_wrap_one = try wrapping the pattern in `{$variant}` infer_stp_wrap_many = try wrapping the pattern in a variant of `{$path}` infer_tuple_trailing_comma = use a trailing comma to create a tuple with one element + +infer_oc_method_compat = method not compatible with trait +infer_oc_type_compat = type not compatible with trait +infer_oc_const_compat = const not compatible with trait +infer_oc_try_compat = `?` operator has incompatible types +infer_oc_match_compat = `match` arms have incompatible types +infer_oc_if_else_different = `if` and `else` have incompatible types +infer_oc_no_else = `if` may be missing an `else` clause +infer_oc_no_diverge = `else` clause of `let...else` does not diverge +infer_oc_fn_main_correct_type = `main` function has wrong type +infer_oc_fn_start_correct_type = `#[start]` function has wrong type +infer_oc_intristic_correct_type = intrinsic has wrong type +infer_oc_method_correct_type = mismatched `self` parameter type +infer_oc_closure_selfref = closure/generator type that references itself +infer_oc_cant_coerce = cannot coerce intrinsics to function pointers +infer_oc_generic = mismatched types + +infer_meant_byte_literal = if you meant to write a byte literal, prefix with `b` +infer_meant_char_literal = if you meant to write a `char` literal, use single quotes +infer_meant_str_literal = if you meant to write a `str` literal, use double quotes +infer_consider_specifying_length = consider specifying the actual array length +infer_try_cannot_convert = `?` operator cannot convert from `{$found}` to `{$expected}` diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 6432ae7d3f8a..f3bed305f84a 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -184,18 +184,6 @@ pub enum SourceKindMultiSuggestion<'a> { }, } -#[derive(Subdiagnostic)] -#[suggestion( - infer_suggest_add_let_for_letchains, - style = "verbose", - applicability = "machine-applicable", - code = "let " -)] -pub(crate) struct SuggAddLetForLetChains { - #[primary_span] - pub span: Span, -} - impl<'a> SourceKindMultiSuggestion<'a> { pub fn new_fully_qualified( span: Span, @@ -1373,17 +1361,172 @@ impl AddToDiagnostic for SuggestTuplePatternMany { } #[derive(Subdiagnostic)] -pub enum TupleTrailingCommaSuggestion { +pub enum Error0308Subdiags { + #[suggestion( + infer_meant_byte_literal, + code = "b'{code}'", + applicability = "machine-applicable" + )] + MeantByteLiteral { + #[primary_span] + span: Span, + code: String, + }, + #[suggestion( + infer_meant_char_literal, + code = "'{code}'", + applicability = "machine-applicable" + )] + MeantCharLiteral { + #[primary_span] + span: Span, + code: String, + }, + #[suggestion( + infer_meant_str_literal, + code = "\"{code}\"", + applicability = "machine-applicable" + )] + MeantStrLiteral { + #[primary_span] + span: Span, + code: String, + }, + #[suggestion( + infer_consider_specifying_length, + code = "{length}", + applicability = "maybe-incorrect" + )] + ConsiderSpecifyingLength { + #[primary_span] + span: Span, + length: u64, + }, + #[note(infer_try_cannot_convert)] + TryCannotConvert { found: String, expected: String }, #[suggestion(infer_tuple_trailing_comma, code = ",", applicability = "machine-applicable")] - OnlyComma { + TupleOnlyComma { #[primary_span] span: Span, }, #[multipart_suggestion(infer_tuple_trailing_comma, applicability = "machine-applicable")] - AlsoParentheses { + TupleAlsoParentheses { #[suggestion_part(code = "(")] span_low: Span, #[suggestion_part(code = ",)")] span_high: Span, }, + #[suggestion( + infer_suggest_add_let_for_letchains, + style = "verbose", + applicability = "machine-applicable", + code = "let " + )] + AddLetForLetChains { + #[primary_span] + span: Span, + }, +} + +#[derive(Diagnostic)] +pub enum FailureCodeDiagnostics { + #[diag(infer_oc_method_compat, code = "E0308")] + MethodCompat { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(infer_oc_type_compat, code = "E0308")] + TypeCompat { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(infer_oc_const_compat, code = "E0308")] + ConstCompat { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(infer_oc_try_compat, code = "E0308")] + TryCompat { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(infer_oc_match_compat, code = "E0308")] + MatchCompat { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(infer_oc_if_else_different, code = "E0308")] + IfElseDifferent { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(infer_oc_no_else, code = "E0317")] + NoElse { + #[primary_span] + span: Span, + }, + #[diag(infer_oc_no_diverge, code = "E0308")] + NoDiverge { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(infer_oc_fn_main_correct_type, code = "E0580")] + FnMainCorrectType { + #[primary_span] + span: Span, + }, + #[diag(infer_oc_fn_start_correct_type, code = "E0308")] + FnStartCorrectType { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(infer_oc_intristic_correct_type, code = "E0308")] + IntristicCorrectType { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(infer_oc_method_correct_type, code = "E0308")] + MethodCorrectType { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(infer_oc_closure_selfref, code = "E0644")] + ClosureSelfref { + #[primary_span] + span: Span, + }, + #[diag(infer_oc_cant_coerce, code = "E0308")] + CantCoerce { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(infer_oc_generic, code = "E0308")] + Generic { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index de9aa45c315b..4b7f4fe1aaa5 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -49,8 +49,7 @@ use super::lexical_region_resolve::RegionResolutionError; use super::region_constraints::GenericKind; use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs}; -use crate::errors; -use crate::errors::TupleTrailingCommaSuggestion; +use crate::errors::{self, Error0308Subdiags, FailureCodeDiagnostics}; use crate::infer; use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type; use crate::infer::ExpectedFound; @@ -1899,225 +1898,196 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { debug!(?diag); } + pub fn type_error_additional_suggestions( + &self, + trace: &TypeTrace<'tcx>, + terr: TypeError<'tcx>, + ) -> Vec { + use crate::traits::ObligationCauseCode::MatchExpressionArm; + fn escape_literal(s: &str) -> String { + let mut escaped = String::with_capacity(s.len()); + let mut chrs = s.chars().peekable(); + while let Some(first) = chrs.next() { + match (first, chrs.peek()) { + ('\\', Some(&delim @ '"') | Some(&delim @ '\'')) => { + escaped.push('\\'); + escaped.push(delim); + chrs.next(); + } + ('"' | '\'', _) => { + escaped.push('\\'); + escaped.push(first) + } + (c, _) => escaped.push(c), + }; + } + escaped + } + let mut suggestions = Vec::new(); + let span = trace.cause.span(); + if let Some((expected, found)) = trace.values.ty() { + match (expected.kind(), found.kind()) { + (ty::Tuple(_), ty::Tuple(_)) => {} + // If a tuple of length one was expected and the found expression has + // parentheses around it, perhaps the user meant to write `(expr,)` to + // build a tuple (issue #86100) + (ty::Tuple(fields), _) => { + suggestions.extend(self.tuple_wrap_err_subdiag( span, found, fields)) + } + // If a byte was expected and the found expression is a char literal + // containing a single ASCII character, perhaps the user meant to write `b'c'` to + // specify a byte literal + (ty::Uint(ty::UintTy::U8), ty::Char) => { + if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) + && let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) + && !code.starts_with("\\u") // forbid all Unicode escapes + && code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII + { + suggestions.push(Error0308Subdiags::MeantByteLiteral { span, code: escape_literal(code) }) + } + } + // If a character was expected and the found expression is a string literal + // containing a single character, perhaps the user meant to write `'c'` to + // specify a character literal (issue #92479) + (ty::Char, ty::Ref(_, r, _)) if r.is_str() => { + if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) + && let Some(code) = code.strip_prefix('"').and_then(|s| s.strip_suffix('"')) + && code.chars().count() == 1 + { + suggestions.push(Error0308Subdiags::MeantCharLiteral { span, code: escape_literal(code) }) + } + } + // If a string was expected and the found expression is a character literal, + // perhaps the user meant to write `"s"` to specify a string literal. + (ty::Ref(_, r, _), ty::Char) if r.is_str() => { + if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) { + if let Some(code) = + code.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) + { + suggestions.push(Error0308Subdiags::MeantStrLiteral { span, code: escape_literal(code) }) + } + } + } + // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`, + // we try to suggest to add the missing `let` for `if let Some(..) = expr` + (ty::Bool, ty::Tuple(list)) => if list.len() == 0 { + suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span)); + } + (ty::Array(_, _), ty::Array(_, _)) => 'block: { + let hir = self.tcx.hir(); + let TypeError::FixedArraySize(sz) = terr else { + break 'block; + }; + let tykind = match hir.find_by_def_id(trace.cause.body_id) { + Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn(_, _, body_id), + .. + })) => { + let body = hir.body(*body_id); + struct LetVisitor<'v> { + span: Span, + result: Option<&'v hir::Ty<'v>>, + } + impl<'v> Visitor<'v> for LetVisitor<'v> { + fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) { + if self.result.is_some() { + return; + } + // Find a local statement where the initializer has + // the same span as the error and the type is specified. + if let hir::Stmt { + kind: hir::StmtKind::Local(hir::Local { + init: Some(hir::Expr { + span: init_span, + .. + }), + ty: Some(array_ty), + .. + }), + .. + } = s + && init_span == &self.span { + self.result = Some(*array_ty); + } + } + } + let mut visitor = LetVisitor {span, result: None}; + visitor.visit_body(body); + visitor.result.map(|r| &r.peel_refs().kind) + } + Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Const(ty, _), + .. + })) => { + Some(&ty.peel_refs().kind) + } + _ => None + }; + + if let Some(tykind) = tykind + && let hir::TyKind::Array(_, length) = tykind + && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length + && let Some(span) = self.tcx.hir().opt_span(*hir_id) + { + suggestions.push(Error0308Subdiags::ConsiderSpecifyingLength { span, length: sz.found }); + } + } + _ => {} + } + } + let code = trace.cause.code(); + if let &MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = code + && let hir::MatchSource::TryDesugar = source + && let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values) + { + suggestions.push(Error0308Subdiags::TryCannotConvert { found: found_ty.content(), expected: expected_ty.content() }); + } + suggestions + } + pub fn report_and_explain_type_error( &self, trace: TypeTrace<'tcx>, terr: TypeError<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - use crate::traits::ObligationCauseCode::MatchExpressionArm; - debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr); let span = trace.cause.span(); - let failure_code = trace.cause.as_failure_code(terr); - let mut diag = match failure_code { - FailureCode::Error0317(failure_str) => { - struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str) - } - FailureCode::Error0580(failure_str) => { - struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str) - } - FailureCode::Error0308(failure_str) => { - fn escape_literal(s: &str) -> String { - let mut escaped = String::with_capacity(s.len()); - let mut chrs = s.chars().peekable(); - while let Some(first) = chrs.next() { - match (first, chrs.peek()) { - ('\\', Some(&delim @ '"') | Some(&delim @ '\'')) => { - escaped.push('\\'); - escaped.push(delim); - chrs.next(); - } - ('"' | '\'', _) => { - escaped.push('\\'); - escaped.push(first) - } - (c, _) => escaped.push(c), - }; - } - escaped - } - let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str); - let values = self.resolve_vars_if_possible(trace.values); - if let Some((expected, found)) = values.ty() { - match (expected.kind(), found.kind()) { - (ty::Tuple(_), ty::Tuple(_)) => {} - // If a tuple of length one was expected and the found expression has - // parentheses around it, perhaps the user meant to write `(expr,)` to - // build a tuple (issue #86100) - (ty::Tuple(fields), _) => { - self.emit_tuple_wrap_err(&mut err, span, found, fields) - } - // If a byte was expected and the found expression is a char literal - // containing a single ASCII character, perhaps the user meant to write `b'c'` to - // specify a byte literal - (ty::Uint(ty::UintTy::U8), ty::Char) => { - if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) - && let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) - && !code.starts_with("\\u") // forbid all Unicode escapes - && code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII - { - err.span_suggestion( - span, - "if you meant to write a byte literal, prefix with `b`", - format!("b'{}'", escape_literal(code)), - Applicability::MachineApplicable, - ); - } - } - // If a character was expected and the found expression is a string literal - // containing a single character, perhaps the user meant to write `'c'` to - // specify a character literal (issue #92479) - (ty::Char, ty::Ref(_, r, _)) if r.is_str() => { - if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) - && let Some(code) = code.strip_prefix('"').and_then(|s| s.strip_suffix('"')) - && code.chars().count() == 1 - { - err.span_suggestion( - span, - "if you meant to write a `char` literal, use single quotes", - format!("'{}'", escape_literal(code)), - Applicability::MachineApplicable, - ); - } - } - // If a string was expected and the found expression is a character literal, - // perhaps the user meant to write `"s"` to specify a string literal. - (ty::Ref(_, r, _), ty::Char) if r.is_str() => { - if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) { - if let Some(code) = - code.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) - { - err.span_suggestion( - span, - "if you meant to write a `str` literal, use double quotes", - format!("\"{}\"", escape_literal(code)), - Applicability::MachineApplicable, - ); - } - } - } - // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`, - // we try to suggest to add the missing `let` for `if let Some(..) = expr` - (ty::Bool, ty::Tuple(list)) => if list.len() == 0 { - self.suggest_let_for_letchains(&mut err, &trace.cause, span); - } - (ty::Array(_, _), ty::Array(_, _)) => 'block: { - let hir = self.tcx.hir(); - let TypeError::FixedArraySize(sz) = terr else { - break 'block; - }; - let tykind = match hir.find_by_def_id(trace.cause.body_id) { - Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(_, _, body_id), - .. - })) => { - let body = hir.body(*body_id); - struct LetVisitor<'v> { - span: Span, - result: Option<&'v hir::Ty<'v>>, - } - impl<'v> Visitor<'v> for LetVisitor<'v> { - fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) { - if self.result.is_some() { - return; - } - // Find a local statement where the initializer has - // the same span as the error and the type is specified. - if let hir::Stmt { - kind: hir::StmtKind::Local(hir::Local { - init: Some(hir::Expr { - span: init_span, - .. - }), - ty: Some(array_ty), - .. - }), - .. - } = s - && init_span == &self.span { - self.result = Some(*array_ty); - } - } - } - let mut visitor = LetVisitor {span, result: None}; - visitor.visit_body(body); - visitor.result.map(|r| &r.peel_refs().kind) - } - Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Const(ty, _), - .. - })) => { - Some(&ty.peel_refs().kind) - } - _ => None - }; - - if let Some(tykind) = tykind - && let hir::TyKind::Array(_, length) = tykind - && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length - && let Some(span) = self.tcx.hir().opt_span(*hir_id) - { - err.span_suggestion( - span, - "consider specifying the actual array length", - sz.found, - Applicability::MaybeIncorrect, - ); - } - } - _ => {} - } - } - let code = trace.cause.code(); - if let &MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = code - && let hir::MatchSource::TryDesugar = source - && let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values) - { - err.note(&format!( - "`?` operator cannot convert from `{}` to `{}`", - found_ty.content(), - expected_ty.content(), - )); - } - err - } - FailureCode::Error0644(failure_str) => { - struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str) - } - }; + let failure_code = trace.cause.as_failure_code_diag( + terr, + span, + self.type_error_additional_suggestions(&trace, terr), + ); + let mut diag = self.tcx.sess.create_err(failure_code); self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false, false); diag } - fn emit_tuple_wrap_err( + fn tuple_wrap_err_subdiag( &self, - err: &mut Diagnostic, span: Span, found: Ty<'tcx>, expected_fields: &List>, - ) { - let [expected_tup_elem] = expected_fields[..] else { return }; + ) -> Option { + let [expected_tup_elem] = expected_fields[..] else { return None}; if !self.same_type_modulo_infer(expected_tup_elem, found) { - return; + return None; } let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) - else { return }; + else { return None }; let sugg = if code.starts_with('(') && code.ends_with(')') { let before_close = span.hi() - BytePos::from_u32(1); - TupleTrailingCommaSuggestion::OnlyComma { - span: span.with_hi(before_close).shrink_to_hi(), - } + Error0308Subdiags::TupleOnlyComma { span: span.with_hi(before_close).shrink_to_hi() } } else { - TupleTrailingCommaSuggestion::AlsoParentheses { + Error0308Subdiags::TupleAlsoParentheses { span_low: span.shrink_to_lo(), span_high: span.shrink_to_hi(), } }; - err.subdiagnostic(sugg); + Some(sugg) } fn values_str( @@ -2820,56 +2790,89 @@ impl<'tcx> InferCtxt<'tcx> { } pub enum FailureCode { - Error0317(&'static str), - Error0580(&'static str), - Error0308(&'static str), - Error0644(&'static str), + Error0317, + Error0580, + Error0308, + Error0644, } pub trait ObligationCauseExt<'tcx> { fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode; + + fn as_failure_code_diag( + &self, + terr: TypeError<'tcx>, + span: Span, + subdiags: Vec, + ) -> FailureCodeDiagnostics; fn as_requirement_str(&self) -> &'static str; } impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode { use self::FailureCode::*; + use crate::traits::ObligationCauseCode::*; + match self.code() { + IfExpressionWithNoElse => Error0317, + MainFunctionType => Error0580, + CompareImplItemObligation { .. } + | MatchExpressionArm(_) + | IfExpression { .. } + | LetElse + | StartFunctionType + | IntrinsicType + | MethodReceiver => Error0308, + + // In the case where we have no more specific thing to + // say, also take a look at the error code, maybe we can + // tailor to that. + _ => match terr { + TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => Error0644, + TypeError::IntrinsicCast => Error0308, + _ => Error0308, + }, + } + } + fn as_failure_code_diag( + &self, + terr: TypeError<'tcx>, + span: Span, + subdiags: Vec, + ) -> FailureCodeDiagnostics { use crate::traits::ObligationCauseCode::*; match self.code() { CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => { - Error0308("method not compatible with trait") + FailureCodeDiagnostics::MethodCompat { span, subdiags } } CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => { - Error0308("type not compatible with trait") + FailureCodeDiagnostics::TypeCompat { span, subdiags } } CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => { - Error0308("const not compatible with trait") + FailureCodeDiagnostics::ConstCompat { span, subdiags } } - MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => { - Error0308(match source { - hir::MatchSource::TryDesugar => "`?` operator has incompatible types", - _ => "`match` arms have incompatible types", - }) - } - IfExpression { .. } => Error0308("`if` and `else` have incompatible types"), - IfExpressionWithNoElse => Error0317("`if` may be missing an `else` clause"), - LetElse => Error0308("`else` clause of `let...else` does not diverge"), - MainFunctionType => Error0580("`main` function has wrong type"), - StartFunctionType => Error0308("`#[start]` function has wrong type"), - IntrinsicType => Error0308("intrinsic has wrong type"), - MethodReceiver => Error0308("mismatched `self` parameter type"), + MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source { + hir::MatchSource::TryDesugar => { + FailureCodeDiagnostics::TryCompat { span, subdiags } + } + _ => FailureCodeDiagnostics::MatchCompat { span, subdiags }, + }, + IfExpression { .. } => FailureCodeDiagnostics::IfElseDifferent { span, subdiags }, + IfExpressionWithNoElse => FailureCodeDiagnostics::NoElse { span }, + LetElse => FailureCodeDiagnostics::NoDiverge { span, subdiags }, + MainFunctionType => FailureCodeDiagnostics::FnMainCorrectType { span }, + StartFunctionType => FailureCodeDiagnostics::FnStartCorrectType { span, subdiags }, + IntrinsicType => FailureCodeDiagnostics::IntristicCorrectType { span, subdiags }, + MethodReceiver => FailureCodeDiagnostics::MethodCorrectType { span, subdiags }, // In the case where we have no more specific thing to // say, also take a look at the error code, maybe we can // tailor to that. _ => match terr { TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => { - Error0644("closure/generator type that references itself") + FailureCodeDiagnostics::ClosureSelfref { span } } - TypeError::IntrinsicCast => { - Error0308("cannot coerce intrinsics to function pointers") - } - _ => Error0308("mismatched types"), + TypeError::IntrinsicCast => FailureCodeDiagnostics::CantCoerce { span, subdiags }, + _ => FailureCodeDiagnostics::Generic { span, subdiags }, }, } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index e7f5fdaef746..fecfc53c86a2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -13,10 +13,10 @@ use rustc_span::{sym, BytePos, Span}; use rustc_target::abi::FieldIdx; use crate::errors::{ - ConsiderAddingAwait, DiagArg, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes, - FunctionPointerSuggestion, SuggAddLetForLetChains, SuggestAccessingField, - SuggestAsRefWhereAppropriate, SuggestBoxingForReturnImplTrait, - SuggestRemoveSemiOrReturnBinding, SuggestTuplePatternMany, SuggestTuplePatternOne, + ConsiderAddingAwait, DiagArg, Error0308Subdiags, FnConsiderCasting, FnItemsAreDistinct, + FnUniqTypes, FunctionPointerSuggestion, SuggestAccessingField, SuggestAsRefWhereAppropriate, + SuggestBoxingForReturnImplTrait, SuggestRemoveSemiOrReturnBinding, SuggestTuplePatternMany, + SuggestTuplePatternOne, }; use super::TypeErrCtxt; @@ -482,10 +482,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { /// and then try to find a assignment in the `cond` part, which span is equal with error span pub(super) fn suggest_let_for_letchains( &self, - err: &mut Diagnostic, cause: &ObligationCause<'_>, span: Span, - ) { + ) -> Option { let hir = self.tcx.hir(); if let Some(node) = self.tcx.hir().find_by_def_id(cause.body_id) && let hir::Node::Item(hir::Item { @@ -532,9 +531,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let mut visitor = IfVisitor { err_span: span, found_if: false, result: false }; visitor.visit_body(&body); if visitor.result { - err.subdiagnostic(SuggAddLetForLetChains{span: span.shrink_to_lo()}); + return Some(Error0308Subdiags::AddLetForLetChains{span: span.shrink_to_lo()}); } } + None } } From e813b6d6e1ef76a94a68f98316d76517d7ce0719 Mon Sep 17 00:00:00 2001 From: IQuant Date: Thu, 9 Mar 2023 19:47:30 +0300 Subject: [PATCH 106/272] Update compiler/rustc_infer/src/infer/error_reporting/suggest.rs Co-authored-by: David Wood --- compiler/rustc_infer/src/infer/error_reporting/suggest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index fecfc53c86a2..a13c96518341 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -463,7 +463,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { None } - // FIXME: Remove once rustc_hir_typeck is migrated to Diagnostics + // FIXME: Remove once `rustc_hir_typeck` is migrated to diagnostic structs pub fn should_suggest_as_ref(&self, expected: Ty<'tcx>, found: Ty<'tcx>) -> Option<&str> { match self.should_suggest_as_ref_kind(expected, found) { Some(SuggestAsRefKind::Option) => Some( From aa33a6fca27f0b9183146e191ba565e37e7644eb Mon Sep 17 00:00:00 2001 From: IQuant Date: Thu, 9 Mar 2023 21:06:44 +0300 Subject: [PATCH 107/272] Move and document escape_literal function --- .../src/infer/error_reporting/mod.rs | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 4b7f4fe1aaa5..212fea47437d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -89,6 +89,28 @@ pub use need_type_info::TypeAnnotationNeeded; pub mod nice_region_error; +/// Makes a valid string literal from a string by escaping special characters (" and \), +/// unless they are already escaped. +fn escape_literal(s: &str) -> String { + let mut escaped = String::with_capacity(s.len()); + let mut chrs = s.chars().peekable(); + while let Some(first) = chrs.next() { + match (first, chrs.peek()) { + ('\\', Some(&delim @ '"') | Some(&delim @ '\'')) => { + escaped.push('\\'); + escaped.push(delim); + chrs.next(); + } + ('"' | '\'', _) => { + escaped.push('\\'); + escaped.push(first) + } + (c, _) => escaped.push(c), + }; + } + escaped +} + /// A helper for building type related errors. The `typeck_results` /// field is only populated during an in-progress typeck. /// Get an instance by calling `InferCtxt::err` or `FnCtxt::infer_err`. @@ -1904,25 +1926,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { terr: TypeError<'tcx>, ) -> Vec { use crate::traits::ObligationCauseCode::MatchExpressionArm; - fn escape_literal(s: &str) -> String { - let mut escaped = String::with_capacity(s.len()); - let mut chrs = s.chars().peekable(); - while let Some(first) = chrs.next() { - match (first, chrs.peek()) { - ('\\', Some(&delim @ '"') | Some(&delim @ '\'')) => { - escaped.push('\\'); - escaped.push(delim); - chrs.next(); - } - ('"' | '\'', _) => { - escaped.push('\\'); - escaped.push(first) - } - (c, _) => escaped.push(c), - }; - } - escaped - } let mut suggestions = Vec::new(); let span = trace.cause.span(); if let Some((expected, found)) = trace.values.ty() { From fd18d9a584230ad696302157dac1a1a38f1bda31 Mon Sep 17 00:00:00 2001 From: IQuant Date: Thu, 9 Mar 2023 21:27:42 +0300 Subject: [PATCH 108/272] Renamed TypeErrorAdditionalDiags (was Error0308Subdiags) and ObligationCauseFailureCode (was FailureCodeDiagnostics) --- compiler/rustc_infer/src/errors/mod.rs | 28 ++++----- .../src/infer/error_reporting/mod.rs | 62 ++++++++++--------- .../src/infer/error_reporting/suggest.rs | 10 +-- 3 files changed, 52 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index f3bed305f84a..2a5d3516c28f 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1361,7 +1361,7 @@ impl AddToDiagnostic for SuggestTuplePatternMany { } #[derive(Subdiagnostic)] -pub enum Error0308Subdiags { +pub enum TypeErrorAdditionalDiags { #[suggestion( infer_meant_byte_literal, code = "b'{code}'", @@ -1429,48 +1429,48 @@ pub enum Error0308Subdiags { } #[derive(Diagnostic)] -pub enum FailureCodeDiagnostics { +pub enum ObligationCauseFailureCode { #[diag(infer_oc_method_compat, code = "E0308")] MethodCompat { #[primary_span] span: Span, #[subdiagnostic] - subdiags: Vec, + subdiags: Vec, }, #[diag(infer_oc_type_compat, code = "E0308")] TypeCompat { #[primary_span] span: Span, #[subdiagnostic] - subdiags: Vec, + subdiags: Vec, }, #[diag(infer_oc_const_compat, code = "E0308")] ConstCompat { #[primary_span] span: Span, #[subdiagnostic] - subdiags: Vec, + subdiags: Vec, }, #[diag(infer_oc_try_compat, code = "E0308")] TryCompat { #[primary_span] span: Span, #[subdiagnostic] - subdiags: Vec, + subdiags: Vec, }, #[diag(infer_oc_match_compat, code = "E0308")] MatchCompat { #[primary_span] span: Span, #[subdiagnostic] - subdiags: Vec, + subdiags: Vec, }, #[diag(infer_oc_if_else_different, code = "E0308")] IfElseDifferent { #[primary_span] span: Span, #[subdiagnostic] - subdiags: Vec, + subdiags: Vec, }, #[diag(infer_oc_no_else, code = "E0317")] NoElse { @@ -1482,7 +1482,7 @@ pub enum FailureCodeDiagnostics { #[primary_span] span: Span, #[subdiagnostic] - subdiags: Vec, + subdiags: Vec, }, #[diag(infer_oc_fn_main_correct_type, code = "E0580")] FnMainCorrectType { @@ -1494,21 +1494,21 @@ pub enum FailureCodeDiagnostics { #[primary_span] span: Span, #[subdiagnostic] - subdiags: Vec, + subdiags: Vec, }, #[diag(infer_oc_intristic_correct_type, code = "E0308")] IntristicCorrectType { #[primary_span] span: Span, #[subdiagnostic] - subdiags: Vec, + subdiags: Vec, }, #[diag(infer_oc_method_correct_type, code = "E0308")] MethodCorrectType { #[primary_span] span: Span, #[subdiagnostic] - subdiags: Vec, + subdiags: Vec, }, #[diag(infer_oc_closure_selfref, code = "E0644")] ClosureSelfref { @@ -1520,13 +1520,13 @@ pub enum FailureCodeDiagnostics { #[primary_span] span: Span, #[subdiagnostic] - subdiags: Vec, + subdiags: Vec, }, #[diag(infer_oc_generic, code = "E0308")] Generic { #[primary_span] span: Span, #[subdiagnostic] - subdiags: Vec, + subdiags: Vec, }, } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 212fea47437d..1cb901be4e98 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -49,7 +49,7 @@ use super::lexical_region_resolve::RegionResolutionError; use super::region_constraints::GenericKind; use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs}; -use crate::errors::{self, Error0308Subdiags, FailureCodeDiagnostics}; +use crate::errors::{self, ObligationCauseFailureCode, TypeErrorAdditionalDiags}; use crate::infer; use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type; use crate::infer::ExpectedFound; @@ -1924,7 +1924,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, trace: &TypeTrace<'tcx>, terr: TypeError<'tcx>, - ) -> Vec { + ) -> Vec { use crate::traits::ObligationCauseCode::MatchExpressionArm; let mut suggestions = Vec::new(); let span = trace.cause.span(); @@ -1946,7 +1946,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && !code.starts_with("\\u") // forbid all Unicode escapes && code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII { - suggestions.push(Error0308Subdiags::MeantByteLiteral { span, code: escape_literal(code) }) + suggestions.push(TypeErrorAdditionalDiags::MeantByteLiteral { span, code: escape_literal(code) }) } } // If a character was expected and the found expression is a string literal @@ -1957,7 +1957,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && let Some(code) = code.strip_prefix('"').and_then(|s| s.strip_suffix('"')) && code.chars().count() == 1 { - suggestions.push(Error0308Subdiags::MeantCharLiteral { span, code: escape_literal(code) }) + suggestions.push(TypeErrorAdditionalDiags::MeantCharLiteral { span, code: escape_literal(code) }) } } // If a string was expected and the found expression is a character literal, @@ -1967,7 +1967,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) { - suggestions.push(Error0308Subdiags::MeantStrLiteral { span, code: escape_literal(code) }) + suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral { span, code: escape_literal(code) }) } } } @@ -2032,7 +2032,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length && let Some(span) = self.tcx.hir().opt_span(*hir_id) { - suggestions.push(Error0308Subdiags::ConsiderSpecifyingLength { span, length: sz.found }); + suggestions.push(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { span, length: sz.found }); } } _ => {} @@ -2043,7 +2043,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && let hir::MatchSource::TryDesugar = source && let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values) { - suggestions.push(Error0308Subdiags::TryCannotConvert { found: found_ty.content(), expected: expected_ty.content() }); + suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert { found: found_ty.content(), expected: expected_ty.content() }); } suggestions } @@ -2071,7 +2071,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span: Span, found: Ty<'tcx>, expected_fields: &List>, - ) -> Option { + ) -> Option { let [expected_tup_elem] = expected_fields[..] else { return None}; if !self.same_type_modulo_infer(expected_tup_elem, found) { @@ -2083,9 +2083,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let sugg = if code.starts_with('(') && code.ends_with(')') { let before_close = span.hi() - BytePos::from_u32(1); - Error0308Subdiags::TupleOnlyComma { span: span.with_hi(before_close).shrink_to_hi() } + TypeErrorAdditionalDiags::TupleOnlyComma { + span: span.with_hi(before_close).shrink_to_hi(), + } } else { - Error0308Subdiags::TupleAlsoParentheses { + TypeErrorAdditionalDiags::TupleAlsoParentheses { span_low: span.shrink_to_lo(), span_high: span.shrink_to_hi(), } @@ -2806,8 +2808,8 @@ pub trait ObligationCauseExt<'tcx> { &self, terr: TypeError<'tcx>, span: Span, - subdiags: Vec, - ) -> FailureCodeDiagnostics; + subdiags: Vec, + ) -> ObligationCauseFailureCode; fn as_requirement_str(&self) -> &'static str; } @@ -2840,42 +2842,44 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { &self, terr: TypeError<'tcx>, span: Span, - subdiags: Vec, - ) -> FailureCodeDiagnostics { + subdiags: Vec, + ) -> ObligationCauseFailureCode { use crate::traits::ObligationCauseCode::*; match self.code() { CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => { - FailureCodeDiagnostics::MethodCompat { span, subdiags } + ObligationCauseFailureCode::MethodCompat { span, subdiags } } CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => { - FailureCodeDiagnostics::TypeCompat { span, subdiags } + ObligationCauseFailureCode::TypeCompat { span, subdiags } } CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => { - FailureCodeDiagnostics::ConstCompat { span, subdiags } + ObligationCauseFailureCode::ConstCompat { span, subdiags } } MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source { hir::MatchSource::TryDesugar => { - FailureCodeDiagnostics::TryCompat { span, subdiags } + ObligationCauseFailureCode::TryCompat { span, subdiags } } - _ => FailureCodeDiagnostics::MatchCompat { span, subdiags }, + _ => ObligationCauseFailureCode::MatchCompat { span, subdiags }, }, - IfExpression { .. } => FailureCodeDiagnostics::IfElseDifferent { span, subdiags }, - IfExpressionWithNoElse => FailureCodeDiagnostics::NoElse { span }, - LetElse => FailureCodeDiagnostics::NoDiverge { span, subdiags }, - MainFunctionType => FailureCodeDiagnostics::FnMainCorrectType { span }, - StartFunctionType => FailureCodeDiagnostics::FnStartCorrectType { span, subdiags }, - IntrinsicType => FailureCodeDiagnostics::IntristicCorrectType { span, subdiags }, - MethodReceiver => FailureCodeDiagnostics::MethodCorrectType { span, subdiags }, + IfExpression { .. } => ObligationCauseFailureCode::IfElseDifferent { span, subdiags }, + IfExpressionWithNoElse => ObligationCauseFailureCode::NoElse { span }, + LetElse => ObligationCauseFailureCode::NoDiverge { span, subdiags }, + MainFunctionType => ObligationCauseFailureCode::FnMainCorrectType { span }, + StartFunctionType => ObligationCauseFailureCode::FnStartCorrectType { span, subdiags }, + IntrinsicType => ObligationCauseFailureCode::IntristicCorrectType { span, subdiags }, + MethodReceiver => ObligationCauseFailureCode::MethodCorrectType { span, subdiags }, // In the case where we have no more specific thing to // say, also take a look at the error code, maybe we can // tailor to that. _ => match terr { TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => { - FailureCodeDiagnostics::ClosureSelfref { span } + ObligationCauseFailureCode::ClosureSelfref { span } } - TypeError::IntrinsicCast => FailureCodeDiagnostics::CantCoerce { span, subdiags }, - _ => FailureCodeDiagnostics::Generic { span, subdiags }, + TypeError::IntrinsicCast => { + ObligationCauseFailureCode::CantCoerce { span, subdiags } + } + _ => ObligationCauseFailureCode::Generic { span, subdiags }, }, } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index a13c96518341..82cd05e3d07e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -13,10 +13,10 @@ use rustc_span::{sym, BytePos, Span}; use rustc_target::abi::FieldIdx; use crate::errors::{ - ConsiderAddingAwait, DiagArg, Error0308Subdiags, FnConsiderCasting, FnItemsAreDistinct, - FnUniqTypes, FunctionPointerSuggestion, SuggestAccessingField, SuggestAsRefWhereAppropriate, + ConsiderAddingAwait, DiagArg, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes, + FunctionPointerSuggestion, SuggestAccessingField, SuggestAsRefWhereAppropriate, SuggestBoxingForReturnImplTrait, SuggestRemoveSemiOrReturnBinding, SuggestTuplePatternMany, - SuggestTuplePatternOne, + SuggestTuplePatternOne, TypeErrorAdditionalDiags, }; use super::TypeErrCtxt; @@ -484,7 +484,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, cause: &ObligationCause<'_>, span: Span, - ) -> Option { + ) -> Option { let hir = self.tcx.hir(); if let Some(node) = self.tcx.hir().find_by_def_id(cause.body_id) && let hir::Node::Item(hir::Item { @@ -531,7 +531,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let mut visitor = IfVisitor { err_span: span, found_if: false, result: false }; visitor.visit_body(&body); if visitor.result { - return Some(Error0308Subdiags::AddLetForLetChains{span: span.shrink_to_lo()}); + return Some(TypeErrorAdditionalDiags::AddLetForLetChains{span: span.shrink_to_lo()}); } } None From 6a05cd85adf99445a9064a0bbc71b507fcb3856e Mon Sep 17 00:00:00 2001 From: IQuant Date: Thu, 9 Mar 2023 21:59:40 +0300 Subject: [PATCH 109/272] A more general implementation of `IntoDiagnosticArg` for `Binder` (Also removes `DiagArg`, as it's no longer necessary) --- compiler/rustc_infer/src/errors/mod.rs | 12 ++-------- .../src/infer/error_reporting/suggest.rs | 6 ++--- compiler/rustc_middle/src/ty/sty.rs | 24 +++++++++---------- 3 files changed, 16 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 2a5d3516c28f..b129621130d4 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1146,14 +1146,6 @@ pub struct OpaqueCapturesLifetime<'tcx> { pub opaque_ty: Ty<'tcx>, } -pub struct DiagArg(pub T); - -impl IntoDiagnosticArg for DiagArg { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { - self.0.to_string().into_diagnostic_arg() - } -} - #[derive(Subdiagnostic)] pub enum FunctionPointerSuggestion<'a> { #[suggestion( @@ -1221,7 +1213,7 @@ pub enum FunctionPointerSuggestion<'a> { fn_name: String, #[skip_arg] found_sig: Binder<'a, FnSig<'a>>, - expected_sig: DiagArg>>, + expected_sig: Binder<'a, FnSig<'a>>, }, #[suggestion( infer_fps_cast_both, @@ -1236,7 +1228,7 @@ pub enum FunctionPointerSuggestion<'a> { fn_name: String, #[skip_arg] found_sig: Binder<'a, FnSig<'a>>, - expected_sig: DiagArg>>, + expected_sig: Binder<'a, FnSig<'a>>, }, } diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 82cd05e3d07e..b5aeca12a1f0 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -13,7 +13,7 @@ use rustc_span::{sym, BytePos, Span}; use rustc_target::abi::FieldIdx; use crate::errors::{ - ConsiderAddingAwait, DiagArg, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes, + ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes, FunctionPointerSuggestion, SuggestAccessingField, SuggestAsRefWhereAppropriate, SuggestBoxingForReturnImplTrait, SuggestRemoveSemiOrReturnBinding, SuggestTuplePatternMany, SuggestTuplePatternOne, TypeErrorAdditionalDiags, @@ -379,14 +379,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span, fn_name, found_sig: *found_sig, - expected_sig: DiagArg(*expected_sig), + expected_sig: *expected_sig, } } else { FunctionPointerSuggestion::CastBoth { span, fn_name, found_sig: *found_sig, - expected_sig: DiagArg(*expected_sig), + expected_sig: *expected_sig, } }; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 5ea77833af25..061f26384bd0 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -15,6 +15,7 @@ use hir::def::DefKind; use polonius_engine::Atom; use rustc_data_structures::captures::Captures; use rustc_data_structures::intern::Interned; +use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; @@ -26,7 +27,7 @@ use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use rustc_target::spec::abi::{self, Abi}; use std::borrow::Cow; use std::cmp::Ordering; -use std::fmt; +use std::fmt::{self, Display}; use std::marker::PhantomData; use std::ops::{ControlFlow, Deref, Range}; use ty::util::IntTypeExt; @@ -877,12 +878,6 @@ impl<'tcx> PolyTraitRef<'tcx> { } } -impl rustc_errors::IntoDiagnosticArg for PolyTraitRef<'_> { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { - self.to_string().into_diagnostic_arg() - } -} - /// An existential reference to a trait, where `Self` is erased. /// For example, the trait object `Trait<'a, 'b, X, Y>` is: /// ```ignore (illustrative) @@ -939,12 +934,6 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { } } -impl rustc_errors::IntoDiagnosticArg for PolyExistentialTraitRef<'_> { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { - self.to_string().into_diagnostic_arg() - } -} - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable)] pub enum BoundVariableKind { @@ -1159,6 +1148,15 @@ impl<'tcx, T: IntoIterator> Binder<'tcx, T> { } } +impl<'tcx, T> IntoDiagnosticArg for Binder<'tcx, T> +where + Binder<'tcx, T>: Display, +{ + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + struct SkipBindersAt<'tcx> { tcx: TyCtxt<'tcx>, index: ty::DebruijnIndex, From 21d5bedd5f7564d62096e485f2fcb6a8956f1dec Mon Sep 17 00:00:00 2001 From: IQuant Date: Fri, 10 Mar 2023 19:49:44 +0300 Subject: [PATCH 110/272] Extract suggest_specify_actual_length into a separate function --- .../src/infer/error_reporting/mod.rs | 120 +++++++++--------- 1 file changed, 61 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 1cb901be4e98..3bb4e1c6b299 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1976,65 +1976,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (ty::Bool, ty::Tuple(list)) => if list.len() == 0 { suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span)); } - (ty::Array(_, _), ty::Array(_, _)) => 'block: { - let hir = self.tcx.hir(); - let TypeError::FixedArraySize(sz) = terr else { - break 'block; - }; - let tykind = match hir.find_by_def_id(trace.cause.body_id) { - Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(_, _, body_id), - .. - })) => { - let body = hir.body(*body_id); - struct LetVisitor<'v> { - span: Span, - result: Option<&'v hir::Ty<'v>>, - } - impl<'v> Visitor<'v> for LetVisitor<'v> { - fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) { - if self.result.is_some() { - return; - } - // Find a local statement where the initializer has - // the same span as the error and the type is specified. - if let hir::Stmt { - kind: hir::StmtKind::Local(hir::Local { - init: Some(hir::Expr { - span: init_span, - .. - }), - ty: Some(array_ty), - .. - }), - .. - } = s - && init_span == &self.span { - self.result = Some(*array_ty); - } - } - } - let mut visitor = LetVisitor {span, result: None}; - visitor.visit_body(body); - visitor.result.map(|r| &r.peel_refs().kind) - } - Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Const(ty, _), - .. - })) => { - Some(&ty.peel_refs().kind) - } - _ => None - }; - - if let Some(tykind) = tykind - && let hir::TyKind::Array(_, length) = tykind - && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length - && let Some(span) = self.tcx.hir().opt_span(*hir_id) - { - suggestions.push(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { span, length: sz.found }); - } - } + (ty::Array(_, _), ty::Array(_, _)) => suggestions.extend(self.specify_actual_length(terr, trace, span)), _ => {} } } @@ -2048,6 +1990,66 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { suggestions } + fn specify_actual_length( + &self, + terr: TypeError<'_>, + trace: &TypeTrace<'_>, + span: Span, + ) -> Option { + let hir = self.tcx.hir(); + let TypeError::FixedArraySize(sz) = terr else { + return None; + }; + let tykind = match hir.find_by_def_id(trace.cause.body_id) { + Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) => { + let body = hir.body(*body_id); + struct LetVisitor<'v> { + span: Span, + result: Option<&'v hir::Ty<'v>>, + } + impl<'v> Visitor<'v> for LetVisitor<'v> { + fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) { + if self.result.is_some() { + return; + } + // Find a local statement where the initializer has + // the same span as the error and the type is specified. + if let hir::Stmt { + kind: hir::StmtKind::Local(hir::Local { + init: Some(hir::Expr { + span: init_span, + .. + }), + ty: Some(array_ty), + .. + }), + .. + } = s + && init_span == &self.span { + self.result = Some(*array_ty); + } + } + } + let mut visitor = LetVisitor { span, result: None }; + visitor.visit_body(body); + visitor.result.map(|r| &r.peel_refs().kind) + } + Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. })) => { + Some(&ty.peel_refs().kind) + } + _ => None, + }; + if let Some(tykind) = tykind + && let hir::TyKind::Array(_, length) = tykind + && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length + && let Some(span) = self.tcx.hir().opt_span(*hir_id) + { + Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { span, length: sz.found }) + } else { + None + } + } + pub fn report_and_explain_type_error( &self, trace: TypeTrace<'tcx>, From 467d367df75121dd305626ea2fb4459af588d29c Mon Sep 17 00:00:00 2001 From: IQuant Date: Sat, 11 Mar 2023 17:39:14 +0300 Subject: [PATCH 111/272] Rename tuple_wrap_err_subdiag to suggest_wrap_to_build_a_tuple, making it more consistent with similar functions --- compiler/rustc_infer/src/infer/error_reporting/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 3bb4e1c6b299..ca4f1c20b892 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1935,7 +1935,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // parentheses around it, perhaps the user meant to write `(expr,)` to // build a tuple (issue #86100) (ty::Tuple(fields), _) => { - suggestions.extend(self.tuple_wrap_err_subdiag( span, found, fields)) + suggestions.extend(self.suggest_wrap_to_build_a_tuple( span, found, fields)) } // If a byte was expected and the found expression is a char literal // containing a single ASCII character, perhaps the user meant to write `b'c'` to @@ -1976,7 +1976,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (ty::Bool, ty::Tuple(list)) => if list.len() == 0 { suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span)); } - (ty::Array(_, _), ty::Array(_, _)) => suggestions.extend(self.specify_actual_length(terr, trace, span)), + (ty::Array(_, _), ty::Array(_, _)) => suggestions.extend(self.suggest_specify_actual_length(terr, trace, span)), _ => {} } } @@ -1990,7 +1990,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { suggestions } - fn specify_actual_length( + fn suggest_specify_actual_length( &self, terr: TypeError<'_>, trace: &TypeTrace<'_>, @@ -2068,7 +2068,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { diag } - fn tuple_wrap_err_subdiag( + fn suggest_wrap_to_build_a_tuple( &self, span: Span, found: Ty<'tcx>, From 3fb6d6b2f422943cea592f64e4ae8984d6b86f1f Mon Sep 17 00:00:00 2001 From: IQuant Date: Tue, 4 Apr 2023 19:18:34 +0300 Subject: [PATCH 112/272] Now passes tests --- compiler/rustc_infer/src/infer/error_reporting/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index ca4f1c20b892..34dfcea81d18 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1928,7 +1928,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { use crate::traits::ObligationCauseCode::MatchExpressionArm; let mut suggestions = Vec::new(); let span = trace.cause.span(); - if let Some((expected, found)) = trace.values.ty() { + let values = self.resolve_vars_if_possible(trace.values); + if let Some((expected, found)) = values.ty() { match (expected.kind(), found.kind()) { (ty::Tuple(_), ty::Tuple(_)) => {} // If a tuple of length one was expected and the found expression has From 2891d8f72f8e598177c0bf6c1d56ad2e70a1f536 Mon Sep 17 00:00:00 2001 From: "Samuel \"Sam\" Tardieu" Date: Sun, 26 Mar 2023 17:11:34 +0200 Subject: [PATCH 113/272] Make redundant_async_block a more complete late pass This lets us detect more complex situations: `async { x.await }` is simplified into `x` if: - `x` is an expression without side-effect - or `x` is an async block itself In both cases, no part of the `async` expression can be part of a macro expansion. --- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/redundant_async_block.rs | 145 ++++++++++----------- tests/ui/redundant_async_block.fixed | 148 +++++++++++++++++----- tests/ui/redundant_async_block.rs | 148 +++++++++++++++++----- tests/ui/redundant_async_block.stderr | 46 ++++++- 5 files changed, 338 insertions(+), 151 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c9210bf73f89..4638af8da9f3 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -935,7 +935,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(no_mangle_with_rust_abi::NoMangleWithRustAbi)); store.register_late_pass(|_| Box::new(collection_is_never_read::CollectionIsNeverRead)); store.register_late_pass(|_| Box::new(missing_assert_message::MissingAssertMessage)); - store.register_early_pass(|| Box::new(redundant_async_block::RedundantAsyncBlock)); + store.register_late_pass(|_| Box::new(redundant_async_block::RedundantAsyncBlock)); store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped)); store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute)); store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(msrv()))); diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 2d30e77d55de..a0f831764d07 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -1,8 +1,15 @@ -use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet}; -use rustc_ast::ast::{Expr, ExprKind, Stmt, StmtKind}; -use rustc_ast::visit::Visitor as AstVisitor; +use std::ops::ControlFlow; + +use clippy_utils::{ + diagnostics::span_lint_and_sugg, + peel_blocks, + source::{snippet, walk_span_to_context}, + visitors::for_each_expr, +}; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_hir::{AsyncGeneratorKind, Closure, Expr, ExprKind, GeneratorKind, MatchSource}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::{lint::in_external_macro, ty::UpvarCapture}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -14,106 +21,88 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// async fn f() -> i32 { - /// 1 + 2 - /// } - /// + /// let f = async { + /// 1 + 2 + /// }; /// let fut = async { - /// f().await + /// f.await /// }; /// ``` /// Use instead: /// ```rust - /// async fn f() -> i32 { - /// 1 + 2 - /// } - /// - /// let fut = f(); + /// let f = async { + /// 1 + 2 + /// }; + /// let fut = f; /// ``` #[clippy::version = "1.69.0"] pub REDUNDANT_ASYNC_BLOCK, - nursery, + complexity, "`async { future.await }` can be replaced by `future`" } declare_lint_pass!(RedundantAsyncBlock => [REDUNDANT_ASYNC_BLOCK]); -impl EarlyLintPass for RedundantAsyncBlock { - fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if expr.span.from_expansion() { - return; - } - if let ExprKind::Async(_, _, block) = &expr.kind && block.stmts.len() == 1 && - let Some(Stmt { kind: StmtKind::Expr(last), .. }) = block.stmts.last() && - let ExprKind::Await(future) = &last.kind && - !future.span.from_expansion() && - !await_in_expr(future) +impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let span = expr.span; + if !in_external_macro(cx.tcx.sess, span) && + let Some(body_expr) = desugar_async_block(cx, expr) && + let Some(expr) = desugar_await(peel_blocks(body_expr)) && + // The await prefix must not come from a macro as its content could change in the future. + expr.span.ctxt() == body_expr.span.ctxt() && + // An async block does not have immediate side-effects from a `.await` point-of-view. + (!expr.can_have_side_effects() || desugar_async_block(cx, expr).is_some()) && + let Some(shortened_span) = walk_span_to_context(expr.span, span.ctxt()) { - if captures_value(last) { - // If the async block captures variables then there is no equivalence. - return; - } - span_lint_and_sugg( cx, REDUNDANT_ASYNC_BLOCK, - expr.span, + span, "this async expression only awaits a single future", "you can reduce it to", - snippet(cx, future.span, "..").into_owned(), + snippet(cx, shortened_span, "..").into_owned(), Applicability::MachineApplicable, ); } } } -/// Check whether an expression contains `.await` -fn await_in_expr(expr: &Expr) -> bool { - let mut detector = AwaitDetector::default(); - detector.visit_expr(expr); - detector.await_found -} - -#[derive(Default)] -struct AwaitDetector { - await_found: bool, -} - -impl<'ast> AstVisitor<'ast> for AwaitDetector { - fn visit_expr(&mut self, ex: &'ast Expr) { - match (&ex.kind, self.await_found) { - (ExprKind::Await(_), _) => self.await_found = true, - (_, false) => rustc_ast::visit::walk_expr(self, ex), - _ => (), - } +/// If `expr` is a desugared `async` block, return the original expression if it does not capture +/// any variable by ref. +fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { + if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind && + let body = cx.tcx.hir().body(*body) && + matches!(body.generator_kind, Some(GeneratorKind::Async(AsyncGeneratorKind::Block))) + { + cx + .typeck_results() + .closure_min_captures + .get(def_id) + .map_or(true, |m| { + m.values().all(|places| { + places + .iter() + .all(|place| matches!(place.info.capture_kind, UpvarCapture::ByValue)) + }) + }) + .then_some(body.value) + } else { + None } } -/// Check whether an expression may have captured a local variable. -/// This is done by looking for paths with only one segment, except as -/// a prefix of `.await` since this would be captured by value. -/// -/// This function will sometimes return `true` even tough there are no -/// captures happening: at the AST level, it is impossible to -/// dinstinguish a function call from a call to a closure which comes -/// from the local environment. -fn captures_value(expr: &Expr) -> bool { - let mut detector = CaptureDetector::default(); - detector.visit_expr(expr); - detector.capture_found -} - -#[derive(Default)] -struct CaptureDetector { - capture_found: bool, -} - -impl<'ast> AstVisitor<'ast> for CaptureDetector { - fn visit_expr(&mut self, ex: &'ast Expr) { - match (&ex.kind, self.capture_found) { - (ExprKind::Await(fut), _) if matches!(fut.kind, ExprKind::Path(..)) => (), - (ExprKind::Path(_, path), _) if path.segments.len() == 1 => self.capture_found = true, - (_, false) => rustc_ast::visit::walk_expr(self, ex), - _ => (), - } +/// If `expr` is a desugared `.await`, return the original expression if it does not come from a +/// macro expansion. +fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { + if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind && + let ExprKind::Call(_, [into_future_arg]) = match_value.kind && + let ctxt = expr.span.ctxt() && + for_each_expr(into_future_arg, |e| + walk_span_to_context(e.span, ctxt) + .map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(()))).is_none() + { + Some(into_future_arg) + } else { + None } } diff --git a/tests/ui/redundant_async_block.fixed b/tests/ui/redundant_async_block.fixed index d26b7a332cbb..ad96993c4a78 100644 --- a/tests/ui/redundant_async_block.fixed +++ b/tests/ui/redundant_async_block.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused)] +#![allow(unused, clippy::manual_async_fn)] #![warn(clippy::redundant_async_block)] use std::future::Future; @@ -16,40 +16,16 @@ async fn func2() -> String { x.await } -macro_rules! await_in_macro { - ($e:expr) => { - std::convert::identity($e).await - }; -} - -async fn func3(n: usize) -> usize { - // Do not lint (suggestion would be `std::convert::identity(func1(n))` - // which copies code from inside the macro) - async move { await_in_macro!(func1(n)) }.await -} - -// This macro should never be linted as `$e` might contain `.await` -macro_rules! async_await_parameter_in_macro { - ($e:expr) => { - async { $e.await } - }; -} - -// MISSED OPPORTUNITY: this macro could be linted as the `async` block does not -// contain code coming from the parameters -macro_rules! async_await_in_macro { - ($f:expr) => { - ($f)(async { func2().await }) - }; -} - fn main() { let fut1 = async { 17 }; + // Lint let fut2 = fut1; let fut1 = async { 25 }; + // Lint let fut2 = fut1; + // Lint let fut = async { 42 }; // Do not lint: not a single expression @@ -60,15 +36,12 @@ fn main() { // Do not lint: expression contains `.await` let fut = async { func1(func2().await.len()).await }; - - let fut = async_await_parameter_in_macro!(func2()); - let fut = async_await_in_macro!(std::convert::identity); } #[allow(clippy::let_and_return)] fn capture_local() -> impl Future { - // Lint let fut = async { 17 }; + // Lint fut } @@ -80,11 +53,39 @@ fn capture_local_closure(s: &str) -> impl Future { #[allow(clippy::let_and_return)] fn capture_arg(s: &str) -> impl Future { - // Lint let fut = async move { s }; + // Lint fut } +fn capture_future_arg(f: impl Future) -> impl Future { + // Lint + f +} + +fn capture_func_result(f: FN) -> impl Future +where + F: Future, + FN: FnOnce() -> F, +{ + // Do not lint, as f() would be evaluated prematurely + async { f().await } +} + +fn double_future(f: impl Future>) -> impl Future { + // Do not lint, we will get a `.await` outside a `.async` + async { f.await.await } +} + +fn await_in_async(f: F) -> impl Future +where + F: FnOnce() -> R, + R: Future, +{ + // Lint + async { f().await + 1 } +} + #[derive(Debug, Clone)] struct F {} @@ -109,3 +110,84 @@ fn capture() { // Do not lint: `val` would not live long enough spawn(async { work(&{ val }).await }); } + +fn await_from_macro() -> impl Future { + macro_rules! mac { + ($e:expr) => { + $e.await + }; + } + // Do not lint: the macro may change in the future + // or return different things depending on its argument + async { mac!(async { 42 }) } +} + +fn async_expr_from_macro() -> impl Future { + macro_rules! mac { + () => { + async { 42 } + }; + } + // Do not lint: the macro may change in the future + async { mac!().await } +} + +fn async_expr_from_macro_deep() -> impl Future { + macro_rules! mac { + () => { + async { 42 } + }; + } + // Do not lint: the macro may change in the future + async { ({ mac!() }).await } +} + +fn all_from_macro() -> impl Future { + macro_rules! mac { + () => { + // Lint + async { 42 } + }; + } + mac!() +} + +fn parts_from_macro() -> impl Future { + macro_rules! mac { + ($e: expr) => { + // Do not lint: `$e` might not always be side-effect free + async { $e.await } + }; + } + mac!(async { 42 }) +} + +fn safe_parts_from_macro() -> impl Future { + macro_rules! mac { + ($e: expr) => { + // Lint + async { $e } + }; + } + mac!(42) +} + +fn parts_from_macro_deep() -> impl Future { + macro_rules! mac { + ($e: expr) => { + // Do not lint: `$e` might not always be side-effect free + async { ($e,).0.await } + }; + } + let f = std::future::ready(42); + mac!(f) +} + +fn await_from_macro_deep() -> impl Future { + macro_rules! mac { + ($e:expr) => {{ $e }.await}; + } + // Do not lint: the macro may change in the future + // or return different things depending on its argument + async { mac!(async { 42 }) } +} diff --git a/tests/ui/redundant_async_block.rs b/tests/ui/redundant_async_block.rs index 04726e628050..7ae235583694 100644 --- a/tests/ui/redundant_async_block.rs +++ b/tests/ui/redundant_async_block.rs @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused)] +#![allow(unused, clippy::manual_async_fn)] #![warn(clippy::redundant_async_block)] use std::future::Future; @@ -16,40 +16,16 @@ async fn func2() -> String { x.await } -macro_rules! await_in_macro { - ($e:expr) => { - std::convert::identity($e).await - }; -} - -async fn func3(n: usize) -> usize { - // Do not lint (suggestion would be `std::convert::identity(func1(n))` - // which copies code from inside the macro) - async move { await_in_macro!(func1(n)) }.await -} - -// This macro should never be linted as `$e` might contain `.await` -macro_rules! async_await_parameter_in_macro { - ($e:expr) => { - async { $e.await } - }; -} - -// MISSED OPPORTUNITY: this macro could be linted as the `async` block does not -// contain code coming from the parameters -macro_rules! async_await_in_macro { - ($f:expr) => { - ($f)(async { func2().await }) - }; -} - fn main() { let fut1 = async { 17 }; + // Lint let fut2 = async { fut1.await }; let fut1 = async { 25 }; + // Lint let fut2 = async move { fut1.await }; + // Lint let fut = async { async { 42 }.await }; // Do not lint: not a single expression @@ -60,15 +36,12 @@ fn main() { // Do not lint: expression contains `.await` let fut = async { func1(func2().await.len()).await }; - - let fut = async_await_parameter_in_macro!(func2()); - let fut = async_await_in_macro!(std::convert::identity); } #[allow(clippy::let_and_return)] fn capture_local() -> impl Future { - // Lint let fut = async { 17 }; + // Lint async move { fut.await } } @@ -80,11 +53,39 @@ fn capture_local_closure(s: &str) -> impl Future { #[allow(clippy::let_and_return)] fn capture_arg(s: &str) -> impl Future { - // Lint let fut = async move { s }; + // Lint async move { fut.await } } +fn capture_future_arg(f: impl Future) -> impl Future { + // Lint + async { f.await } +} + +fn capture_func_result(f: FN) -> impl Future +where + F: Future, + FN: FnOnce() -> F, +{ + // Do not lint, as f() would be evaluated prematurely + async { f().await } +} + +fn double_future(f: impl Future>) -> impl Future { + // Do not lint, we will get a `.await` outside a `.async` + async { f.await.await } +} + +fn await_in_async(f: F) -> impl Future +where + F: FnOnce() -> R, + R: Future, +{ + // Lint + async { async { f().await + 1 }.await } +} + #[derive(Debug, Clone)] struct F {} @@ -109,3 +110,84 @@ fn capture() { // Do not lint: `val` would not live long enough spawn(async { work(&{ val }).await }); } + +fn await_from_macro() -> impl Future { + macro_rules! mac { + ($e:expr) => { + $e.await + }; + } + // Do not lint: the macro may change in the future + // or return different things depending on its argument + async { mac!(async { 42 }) } +} + +fn async_expr_from_macro() -> impl Future { + macro_rules! mac { + () => { + async { 42 } + }; + } + // Do not lint: the macro may change in the future + async { mac!().await } +} + +fn async_expr_from_macro_deep() -> impl Future { + macro_rules! mac { + () => { + async { 42 } + }; + } + // Do not lint: the macro may change in the future + async { ({ mac!() }).await } +} + +fn all_from_macro() -> impl Future { + macro_rules! mac { + () => { + // Lint + async { async { 42 }.await } + }; + } + mac!() +} + +fn parts_from_macro() -> impl Future { + macro_rules! mac { + ($e: expr) => { + // Do not lint: `$e` might not always be side-effect free + async { $e.await } + }; + } + mac!(async { 42 }) +} + +fn safe_parts_from_macro() -> impl Future { + macro_rules! mac { + ($e: expr) => { + // Lint + async { async { $e }.await } + }; + } + mac!(42) +} + +fn parts_from_macro_deep() -> impl Future { + macro_rules! mac { + ($e: expr) => { + // Do not lint: `$e` might not always be side-effect free + async { ($e,).0.await } + }; + } + let f = std::future::ready(42); + mac!(f) +} + +fn await_from_macro_deep() -> impl Future { + macro_rules! mac { + ($e:expr) => {{ $e }.await}; + } + // Do not lint: the macro may change in the future + // or return different things depending on its argument + async { mac!(async { 42 }) } +} diff --git a/tests/ui/redundant_async_block.stderr b/tests/ui/redundant_async_block.stderr index 1a1c1603e080..f3dcb09b4440 100644 --- a/tests/ui/redundant_async_block.stderr +++ b/tests/ui/redundant_async_block.stderr @@ -7,34 +7,68 @@ LL | let x = async { f.await }; = note: `-D clippy::redundant-async-block` implied by `-D warnings` error: this async expression only awaits a single future - --> $DIR/redundant_async_block.rs:48:16 + --> $DIR/redundant_async_block.rs:22:16 | LL | let fut2 = async { fut1.await }; | ^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut1` error: this async expression only awaits a single future - --> $DIR/redundant_async_block.rs:51:16 + --> $DIR/redundant_async_block.rs:26:16 | LL | let fut2 = async move { fut1.await }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut1` error: this async expression only awaits a single future - --> $DIR/redundant_async_block.rs:53:15 + --> $DIR/redundant_async_block.rs:29:15 | LL | let fut = async { async { 42 }.await }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `async { 42 }` error: this async expression only awaits a single future - --> $DIR/redundant_async_block.rs:72:5 + --> $DIR/redundant_async_block.rs:45:5 | LL | async move { fut.await } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut` error: this async expression only awaits a single future - --> $DIR/redundant_async_block.rs:85:5 + --> $DIR/redundant_async_block.rs:58:5 | LL | async move { fut.await } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut` -error: aborting due to 6 previous errors +error: this async expression only awaits a single future + --> $DIR/redundant_async_block.rs:63:5 + | +LL | async { f.await } + | ^^^^^^^^^^^^^^^^^ help: you can reduce it to: `f` + +error: this async expression only awaits a single future + --> $DIR/redundant_async_block.rs:86:5 + | +LL | async { async { f().await + 1 }.await } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `async { f().await + 1 }` + +error: this async expression only awaits a single future + --> $DIR/redundant_async_block.rs:149:13 + | +LL | async { async { 42 }.await } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `async { 42 }` +... +LL | mac!() + | ------ in this macro invocation + | + = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: this async expression only awaits a single future + --> $DIR/redundant_async_block.rs:169:13 + | +LL | async { async { $e }.await } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `async { $e }` +... +LL | mac!(42) + | -------- in this macro invocation + | + = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 10 previous errors From b499b7dc73f3571e2627a34a93e3079cab848bbc Mon Sep 17 00:00:00 2001 From: feniljain Date: Wed, 5 Apr 2023 19:50:12 +0530 Subject: [PATCH 114/272] test: add test for match as stmt no triggering needless_return --- tests/ui/needless_return.fixed | 9 +++++++++ tests/ui/needless_return.rs | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 38ae448618c0..47a9f031a42c 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -307,4 +307,13 @@ mod issue10049 { } } +fn test_match_as_stmt() { + let x = 9; + match x { + 1 => 2, + 2 => return, + _ => 0, + }; +} + fn main() {} diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index a1db8375d95b..7c1feefbe32b 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -317,4 +317,13 @@ mod issue10049 { } } +fn test_match_as_stmt() { + let x = 9; + match x { + 1 => 2, + 2 => return, + _ => 0, + }; +} + fn main() {} From 5f52a96b85cf574f083b796d4d61b6d19461694b Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 5 Apr 2023 16:21:50 +0200 Subject: [PATCH 115/272] incr.comp.: Don't ignore dep-tracking during HirId validation. --- compiler/rustc_passes/src/hir_id_validator.rs | 52 +++++++++---------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index 49aa1da01a23..3942a73befdc 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -8,34 +8,32 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; pub fn check_crate(tcx: TyCtxt<'_>) { - tcx.dep_graph.with_ignore(|| { - if tcx.sess.opts.unstable_opts.hir_stats { - crate::hir_stats::print_hir_stats(tcx); + if tcx.sess.opts.unstable_opts.hir_stats { + crate::hir_stats::print_hir_stats(tcx); + } + + #[cfg(debug_assertions)] + { + let errors = Lock::new(Vec::new()); + + tcx.hir().par_for_each_module(|module_id| { + let mut v = HirIdValidator { + tcx, + owner: None, + hir_ids_seen: Default::default(), + errors: &errors, + }; + + tcx.hir().visit_item_likes_in_module(module_id, &mut v); + }); + + let errors = errors.into_inner(); + + if !errors.is_empty() { + let message = errors.iter().fold(String::new(), |s1, s2| s1 + "\n" + s2); + tcx.sess.delay_span_bug(rustc_span::DUMMY_SP, &message); } - - #[cfg(debug_assertions)] - { - let errors = Lock::new(Vec::new()); - - tcx.hir().par_for_each_module(|module_id| { - let mut v = HirIdValidator { - tcx, - owner: None, - hir_ids_seen: Default::default(), - errors: &errors, - }; - - tcx.hir().visit_item_likes_in_module(module_id, &mut v); - }); - - let errors = errors.into_inner(); - - if !errors.is_empty() { - let message = errors.iter().fold(String::new(), |s1, s2| s1 + "\n" + s2); - tcx.sess.delay_span_bug(rustc_span::DUMMY_SP, &message); - } - } - }) + } } struct HirIdValidator<'a, 'hir> { From 9cf57d0a8f95c51b0faeda4ce5c5b4cd629f1cae Mon Sep 17 00:00:00 2001 From: feniljain Date: Wed, 5 Apr 2023 20:03:45 +0530 Subject: [PATCH 116/272] fix(needles_return): correct span selection for text replacement --- clippy_lints/src/returns.rs | 2 +- tests/ui/needless_return.fixed | 6 +++--- tests/ui/needless_return.stderr | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index b8172b74dc01..df126d7617eb 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -286,7 +286,7 @@ fn check_final_expr<'tcx>( ExprKind::Match(_, arms, MatchSource::Normal) => { let match_ty = cx.typeck_results().expr_ty(peeled_drop_expr); for arm in arms.iter() { - check_final_expr(cx, arm.body, semi_spans.clone(), RetReplacement::Empty, Some(match_ty)); + check_final_expr(cx, arm.body, semi_spans.clone(), RetReplacement::Unit, Some(match_ty)); } }, // if it's a whole block, check it diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 47a9f031a42c..57c08996ce25 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -81,7 +81,7 @@ fn test_void_if_fun(b: bool) { fn test_void_match(x: u32) { match x { 0 => (), - _ =>(), + _ => (), } } @@ -91,7 +91,7 @@ fn test_nested_match(x: u32) { 1 => { let _ = 42; }, - _ =>(), + _ => (), } } @@ -196,7 +196,7 @@ async fn async_test_void_if_fun(b: bool) { async fn async_test_void_match(x: u32) { match x { 0 => (), - _ =>(), + _ => (), } } diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 5d471a3c5214..87d0cd3e14cf 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -118,10 +118,10 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:87:13 + --> $DIR/needless_return.rs:87:14 | LL | _ => return, - | ^^^^^^^ + | ^^^^^^ | = help: replace `return` with a unit value @@ -136,10 +136,10 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:98:13 + --> $DIR/needless_return.rs:98:14 | LL | _ => return, - | ^^^^^^^ + | ^^^^^^ | = help: replace `return` with a unit value @@ -296,10 +296,10 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:207:13 + --> $DIR/needless_return.rs:207:14 | LL | _ => return, - | ^^^^^^^ + | ^^^^^^ | = help: replace `return` with a unit value From 008e07d4e8e434933e1ba25a5c324a3a9d46dd7b Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Thu, 6 Apr 2023 16:16:22 +0800 Subject: [PATCH 117/272] fix [mem_replace_option_with_none] not considering field variables --- clippy_lints/src/mem_replace.rs | 71 +++++++++++++-------------------- tests/ui/mem_replace.fixed | 34 ++++++++++++++++ tests/ui/mem_replace.rs | 34 ++++++++++++++++ tests/ui/mem_replace.stderr | 26 +++++++++++- 4 files changed, 121 insertions(+), 44 deletions(-) diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 35024ec1224f..8a921d4af165 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,12 +1,13 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_non_aggregate_primitive_type; -use clippy_utils::{is_default_equivalent, is_res_lang_ctor, path_res}; +use clippy_utils::{is_default_equivalent, is_res_lang_ctor, path_res, peel_ref_operators}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; -use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath}; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -101,40 +102,26 @@ declare_clippy_lint! { impl_lint_pass!(MemReplace => [MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_WITH_UNINIT, MEM_REPLACE_WITH_DEFAULT]); -fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { - // Check that second argument is `Option::None` - if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) { - // Since this is a late pass (already type-checked), - // and we already know that the second argument is an - // `Option`, we do not need to check the first - // argument's type. All that's left is to get - // replacee's path. - let replaced_path = match dest.kind { - ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, replaced) => { - if let ExprKind::Path(QPath::Resolved(None, replaced_path)) = replaced.kind { - replaced_path - } else { - return; - } - }, - ExprKind::Path(QPath::Resolved(None, replaced_path)) => replaced_path, - _ => return, - }; - - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - MEM_REPLACE_OPTION_WITH_NONE, - expr_span, - "replacing an `Option` with `None`", - "consider `Option::take()` instead", - format!( - "{}.take()", - snippet_with_applicability(cx, replaced_path.span, "", &mut applicability) - ), - applicability, - ); - } +fn check_replace_option_with_none(cx: &LateContext<'_>, dest: &Expr<'_>, expr_span: Span) { + // Since this is a late pass (already type-checked), + // and we already know that the second argument is an + // `Option`, we do not need to check the first + // argument's type. All that's left is to get + // the replacee's expr after peeling off the `&mut` + let sugg_expr = peel_ref_operators(cx, dest); + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + MEM_REPLACE_OPTION_WITH_NONE, + expr_span, + "replacing an `Option` with `None`", + "consider `Option::take()` instead", + format!( + "{}.take()", + Sugg::hir_with_context(cx, sugg_expr, expr_span.ctxt(), "", &mut applicability).maybe_par() + ), + applicability, + ); } fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { @@ -200,10 +187,6 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< if is_non_aggregate_primitive_type(expr_type) { return; } - // disable lint for Option since it is covered in another lint - if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) { - return; - } if is_default_equivalent(cx, src) && !in_external_macro(cx.tcx.sess, expr_span) { span_lint_and_then( cx, @@ -246,11 +229,13 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace { if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); if cx.tcx.is_diagnostic_item(sym::mem_replace, def_id); then { - check_replace_option_with_none(cx, src, dest, expr.span); - check_replace_with_uninit(cx, src, dest, expr.span); - if self.msrv.meets(msrvs::MEM_TAKE) { + // Check that second argument is `Option::None` + if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) { + check_replace_option_with_none(cx, dest, expr.span); + } else if self.msrv.meets(msrvs::MEM_TAKE) { check_replace_with_default(cx, src, dest, expr.span); } + check_replace_with_uninit(cx, src, dest, expr.span); } } } diff --git a/tests/ui/mem_replace.fixed b/tests/ui/mem_replace.fixed index 874d55843303..7fd340173af9 100644 --- a/tests/ui/mem_replace.fixed +++ b/tests/ui/mem_replace.fixed @@ -90,3 +90,37 @@ fn msrv_1_40() { let mut s = String::from("foo"); let _ = std::mem::take(&mut s); } + +fn issue9824() { + struct Foo<'a>(Option<&'a str>); + impl<'a> std::ops::Deref for Foo<'a> { + type Target = Option<&'a str>; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl<'a> std::ops::DerefMut for Foo<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + struct Bar { + opt: Option, + val: String, + } + + let mut f = Foo(Some("foo")); + let mut b = Bar { + opt: Some(1), + val: String::from("bar"), + }; + + // replace option with none + let _ = f.0.take(); + let _ = (*f).take(); + let _ = b.opt.take(); + // replace with default + let _ = std::mem::take(&mut b.val); +} diff --git a/tests/ui/mem_replace.rs b/tests/ui/mem_replace.rs index f4f3bff51446..fa2903addbc0 100644 --- a/tests/ui/mem_replace.rs +++ b/tests/ui/mem_replace.rs @@ -90,3 +90,37 @@ fn msrv_1_40() { let mut s = String::from("foo"); let _ = std::mem::replace(&mut s, String::default()); } + +fn issue9824() { + struct Foo<'a>(Option<&'a str>); + impl<'a> std::ops::Deref for Foo<'a> { + type Target = Option<&'a str>; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl<'a> std::ops::DerefMut for Foo<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + struct Bar { + opt: Option, + val: String, + } + + let mut f = Foo(Some("foo")); + let mut b = Bar { + opt: Some(1), + val: String::from("bar"), + }; + + // replace option with none + let _ = std::mem::replace(&mut f.0, None); + let _ = std::mem::replace(&mut *f, None); + let _ = std::mem::replace(&mut b.opt, None); + // replace with default + let _ = std::mem::replace(&mut b.val, String::default()); +} diff --git a/tests/ui/mem_replace.stderr b/tests/ui/mem_replace.stderr index caa127f76eef..58b57be75070 100644 --- a/tests/ui/mem_replace.stderr +++ b/tests/ui/mem_replace.stderr @@ -122,5 +122,29 @@ error: replacing a value of type `T` with `T::default()` is better expressed usi LL | let _ = std::mem::replace(&mut s, String::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)` -error: aborting due to 20 previous errors +error: replacing an `Option` with `None` + --> $DIR/mem_replace.rs:121:13 + | +LL | let _ = std::mem::replace(&mut f.0, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `f.0.take()` + +error: replacing an `Option` with `None` + --> $DIR/mem_replace.rs:122:13 + | +LL | let _ = std::mem::replace(&mut *f, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `(*f).take()` + +error: replacing an `Option` with `None` + --> $DIR/mem_replace.rs:123:13 + | +LL | let _ = std::mem::replace(&mut b.opt, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `b.opt.take()` + +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> $DIR/mem_replace.rs:125:13 + | +LL | let _ = std::mem::replace(&mut b.val, String::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut b.val)` + +error: aborting due to 24 previous errors From fa425061e641429cc63fcd02b0c42694cd74dfc6 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 6 Apr 2023 12:32:47 +0200 Subject: [PATCH 118/272] Bump nightly version -> 2023-04-06 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 0b2458ea0070..91e8ccea1f43 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-03-24" +channel = "nightly-2023-04-06" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] From b66aa09b951dace249fad3376c2d97c95d11b6a9 Mon Sep 17 00:00:00 2001 From: Michael Schubart Date: Sun, 19 Mar 2023 09:29:32 +0000 Subject: [PATCH 119/272] Add [`manual_slice_size_calculation`] --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + .../src/manual_slice_size_calculation.rs | 90 +++++++++++++++++++ tests/ui/manual_slice_size_calculation.rs | 30 +++++++ tests/ui/manual_slice_size_calculation.stderr | 27 ++++++ 6 files changed, 151 insertions(+) create mode 100644 clippy_lints/src/manual_slice_size_calculation.rs create mode 100644 tests/ui/manual_slice_size_calculation.rs create mode 100644 tests/ui/manual_slice_size_calculation.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index ba10cb53ec92..f615b27bf688 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4674,6 +4674,7 @@ Released 2018-09-13 [`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_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 [`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat [`manual_string_new`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_string_new diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index b45105570335..09ae6b8ee571 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -269,6 +269,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO, crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO, crate::manual_retain::MANUAL_RETAIN_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, crate::map_unit_fn::OPTION_MAP_UNIT_FN_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 82d63ddca6d7..f842e629c53c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -186,6 +186,7 @@ mod manual_main_separator_str; mod manual_non_exhaustive; mod manual_rem_euclid; mod manual_retain; +mod manual_slice_size_calculation; mod manual_string_new; mod manual_strip; mod map_unit_fn; @@ -957,6 +958,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }); store.register_late_pass(|_| Box::new(lines_filter_map_ok::LinesFilterMapOk)); store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule)); + store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/manual_slice_size_calculation.rs b/clippy_lints/src/manual_slice_size_calculation.rs new file mode 100644 index 000000000000..2659f347778c --- /dev/null +++ b/clippy_lints/src/manual_slice_size_calculation.rs @@ -0,0 +1,90 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::in_constant; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::sym; + +declare_clippy_lint! { + /// ### What it does + /// When `a` is `&[T]`, detect `a.len() * size_of::()` and suggest `size_of_val(a)` + /// instead. + /// + /// ### Why is this better? + /// * Shorter to write + /// * Removes the need for the human and the compiler to worry about overflow in the + /// multiplication + /// * Potentially faster at runtime as rust emits special no-wrapping flags when it + /// calculates the byte length + /// * Less turbofishing + /// + /// ### Example + /// ```rust + /// # let data : &[i32] = &[1, 2, 3]; + /// let newlen = data.len() * std::mem::size_of::(); + /// ``` + /// Use instead: + /// ```rust + /// # let data : &[i32] = &[1, 2, 3]; + /// let newlen = std::mem::size_of_val(data); + /// ``` + #[clippy::version = "1.70.0"] + pub MANUAL_SLICE_SIZE_CALCULATION, + complexity, + "manual slice size calculation" +} +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_value is not cost in stable. + if !in_constant(cx, expr.hir_id) + && let ExprKind::Binary(ref op, left, right) = expr.kind + && BinOpKind::Mul == op.node + && let Some(_receiver) = simplify(cx, left, right) + { + span_lint_and_help( + cx, + MANUAL_SLICE_SIZE_CALCULATION, + expr.span, + "manual slice size calculation", + None, + "consider using std::mem::size_of_value instead"); + } + } +} + +fn simplify<'tcx>( + cx: &LateContext<'tcx>, + expr1: &'tcx Expr<'tcx>, + expr2: &'tcx Expr<'tcx>, +) -> Option<&'tcx Expr<'tcx>> { + simplify_half(cx, expr1, expr2).or_else(|| simplify_half(cx, expr2, expr1)) +} + +fn simplify_half<'tcx>( + cx: &LateContext<'tcx>, + expr1: &'tcx Expr<'tcx>, + expr2: &'tcx Expr<'tcx>, +) -> Option<&'tcx Expr<'tcx>> { + if + // expr1 is `[T1].len()`? + let ExprKind::MethodCall(method_path, receiver, _, _) = expr1.kind + && method_path.ident.name == sym::len + && let receiver_ty = cx.typeck_results().expr_ty(receiver) + && let ty::Slice(ty1) = receiver_ty.peel_refs().kind() + // expr2 is `size_of::()`? + && let ExprKind::Call(func, _) = expr2.kind + && let ExprKind::Path(ref func_qpath) = func.kind + && let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id() + && cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id) + && let Some(ty2) = cx.typeck_results().node_substs(func.hir_id).types().next() + // T1 == T2? + && *ty1 == ty2 + { + Some(receiver) + } else { + None + } +} diff --git a/tests/ui/manual_slice_size_calculation.rs b/tests/ui/manual_slice_size_calculation.rs new file mode 100644 index 000000000000..8ec4ae0aed73 --- /dev/null +++ b/tests/ui/manual_slice_size_calculation.rs @@ -0,0 +1,30 @@ +#![allow(unused)] +#![warn(clippy::manual_slice_size_calculation)] + +use core::mem::{align_of, size_of}; + +fn main() { + let v_i32 = Vec::::new(); + let s_i32 = v_i32.as_slice(); + + // True positives: + let _ = s_i32.len() * size_of::(); // WARNING + let _ = size_of::() * s_i32.len(); // WARNING + let _ = size_of::() * s_i32.len() * 5; // WARNING + + // True negatives: + let _ = size_of::() + s_i32.len(); // Ok, not a multiplication + let _ = size_of::() * s_i32.partition_point(|_| true); // Ok, not len() + let _ = size_of::() * v_i32.len(); // Ok, not a slice + let _ = align_of::() * s_i32.len(); // Ok, not size_of() + let _ = size_of::() * s_i32.len(); // Ok, different types + + // False negatives: + let _ = 5 * size_of::() * s_i32.len(); // Ok (MISSED OPPORTUNITY) + let _ = size_of::() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY) +} + +const fn _const(s_i32: &[i32]) { + // True negative: + let _ = s_i32.len() * size_of::(); // Ok, can't use size_of_val in const +} diff --git a/tests/ui/manual_slice_size_calculation.stderr b/tests/ui/manual_slice_size_calculation.stderr new file mode 100644 index 000000000000..33de9fad4d38 --- /dev/null +++ b/tests/ui/manual_slice_size_calculation.stderr @@ -0,0 +1,27 @@ +error: manual slice size calculation + --> $DIR/manual_slice_size_calculation.rs:11:13 + | +LL | let _ = s_i32.len() * size_of::(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using std::mem::size_of_value instead + = note: `-D clippy::manual-slice-size-calculation` implied by `-D warnings` + +error: manual slice size calculation + --> $DIR/manual_slice_size_calculation.rs:12:13 + | +LL | let _ = size_of::() * s_i32.len(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using std::mem::size_of_value instead + +error: manual slice size calculation + --> $DIR/manual_slice_size_calculation.rs:13:13 + | +LL | let _ = size_of::() * s_i32.len() * 5; // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using std::mem::size_of_value instead + +error: aborting due to 3 previous errors + From b47a322ef11e541231b18c67dfe133dac8764b11 Mon Sep 17 00:00:00 2001 From: Michael Schubart Date: Thu, 6 Apr 2023 13:45:50 +0100 Subject: [PATCH 120/272] Add tests suggested by @llogiq --- tests/ui/manual_slice_size_calculation.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/ui/manual_slice_size_calculation.rs b/tests/ui/manual_slice_size_calculation.rs index 8ec4ae0aed73..2cb8c4c2ad3e 100644 --- a/tests/ui/manual_slice_size_calculation.rs +++ b/tests/ui/manual_slice_size_calculation.rs @@ -22,6 +22,12 @@ fn main() { // False negatives: let _ = 5 * size_of::() * s_i32.len(); // Ok (MISSED OPPORTUNITY) let _ = size_of::() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY) + + let len = s_i32.len(); + let size = size_of::(); + let _ = len * size_of::(); // Ok (MISSED OPPORTUNITY) + let _ = s_i32.len() * size; // Ok (MISSED OPPORTUNITY) + let _ = len * size; // Ok (MISSED OPPORTUNITY) } const fn _const(s_i32: &[i32]) { From be4416923d2f88a845eb5ea49b1daac9517935b8 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Thu, 6 Apr 2023 18:02:52 +0100 Subject: [PATCH 121/272] Collapse if statements, change message to lowercase --- compiler/rustc_resolve/src/macros.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index b595dc068018..ed479d289d78 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -548,12 +548,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { err.span_label(path.span, format!("not {} {}", article, expected)); - if !path.span.from_expansion() { - // Suggest moving the macro out of the derive() as the macro isn't Derive - if kind == MacroKind::Derive && ext.macro_kind() != MacroKind::Derive { - err.span_help(path.span, "Remove from the surrounding `derive()`"); - err.help(format!("Add as non-Derive macro\n`#[{}]`", path_str)); - } + // Suggest moving the macro out of the derive() as the macro isn't Derive + if !path.span.from_expansion() + && kind == MacroKind::Derive + && ext.macro_kind() != MacroKind::Derive + { + err.span_help(path.span, "remove from the surrounding `derive()`"); + err.help(format!("add as non-Derive macro\n`#[{}]`", path_str)); } err.emit(); From 7944930b0908cecfd58a47ca2b7b2b42136ada14 Mon Sep 17 00:00:00 2001 From: James Farrell Date: Thu, 6 Apr 2023 18:53:29 +0000 Subject: [PATCH 122/272] Pass host linker to compiletest. Tests marked `// force-host` were using the default linker, even if a custom linker was configured in config.toml. This change adds a new flag, --host-linker, to compiletest, and renames --linker to --target-linker. --- src/bootstrap/test.rs | 5 ++++- src/tools/compiletest/src/common.rs | 3 ++- src/tools/compiletest/src/main.rs | 9 ++++++--- src/tools/compiletest/src/runtest.rs | 11 ++++++++--- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 92a7603a9df6..0d5672305e8b 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1535,7 +1535,10 @@ note: if you're sure you want to do this, please open an issue as to why. In the flags.extend(builder.config.cmd.rustc_args().iter().map(|s| s.to_string())); if let Some(linker) = builder.linker(target) { - cmd.arg("--linker").arg(linker); + cmd.arg("--target-linker").arg(linker); + } + if let Some(linker) = builder.linker(compiler.host) { + cmd.arg("--host-linker").arg(linker); } let mut hostflags = flags.clone(); diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 28c045f83824..f61d6f252137 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -369,7 +369,8 @@ pub struct Config { pub cflags: String, pub cxxflags: String, pub ar: String, - pub linker: Option, + pub target_linker: Option, + pub host_linker: Option, pub llvm_components: String, /// Path to a NodeJS executable. Used for JS doctests, emscripten and WASM tests diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index bce61c55c3d0..8537d72cd872 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -132,7 +132,8 @@ pub fn parse_config(args: Vec) -> Config { .reqopt("", "cflags", "flags for the C compiler", "FLAGS") .reqopt("", "cxxflags", "flags for the CXX compiler", "FLAGS") .optopt("", "ar", "path to an archiver", "PATH") - .optopt("", "linker", "path to a linker", "PATH") + .optopt("", "target-linker", "path to a linker for the target", "PATH") + .optopt("", "host-linker", "path to a linker for the host", "PATH") .reqopt("", "llvm-components", "list of LLVM components built in", "LIST") .optopt("", "llvm-bin-dir", "Path to LLVM's `bin` directory", "PATH") .optopt("", "nodejs", "the name of nodejs", "PATH") @@ -303,7 +304,8 @@ pub fn parse_config(args: Vec) -> Config { cflags: matches.opt_str("cflags").unwrap(), cxxflags: matches.opt_str("cxxflags").unwrap(), ar: matches.opt_str("ar").unwrap_or_else(|| String::from("ar")), - linker: matches.opt_str("linker"), + target_linker: matches.opt_str("target-linker"), + host_linker: matches.opt_str("host-linker"), llvm_components: matches.opt_str("llvm-components").unwrap(), nodejs: matches.opt_str("nodejs"), npm: matches.opt_str("npm"), @@ -346,7 +348,8 @@ pub fn log_config(config: &Config) { logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir)); logv(c, format!("adb_device_status: {}", config.adb_device_status)); logv(c, format!("ar: {}", config.ar)); - logv(c, format!("linker: {:?}", config.linker)); + logv(c, format!("target-linker: {:?}", config.target_linker)); + logv(c, format!("host-linker: {:?}", config.host_linker)); logv(c, format!("verbose: {}", config.verbose)); logv(c, format!("format: {:?}", config.format)); logv(c, "\n".to_string()); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index a40030723105..957560fcee5e 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1567,7 +1567,7 @@ impl<'test> TestCx<'test> { rustdoc.arg("--output-format").arg("json").arg("-Zunstable-options"); } - if let Some(ref linker) = self.config.linker { + if let Some(ref linker) = self.config.target_linker { rustdoc.arg(format!("-Clinker={}", linker)); } @@ -2080,10 +2080,15 @@ impl<'test> TestCx<'test> { if self.props.force_host { self.maybe_add_external_args(&mut rustc, &self.config.host_rustcflags); + if !is_rustdoc { + if let Some(ref linker) = self.config.host_linker { + rustc.arg(format!("-Clinker={}", linker)); + } + } } else { self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags); if !is_rustdoc { - if let Some(ref linker) = self.config.linker { + if let Some(ref linker) = self.config.target_linker { rustc.arg(format!("-Clinker={}", linker)); } } @@ -3035,7 +3040,7 @@ impl<'test> TestCx<'test> { cmd.env("NODE", node); } - if let Some(ref linker) = self.config.linker { + if let Some(ref linker) = self.config.target_linker { cmd.env("RUSTC_LINKER", linker); } From cf260bc90f2c2df8cc974fced7336129478fd4ef Mon Sep 17 00:00:00 2001 From: blyxyas Date: Thu, 6 Apr 2023 21:50:49 +0200 Subject: [PATCH 123/272] Fix broken links for Rust merge --- book/src/development/adding_lints.md | 2 +- book/src/usage.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index 3f4088e74eaf..9dacaaaae5c9 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -24,7 +24,7 @@ because that's clearly a non-descriptive name. - [Lint passes](#lint-passes) - [Emitting a lint](#emitting-a-lint) - [Adding the lint logic](#adding-the-lint-logic) - - [Specifying the lint's minimum supported Rust version (MSRV)](#specifying-the-lints-minimum-supported-rust-version--msrv-) + - [Specifying the lint's minimum supported Rust version (MSRV)](#specifying-the-lints-minimum-supported-rust-version-msrv) - [Author lint](#author-lint) - [Print HIR lint](#print-hir-lint) - [Documentation](#documentation) diff --git a/book/src/usage.md b/book/src/usage.md index 32084a9199b7..372a23320d85 100644 --- a/book/src/usage.md +++ b/book/src/usage.md @@ -148,4 +148,4 @@ clippy-driver --edition 2018 -Cpanic=abort foo.rs > that are not optimized as expected, for example. [Installation]: installation.md -[CI]: continuous_integration/index.md +[CI]: continuous_integration/README.md From b1c784d31f3361b3093466d61b8e62c997b1d086 Mon Sep 17 00:00:00 2001 From: Michael Schubart Date: Fri, 7 Apr 2023 08:00:53 +0900 Subject: [PATCH 124/272] Fix false negatives by using `expr_or_init` --- .../src/manual_slice_size_calculation.rs | 5 +++- tests/ui/manual_slice_size_calculation.rs | 12 ++++----- tests/ui/manual_slice_size_calculation.stderr | 26 ++++++++++++++++++- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/manual_slice_size_calculation.rs b/clippy_lints/src/manual_slice_size_calculation.rs index 2659f347778c..92ee79453a3b 100644 --- a/clippy_lints/src/manual_slice_size_calculation.rs +++ b/clippy_lints/src/manual_slice_size_calculation.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::in_constant; +use clippy_utils::{expr_or_init, in_constant}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; @@ -60,6 +60,9 @@ fn simplify<'tcx>( expr1: &'tcx Expr<'tcx>, expr2: &'tcx Expr<'tcx>, ) -> Option<&'tcx Expr<'tcx>> { + let expr1 = expr_or_init(cx, expr1); + let expr2 = expr_or_init(cx, expr2); + simplify_half(cx, expr1, expr2).or_else(|| simplify_half(cx, expr2, expr1)) } diff --git a/tests/ui/manual_slice_size_calculation.rs b/tests/ui/manual_slice_size_calculation.rs index 2cb8c4c2ad3e..5082f931f3c2 100644 --- a/tests/ui/manual_slice_size_calculation.rs +++ b/tests/ui/manual_slice_size_calculation.rs @@ -12,6 +12,12 @@ fn main() { let _ = size_of::() * s_i32.len(); // WARNING let _ = size_of::() * s_i32.len() * 5; // WARNING + let len = s_i32.len(); + let size = size_of::(); + let _ = len * size_of::(); // WARNING + let _ = s_i32.len() * size; // WARNING + let _ = len * size; // WARNING + // True negatives: let _ = size_of::() + s_i32.len(); // Ok, not a multiplication let _ = size_of::() * s_i32.partition_point(|_| true); // Ok, not len() @@ -22,12 +28,6 @@ fn main() { // False negatives: let _ = 5 * size_of::() * s_i32.len(); // Ok (MISSED OPPORTUNITY) let _ = size_of::() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY) - - let len = s_i32.len(); - let size = size_of::(); - let _ = len * size_of::(); // Ok (MISSED OPPORTUNITY) - let _ = s_i32.len() * size; // Ok (MISSED OPPORTUNITY) - let _ = len * size; // Ok (MISSED OPPORTUNITY) } const fn _const(s_i32: &[i32]) { diff --git a/tests/ui/manual_slice_size_calculation.stderr b/tests/ui/manual_slice_size_calculation.stderr index 33de9fad4d38..4a24fc60a0fa 100644 --- a/tests/ui/manual_slice_size_calculation.stderr +++ b/tests/ui/manual_slice_size_calculation.stderr @@ -23,5 +23,29 @@ LL | let _ = size_of::() * s_i32.len() * 5; // WARNING | = help: consider using std::mem::size_of_value instead -error: aborting due to 3 previous errors +error: manual slice size calculation + --> $DIR/manual_slice_size_calculation.rs:17:13 + | +LL | let _ = len * size_of::(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using std::mem::size_of_value instead + +error: manual slice size calculation + --> $DIR/manual_slice_size_calculation.rs:18:13 + | +LL | let _ = s_i32.len() * size; // WARNING + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider using std::mem::size_of_value instead + +error: manual slice size calculation + --> $DIR/manual_slice_size_calculation.rs:19:13 + | +LL | let _ = len * size; // WARNING + | ^^^^^^^^^^ + | + = help: consider using std::mem::size_of_value instead + +error: aborting due to 6 previous errors From f4e7a99662f710c57b6166418f1c3ac496269c96 Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Fri, 7 Apr 2023 14:32:55 +1200 Subject: [PATCH 125/272] fix: ensure bad `#[test]` invocs retain correct AST --- compiler/rustc_builtin_macros/src/test.rs | 62 ++++++++++++------- tests/ui/test-attrs/issue-109816.rs | 7 +++ tests/ui/test-attrs/issue-109816.stderr | 16 +++++ .../test-attr-non-associated-functions.rs | 6 +- .../test-attr-non-associated-functions.stderr | 32 +++++----- tests/ui/test-attrs/test-on-not-fn.stderr | 24 +++---- 6 files changed, 95 insertions(+), 52 deletions(-) create mode 100644 tests/ui/test-attrs/issue-109816.rs create mode 100644 tests/ui/test-attrs/issue-109816.stderr diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index a76ed4ee6cee..9a50999faa0d 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -107,6 +107,36 @@ pub fn expand_test_or_bench( return vec![]; } + let not_testable_error = |item: Option<&ast::Item>| { + let diag = &cx.sess.parse_sess.span_diagnostic; + let msg = "the `#[test]` attribute may only be used on a non-associated function"; + let mut err = match item.map(|i| &i.kind) { + // These were a warning before #92959 and need to continue being that to avoid breaking + // stable user code (#94508). + Some(ast::ItemKind::MacCall(_)) => diag.struct_span_warn(attr_sp, msg), + // `.forget_guarantee()` needed to get these two arms to match types. Because of how + // locally close the `.emit()` call is I'm comfortable with it, but if it can be + // reworked in the future to not need it, it'd be nice. + _ => diag.struct_span_err(attr_sp, msg).forget_guarantee(), + }; + if let Some(item) = item { + err.span_label( + item.span, + format!( + "expected a non-associated function, found {} {}", + item.kind.article(), + item.kind.descr() + ), + ); + } + err.span_label(attr_sp, "the `#[test]` macro causes a function to be run as a test and has no effect on non-functions") + .span_suggestion(attr_sp, + "replace with conditional compilation to make the item only exist when tests are being run", + "#[cfg(test)]", + Applicability::MaybeIncorrect) + .emit(); + }; + let (item, is_stmt) = match item { Annotatable::Item(i) => (i, false), Annotatable::Stmt(stmt) if matches!(stmt.kind, ast::StmtKind::Item(_)) => { @@ -118,34 +148,22 @@ pub fn expand_test_or_bench( } } other => { - cx.struct_span_err( - other.span(), - "`#[test]` attribute is only allowed on non associated functions", - ) - .emit(); + not_testable_error(None); return vec![other]; } }; - // Note: non-associated fn items are already handled by `expand_test_or_bench` let ast::ItemKind::Fn(fn_) = &item.kind else { - let diag = &cx.sess.parse_sess.span_diagnostic; - let msg = "the `#[test]` attribute may only be used on a non-associated function"; - let mut err = match item.kind { - // These were a warning before #92959 and need to continue being that to avoid breaking - // stable user code (#94508). - ast::ItemKind::MacCall(_) => diag.struct_span_warn(attr_sp, msg), - // `.forget_guarantee()` needed to get these two arms to match types. Because of how - // locally close the `.emit()` call is I'm comfortable with it, but if it can be - // reworked in the future to not need it, it'd be nice. - _ => diag.struct_span_err(attr_sp, msg).forget_guarantee(), + not_testable_error(Some(&item)); + return if is_stmt { + vec![Annotatable::Stmt(P(ast::Stmt { + id: ast::DUMMY_NODE_ID, + span: item.span, + kind: ast::StmtKind::Item(item), + }))] + } else { + vec![Annotatable::Item(item)] }; - err.span_label(attr_sp, "the `#[test]` macro causes a function to be run on a test and has no effect on non-functions") - .span_label(item.span, format!("expected a non-associated function, found {} {}", item.kind.article(), item.kind.descr())) - .span_suggestion(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", "#[cfg(test)]", Applicability::MaybeIncorrect) - .emit(); - - return vec![Annotatable::Item(item)]; }; // has_*_signature will report any errors in the type so compilation diff --git a/tests/ui/test-attrs/issue-109816.rs b/tests/ui/test-attrs/issue-109816.rs new file mode 100644 index 000000000000..21fe5bc53b75 --- /dev/null +++ b/tests/ui/test-attrs/issue-109816.rs @@ -0,0 +1,7 @@ +// compile-flags: --test + +fn align_offset_weird_strides() { + #[test] + //~^ ERROR the `#[test]` attribute may only be used on a non-associated function + struct A5(u32, u8); +} diff --git a/tests/ui/test-attrs/issue-109816.stderr b/tests/ui/test-attrs/issue-109816.stderr new file mode 100644 index 000000000000..e69932875555 --- /dev/null +++ b/tests/ui/test-attrs/issue-109816.stderr @@ -0,0 +1,16 @@ +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/issue-109816.rs:4:5 + | +LL | #[test] + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions +LL | +LL | struct A5(u32, u8); + | ------------------- expected a non-associated function, found a struct + | +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL | #[cfg(test)] + | + +error: aborting due to previous error + diff --git a/tests/ui/test-attrs/test-attr-non-associated-functions.rs b/tests/ui/test-attrs/test-attr-non-associated-functions.rs index 31e567c39606..2481919b616e 100644 --- a/tests/ui/test-attrs/test-attr-non-associated-functions.rs +++ b/tests/ui/test-attrs/test-attr-non-associated-functions.rs @@ -1,18 +1,16 @@ -// #[test] attribute is not allowed on associated functions or methods -// reworded error message // compile-flags:--test struct A {} impl A { #[test] + //~^ ERROR the `#[test]` attribute may only be used on a non-associated function fn new() -> A { - //~^ ERROR `#[test]` attribute is only allowed on non associated functions A {} } #[test] + //~^ ERROR the `#[test]` attribute may only be used on a non-associated function fn recovery_witness() -> A { - //~^ ERROR `#[test]` attribute is only allowed on non associated functions A {} } } diff --git a/tests/ui/test-attrs/test-attr-non-associated-functions.stderr b/tests/ui/test-attrs/test-attr-non-associated-functions.stderr index a81b8f3980c3..3e3a951aff3e 100644 --- a/tests/ui/test-attrs/test-attr-non-associated-functions.stderr +++ b/tests/ui/test-attrs/test-attr-non-associated-functions.stderr @@ -1,20 +1,24 @@ -error: `#[test]` attribute is only allowed on non associated functions - --> $DIR/test-attr-non-associated-functions.rs:9:5 +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/test-attr-non-associated-functions.rs:6:5 + | +LL | #[test] + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions + | +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL | #[cfg(test)] | -LL | / fn new() -> A { -LL | | -LL | | A {} -LL | | } - | |_____^ -error: `#[test]` attribute is only allowed on non associated functions - --> $DIR/test-attr-non-associated-functions.rs:14:5 +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/test-attr-non-associated-functions.rs:11:5 + | +LL | #[test] + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions + | +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL | #[cfg(test)] | -LL | / fn recovery_witness() -> A { -LL | | -LL | | A {} -LL | | } - | |_____^ error: aborting due to 2 previous errors diff --git a/tests/ui/test-attrs/test-on-not-fn.stderr b/tests/ui/test-attrs/test-on-not-fn.stderr index fc2c5f62bedb..7a9913fbcfa1 100644 --- a/tests/ui/test-attrs/test-on-not-fn.stderr +++ b/tests/ui/test-attrs/test-on-not-fn.stderr @@ -2,7 +2,7 @@ error: the `#[test]` attribute may only be used on a non-associated function --> $DIR/test-on-not-fn.rs:3:1 | LL | #[test] - | ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions LL | mod test {} | ----------- expected a non-associated function, found a module | @@ -15,7 +15,7 @@ error: the `#[test]` attribute may only be used on a non-associated function --> $DIR/test-on-not-fn.rs:6:1 | LL | #[test] - | ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions LL | / mod loooooooooooooong_teeeeeeeeeest { LL | | /* LL | | this is a comment @@ -34,7 +34,7 @@ error: the `#[test]` attribute may only be used on a non-associated function --> $DIR/test-on-not-fn.rs:20:1 | LL | #[test] - | ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions LL | extern "C" {} | ------------- expected a non-associated function, found an extern block | @@ -47,7 +47,7 @@ error: the `#[test]` attribute may only be used on a non-associated function --> $DIR/test-on-not-fn.rs:23:1 | LL | #[test] - | ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions LL | trait Foo {} | ------------ expected a non-associated function, found a trait | @@ -60,7 +60,7 @@ error: the `#[test]` attribute may only be used on a non-associated function --> $DIR/test-on-not-fn.rs:26:1 | LL | #[test] - | ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions LL | impl Foo for i32 {} | ------------------- expected a non-associated function, found an implementation | @@ -73,7 +73,7 @@ error: the `#[test]` attribute may only be used on a non-associated function --> $DIR/test-on-not-fn.rs:29:1 | LL | #[test] - | ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions LL | const FOO: i32 = -1_i32; | ------------------------ expected a non-associated function, found a constant item | @@ -86,7 +86,7 @@ error: the `#[test]` attribute may only be used on a non-associated function --> $DIR/test-on-not-fn.rs:32:1 | LL | #[test] - | ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions LL | static BAR: u64 = 10_000_u64; | ----------------------------- expected a non-associated function, found a static item | @@ -99,7 +99,7 @@ error: the `#[test]` attribute may only be used on a non-associated function --> $DIR/test-on-not-fn.rs:35:1 | LL | #[test] - | ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions LL | / enum MyUnit { LL | | Unit, LL | | } @@ -114,7 +114,7 @@ error: the `#[test]` attribute may only be used on a non-associated function --> $DIR/test-on-not-fn.rs:40:1 | LL | #[test] - | ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions LL | struct NewI32(i32); | ------------------- expected a non-associated function, found a struct | @@ -127,7 +127,7 @@ error: the `#[test]` attribute may only be used on a non-associated function --> $DIR/test-on-not-fn.rs:43:1 | LL | #[test] - | ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions LL | / union Spooky { LL | | x: i32, LL | | y: u32, @@ -143,7 +143,7 @@ error: the `#[test]` attribute may only be used on a non-associated function --> $DIR/test-on-not-fn.rs:50:1 | LL | #[test] - | ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions LL | #[derive(Copy, Clone, Debug)] LL | / struct MoreAttrs { LL | | a: i32, @@ -160,7 +160,7 @@ warning: the `#[test]` attribute may only be used on a non-associated function --> $DIR/test-on-not-fn.rs:61:1 | LL | #[test] - | ^^^^^^^ the `#[test]` macro causes a function to be run on a test and has no effect on non-functions + | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions LL | foo!(); | ------- expected a non-associated function, found an item macro invocation | From 5c5c3c95276811d4ea72f6c4b45e7406ee8c6165 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Fri, 7 Apr 2023 04:22:43 +0100 Subject: [PATCH 126/272] Add more complex test cases for new suggestion --- tests/ui/macros/macro-path-prelude-fail-5.rs | 10 +++++++ .../macros/macro-path-prelude-fail-5.stderr | 30 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 tests/ui/macros/macro-path-prelude-fail-5.rs create mode 100644 tests/ui/macros/macro-path-prelude-fail-5.stderr diff --git a/tests/ui/macros/macro-path-prelude-fail-5.rs b/tests/ui/macros/macro-path-prelude-fail-5.rs new file mode 100644 index 000000000000..b82b6bc78785 --- /dev/null +++ b/tests/ui/macros/macro-path-prelude-fail-5.rs @@ -0,0 +1,10 @@ +#[derive(Clone, Debug)] // OK +struct S; + +#[derive(Debug, inline)] //~ ERROR expected derive macro, found built-in attribute `inline` +struct T; + +#[derive(inline, Debug)] //~ ERROR expected derive macro, found built-in attribute `inline` +struct U; + +fn main() {} diff --git a/tests/ui/macros/macro-path-prelude-fail-5.stderr b/tests/ui/macros/macro-path-prelude-fail-5.stderr new file mode 100644 index 000000000000..105c59db6742 --- /dev/null +++ b/tests/ui/macros/macro-path-prelude-fail-5.stderr @@ -0,0 +1,30 @@ +error: expected derive macro, found built-in attribute `inline` + --> $DIR/macro-path-prelude-fail-5.rs:4:17 + | +LL | #[derive(Debug, inline)] + | ^^^^^^ not a derive macro + | +help: remove from the surrounding `derive()` + --> $DIR/macro-path-prelude-fail-5.rs:4:17 + | +LL | #[derive(Debug, inline)] + | ^^^^^^ + = help: add as non-Derive macro + `#[inline]` + +error: expected derive macro, found built-in attribute `inline` + --> $DIR/macro-path-prelude-fail-5.rs:7:10 + | +LL | #[derive(inline, Debug)] + | ^^^^^^ not a derive macro + | +help: remove from the surrounding `derive()` + --> $DIR/macro-path-prelude-fail-5.rs:7:10 + | +LL | #[derive(inline, Debug)] + | ^^^^^^ + = help: add as non-Derive macro + `#[inline]` + +error: aborting due to 2 previous errors + From 18388c9f7372d00fa958a421b3eec639a5b7b5a2 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Fri, 7 Apr 2023 08:14:48 +0100 Subject: [PATCH 127/272] Rewrite added diagnostics as translatable Start messages with lowercase --- compiler/rustc_resolve/messages.ftl | 10 +++++++ compiler/rustc_resolve/src/errors.rs | 27 +++++++++++++++++++ compiler/rustc_resolve/src/macros.rs | 22 ++++++++++----- .../macros/macro-path-prelude-fail-4.stderr | 4 +-- .../macro-namespace-reserved-2.stderr | 8 +++--- .../tool-attributes-misplaced-2.stderr | 4 +-- 6 files changed, 61 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 817bb83ed786..07865044f053 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -209,3 +209,13 @@ resolve_indeterminate = resolve_module_only = visibility must resolve to a module + +resolve_macro_expected_found = + expected {$expected}, found {$found} `{$macro_path}` + +resolve_remove_surrounding_derive = + remove from the surrounding `derive()` + +resolve_add_as_non_derive = + add as non-Derive macro + `#[{$macro_path}]` diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 867363f4246a..ff44ccb265a9 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -472,3 +472,30 @@ pub(crate) struct Indeterminate(#[primary_span] pub(crate) Span); #[derive(Diagnostic)] #[diag(resolve_module_only)] pub(crate) struct ModuleOnly(#[primary_span] pub(crate) Span); + +#[derive(Diagnostic, Default)] +#[diag(resolve_macro_expected_found)] +pub(crate) struct MacroExpectedFound<'a> { + #[primary_span] + pub(crate) span: Span, + pub(crate) found: &'a str, + pub(crate) expected: &'a str, + pub(crate) macro_path: &'a str, + #[subdiagnostic] + pub(crate) remove_surrounding_derive: Option, + #[subdiagnostic] + pub(crate) remove_surrounding_derive_help: Option>, +} + +#[derive(Subdiagnostic)] +#[help(resolve_remove_surrounding_derive)] +pub(crate) struct RemoveSurroundingDerive { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Subdiagnostic)] +#[help(resolve_add_as_non_derive)] +pub(crate) struct RemoveAddAsNonDerive<'a> { + pub(crate) macro_path: &'a str, +} diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index ed479d289d78..b2e23721295d 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -1,6 +1,7 @@ //! A bunch of methods and structures more or less related to resolving macros and //! interface provided by `Resolver` to macro expander. +use crate::errors::{MacroExpectedFound, RemoveAddAsNonDerive, RemoveSurroundingDerive}; use crate::Namespace::*; use crate::{BuiltinMacroState, Determinacy}; use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet}; @@ -543,21 +544,30 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }; if let Some((article, expected)) = unexpected_res { let path_str = pprust::path_to_string(path); - let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path_str); - let mut err = self.tcx.sess.struct_span_err(path.span, &msg); - err.span_label(path.span, format!("not {} {}", article, expected)); + let mut err = MacroExpectedFound { + span: path.span, + expected, + found: res.descr(), + macro_path: &path_str, + ..Default::default() // Subdiagnostics default to None + }; - // Suggest moving the macro out of the derive() as the macro isn't Derive + // Suggest moving the macro out of the derive() if the macro isn't Derive if !path.span.from_expansion() && kind == MacroKind::Derive && ext.macro_kind() != MacroKind::Derive { - err.span_help(path.span, "remove from the surrounding `derive()`"); - err.help(format!("add as non-Derive macro\n`#[{}]`", path_str)); + err.remove_surrounding_derive = Some(RemoveSurroundingDerive { span: path.span }); + err.remove_surrounding_derive_help = + Some(RemoveAddAsNonDerive { macro_path: &path_str }); } + let mut err = self.tcx.sess.create_err(err); + err.span_label(path.span, format!("not {} {}", article, expected)); + err.emit(); + return Ok((self.dummy_ext(kind), Res::Err)); } diff --git a/tests/ui/macros/macro-path-prelude-fail-4.stderr b/tests/ui/macros/macro-path-prelude-fail-4.stderr index 0dd67e6726c8..81c6722b56a8 100644 --- a/tests/ui/macros/macro-path-prelude-fail-4.stderr +++ b/tests/ui/macros/macro-path-prelude-fail-4.stderr @@ -4,12 +4,12 @@ error: expected derive macro, found built-in attribute `inline` LL | #[derive(inline)] | ^^^^^^ not a derive macro | -help: Remove from the surrounding `derive()` +help: remove from the surrounding `derive()` --> $DIR/macro-path-prelude-fail-4.rs:1:10 | LL | #[derive(inline)] | ^^^^^^ - = help: Add as non-Derive macro + = help: add as non-Derive macro `#[inline]` error: aborting due to previous error diff --git a/tests/ui/proc-macro/macro-namespace-reserved-2.stderr b/tests/ui/proc-macro/macro-namespace-reserved-2.stderr index d0f829b50918..b9effe7cf21f 100644 --- a/tests/ui/proc-macro/macro-namespace-reserved-2.stderr +++ b/tests/ui/proc-macro/macro-namespace-reserved-2.stderr @@ -58,12 +58,12 @@ error: expected derive macro, found attribute macro `my_macro_attr` LL | #[derive(my_macro_attr)] | ^^^^^^^^^^^^^ not a derive macro | -help: Remove from the surrounding `derive()` +help: remove from the surrounding `derive()` --> $DIR/macro-namespace-reserved-2.rs:53:10 | LL | #[derive(my_macro_attr)] | ^^^^^^^^^^^^^ - = help: Add as non-Derive macro + = help: add as non-Derive macro `#[my_macro_attr]` error: can't use a procedural macro from the same crate that defines it @@ -96,12 +96,12 @@ error: expected derive macro, found macro `crate::my_macro` LL | #[derive(crate::my_macro)] | ^^^^^^^^^^^^^^^ not a derive macro | -help: Remove from the surrounding `derive()` +help: remove from the surrounding `derive()` --> $DIR/macro-namespace-reserved-2.rs:50:10 | LL | #[derive(crate::my_macro)] | ^^^^^^^^^^^^^^^ - = help: Add as non-Derive macro + = help: add as non-Derive macro `#[crate::my_macro]` error: cannot find macro `my_macro_attr` in this scope diff --git a/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr b/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr index b1ecd5289388..06696b548d48 100644 --- a/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr +++ b/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr @@ -4,12 +4,12 @@ error: expected derive macro, found tool attribute `rustfmt::skip` LL | #[derive(rustfmt::skip)] | ^^^^^^^^^^^^^ not a derive macro | -help: Remove from the surrounding `derive()` +help: remove from the surrounding `derive()` --> $DIR/tool-attributes-misplaced-2.rs:1:10 | LL | #[derive(rustfmt::skip)] | ^^^^^^^^^^^^^ - = help: Add as non-Derive macro + = help: add as non-Derive macro `#[rustfmt::skip]` error: expected macro, found tool attribute `rustfmt::skip` From 668a62984ac51a09987c5b1a7c1589814f7a95d4 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Fri, 7 Apr 2023 08:44:19 +0100 Subject: [PATCH 128/272] Change type and field name to be clearer --- compiler/rustc_resolve/src/errors.rs | 4 ++-- compiler/rustc_resolve/src/macros.rs | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index ff44ccb265a9..660614d34216 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -484,7 +484,7 @@ pub(crate) struct MacroExpectedFound<'a> { #[subdiagnostic] pub(crate) remove_surrounding_derive: Option, #[subdiagnostic] - pub(crate) remove_surrounding_derive_help: Option>, + pub(crate) add_as_non_derive: Option>, } #[derive(Subdiagnostic)] @@ -496,6 +496,6 @@ pub(crate) struct RemoveSurroundingDerive { #[derive(Subdiagnostic)] #[help(resolve_add_as_non_derive)] -pub(crate) struct RemoveAddAsNonDerive<'a> { +pub(crate) struct AddAsNonDerive<'a> { pub(crate) macro_path: &'a str, } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index b2e23721295d..22b014c0651c 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -1,7 +1,7 @@ //! A bunch of methods and structures more or less related to resolving macros and //! interface provided by `Resolver` to macro expander. -use crate::errors::{MacroExpectedFound, RemoveAddAsNonDerive, RemoveSurroundingDerive}; +use crate::errors::{AddAsNonDerive, MacroExpectedFound, RemoveSurroundingDerive}; use crate::Namespace::*; use crate::{BuiltinMacroState, Determinacy}; use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet}; @@ -559,8 +559,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { && ext.macro_kind() != MacroKind::Derive { err.remove_surrounding_derive = Some(RemoveSurroundingDerive { span: path.span }); - err.remove_surrounding_derive_help = - Some(RemoveAddAsNonDerive { macro_path: &path_str }); + err.add_as_non_derive = Some(AddAsNonDerive { macro_path: &path_str }); } let mut err = self.tcx.sess.create_err(err); From 5d01e6e96cc72694529a32c42459b20ddf665507 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 13 Mar 2023 13:06:31 +0100 Subject: [PATCH 129/272] new lint: suspicious_doc_comments --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/suspicious_doc_comments.rs | 94 +++++++++++++++ tests/ui/suspicious_doc_comments.fixed | 81 +++++++++++++ tests/ui/suspicious_doc_comments.rs | 81 +++++++++++++ tests/ui/suspicious_doc_comments.stderr | 114 ++++++++++++++++++ tests/ui/suspicious_doc_comments_unfixable.rs | 16 +++ .../suspicious_doc_comments_unfixable.stderr | 37 ++++++ 9 files changed, 427 insertions(+) create mode 100644 clippy_lints/src/suspicious_doc_comments.rs create mode 100644 tests/ui/suspicious_doc_comments.fixed create mode 100644 tests/ui/suspicious_doc_comments.rs create mode 100644 tests/ui/suspicious_doc_comments.stderr create mode 100644 tests/ui/suspicious_doc_comments_unfixable.rs create mode 100644 tests/ui/suspicious_doc_comments_unfixable.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index f615b27bf688..559b560dde4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4925,6 +4925,7 @@ Released 2018-09-13 [`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl [`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting [`suspicious_command_arg_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_command_arg_space +[`suspicious_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_doc_comments [`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting [`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 09ae6b8ee571..f24dab627809 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -569,6 +569,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::strings::STR_TO_STRING_INFO, crate::strings::TRIM_SPLIT_WHITESPACE_INFO, crate::strlen_on_c_strings::STRLEN_ON_C_STRINGS_INFO, + crate::suspicious_doc_comments::SUSPICIOUS_DOC_COMMENTS_INFO, crate::suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS_INFO, crate::suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL_INFO, crate::suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2a0f219331e2..bac82eca8174 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -284,6 +284,7 @@ mod slow_vector_initialization; mod std_instead_of_core; mod strings; mod strlen_on_c_strings; +mod suspicious_doc_comments; mod suspicious_operation_groupings; mod suspicious_trait_impl; mod suspicious_xor_used_as_pow; @@ -958,6 +959,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(lines_filter_map_ok::LinesFilterMapOk)); store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule)); store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation)); + store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/suspicious_doc_comments.rs b/clippy_lints/src/suspicious_doc_comments.rs new file mode 100644 index 000000000000..e5746ca99cac --- /dev/null +++ b/clippy_lints/src/suspicious_doc_comments.rs @@ -0,0 +1,94 @@ +use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then}; +use if_chain::if_chain; +use rustc_ast::{token::CommentKind, AttrKind, AttrStyle, Attribute, Item}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### What it does + /// Detects the use of outer doc comments (`///`, `/**`) followed by a bang (`!`): `///!` + /// + /// ### Why is this bad? + /// Triple-slash comments (known as "outer doc comments") apply to items that follow it. + /// An outer doc comment followed by a bang (i.e. `///!`) has no specific meaning. + /// + /// The user most likely meant to write an inner doc comment (`//!`, `/*!`), which + /// applies to the parent item (i.e. the item that the comment is contained in, + /// usually a module or crate). + /// + /// ### Known problems + /// Inner doc comments can only appear before items, so there are certain cases where the suggestion + /// made by this lint is not valid code. For example: + /// ```rs + /// fn foo() {} + /// ///! + /// fn bar() {} + /// ``` + /// This lint detects the doc comment and suggests changing it to `//!`, but an inner doc comment + /// is not valid at that position. + /// + /// ### Example + /// In this example, the doc comment is attached to the *function*, rather than the *module*. + /// ```rust + /// pub mod util { + /// ///! This module contains utility functions. + /// + /// pub fn dummy() {} + /// } + /// ``` + /// + /// Use instead: + /// ```rust + /// pub mod util { + /// //! This module contains utility functions. + /// + /// pub fn dummy() {} + /// } + /// ``` + #[clippy::version = "1.70.0"] + pub SUSPICIOUS_DOC_COMMENTS, + suspicious, + "suspicious usage of (outer) doc comments" +} +declare_lint_pass!(SuspiciousDocComments => [SUSPICIOUS_DOC_COMMENTS]); + +const WARNING: &str = "this is an outer doc comment and does not apply to the parent module or crate"; +const HELP: &str = "use an inner doc comment to document the parent module or crate"; + +impl EarlyLintPass for SuspiciousDocComments { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + let replacements = collect_doc_comment_replacements(&item.attrs); + + if let Some(((lo_span, _), (hi_span, _))) = replacements.first().zip(replacements.last()) { + let span = lo_span.to(*hi_span); + + span_lint_and_then(cx, SUSPICIOUS_DOC_COMMENTS, span, WARNING, |diag| { + multispan_sugg_with_applicability(diag, HELP, Applicability::MaybeIncorrect, replacements); + }); + } + } +} + +fn collect_doc_comment_replacements(attrs: &[Attribute]) -> Vec<(Span, String)> { + attrs + .iter() + .filter_map(|attr| { + if_chain! { + if let AttrKind::DocComment(com_kind, sym) = attr.kind; + if let AttrStyle::Outer = attr.style; + if let Some(com) = sym.as_str().strip_prefix('!'); + then { + let sugg = match com_kind { + CommentKind::Line => format!("//!{com}"), + CommentKind::Block => format!("/*!{com}*/") + }; + Some((attr.span, sugg)) + } else { + None + } + } + }) + .collect() +} diff --git a/tests/ui/suspicious_doc_comments.fixed b/tests/ui/suspicious_doc_comments.fixed new file mode 100644 index 000000000000..b404df94d3c2 --- /dev/null +++ b/tests/ui/suspicious_doc_comments.fixed @@ -0,0 +1,81 @@ +// run-rustfix +#![allow(unused)] +#![warn(clippy::suspicious_doc_comments)] + +//! Real module documentation. +//! Fake module documentation. +fn baz() {} + +pub mod singleline_outer_doc { + //! This module contains useful functions. + + pub fn bar() {} +} + +pub mod singleline_inner_doc { + //! This module contains useful functions. + + pub fn bar() {} +} + +pub mod multiline_outer_doc { + /*! This module contains useful functions. + */ + + pub fn bar() {} +} + +pub mod multiline_inner_doc { + /*! This module contains useful functions. + */ + + pub fn bar() {} +} + +pub mod multiline_outer_doc2 { + //! This module + //! contains + //! useful functions. + + pub fn bar() {} +} + +pub mod multiline_outer_doc3 { + //! a + //! b + + /// c + pub fn bar() {} +} + +pub mod multiline_outer_doc4 { + //! a + /// b + pub fn bar() {} +} + +pub mod multiline_outer_doc_gap { + //! a + + //! b + pub fn bar() {} +} + +pub mod multiline_outer_doc_commented { + /////! This outer doc comment was commented out. + pub fn bar() {} +} + +pub mod outer_doc_macro { + //! Very cool macro + macro_rules! x { + () => {}; + } +} + +pub mod useless_outer_doc { + //! Huh. + use std::mem; +} + +fn main() {} diff --git a/tests/ui/suspicious_doc_comments.rs b/tests/ui/suspicious_doc_comments.rs new file mode 100644 index 000000000000..46eff51e220f --- /dev/null +++ b/tests/ui/suspicious_doc_comments.rs @@ -0,0 +1,81 @@ +// run-rustfix +#![allow(unused)] +#![warn(clippy::suspicious_doc_comments)] + +//! Real module documentation. +///! Fake module documentation. +fn baz() {} + +pub mod singleline_outer_doc { + ///! This module contains useful functions. + + pub fn bar() {} +} + +pub mod singleline_inner_doc { + //! This module contains useful functions. + + pub fn bar() {} +} + +pub mod multiline_outer_doc { + /**! This module contains useful functions. + */ + + pub fn bar() {} +} + +pub mod multiline_inner_doc { + /*! This module contains useful functions. + */ + + pub fn bar() {} +} + +pub mod multiline_outer_doc2 { + ///! This module + ///! contains + ///! useful functions. + + pub fn bar() {} +} + +pub mod multiline_outer_doc3 { + ///! a + ///! b + + /// c + pub fn bar() {} +} + +pub mod multiline_outer_doc4 { + ///! a + /// b + pub fn bar() {} +} + +pub mod multiline_outer_doc_gap { + ///! a + + ///! b + pub fn bar() {} +} + +pub mod multiline_outer_doc_commented { + /////! This outer doc comment was commented out. + pub fn bar() {} +} + +pub mod outer_doc_macro { + ///! Very cool macro + macro_rules! x { + () => {}; + } +} + +pub mod useless_outer_doc { + ///! Huh. + use std::mem; +} + +fn main() {} diff --git a/tests/ui/suspicious_doc_comments.stderr b/tests/ui/suspicious_doc_comments.stderr new file mode 100644 index 000000000000..6c167df27873 --- /dev/null +++ b/tests/ui/suspicious_doc_comments.stderr @@ -0,0 +1,114 @@ +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments.rs:6:1 + | +LL | ///! Fake module documentation. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::suspicious-doc-comments` implied by `-D warnings` +help: use an inner doc comment to document the parent module or crate + | +LL | //! Fake module documentation. + | + +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments.rs:10:5 + | +LL | ///! This module contains useful functions. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use an inner doc comment to document the parent module or crate + | +LL | //! This module contains useful functions. + | + +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments.rs:22:5 + | +LL | / /**! This module contains useful functions. +LL | | */ + | |_______^ + | +help: use an inner doc comment to document the parent module or crate + | +LL ~ /*! This module contains useful functions. +LL + */ + | + +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments.rs:36:5 + | +LL | / ///! This module +LL | | ///! contains +LL | | ///! useful functions. + | |__________________________^ + | +help: use an inner doc comment to document the parent module or crate + | +LL ~ //! This module +LL ~ //! contains +LL ~ //! useful functions. + | + +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments.rs:44:5 + | +LL | / ///! a +LL | | ///! b + | |__________^ + | +help: use an inner doc comment to document the parent module or crate + | +LL ~ //! a +LL ~ //! b + | + +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments.rs:52:5 + | +LL | ///! a + | ^^^^^^ + | +help: use an inner doc comment to document the parent module or crate + | +LL | //! a + | + +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments.rs:58:5 + | +LL | / ///! a +LL | | +LL | | ///! b + | |__________^ + | +help: use an inner doc comment to document the parent module or crate + | +LL ~ //! a +LL | +LL ~ //! b + | + +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments.rs:70:5 + | +LL | ///! Very cool macro + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use an inner doc comment to document the parent module or crate + | +LL | //! Very cool macro + | + +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments.rs:77:5 + | +LL | ///! Huh. + | ^^^^^^^^^ + | +help: use an inner doc comment to document the parent module or crate + | +LL | //! Huh. + | + +error: aborting due to 9 previous errors + diff --git a/tests/ui/suspicious_doc_comments_unfixable.rs b/tests/ui/suspicious_doc_comments_unfixable.rs new file mode 100644 index 000000000000..ad98c7f4966f --- /dev/null +++ b/tests/ui/suspicious_doc_comments_unfixable.rs @@ -0,0 +1,16 @@ +#![allow(unused)] +#![warn(clippy::suspicious_doc_comments)] + +///! a +///! b +/// c +///! d +pub fn foo() {} + +///! a +///! b +/// c +///! d +use std::mem; + +fn main() {} diff --git a/tests/ui/suspicious_doc_comments_unfixable.stderr b/tests/ui/suspicious_doc_comments_unfixable.stderr new file mode 100644 index 000000000000..f89146dad36e --- /dev/null +++ b/tests/ui/suspicious_doc_comments_unfixable.stderr @@ -0,0 +1,37 @@ +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments_unfixable.rs:4:1 + | +LL | / ///! a +LL | | ///! b +LL | | /// c +LL | | ///! d + | |______^ + | + = note: `-D clippy::suspicious-doc-comments` implied by `-D warnings` +help: use an inner doc comment to document the parent module or crate + | +LL + //! a +LL + //! b +LL | /// c +LL + //! d + | + +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments_unfixable.rs:10:1 + | +LL | / ///! a +LL | | ///! b +LL | | /// c +LL | | ///! d + | |______^ + | +help: use an inner doc comment to document the parent module or crate + | +LL + //! a +LL + //! b +LL | /// c +LL + //! d + | + +error: aborting due to 2 previous errors + From 90e6ddc8e77eadf5cc83bc94a1d81dfb51c64371 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Fri, 7 Apr 2023 13:08:29 +0200 Subject: [PATCH 130/272] New chapter: "Type Checking" --- book/src/SUMMARY.md | 1 + book/src/development/type_checking.md | 126 ++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 book/src/development/type_checking.md diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 0649f7a631df..cbd73376dfa0 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -13,6 +13,7 @@ - [Development](development/README.md) - [Basics](development/basics.md) - [Adding Lints](development/adding_lints.md) + - [Type Checking](development/type_checking.md) - [Common Tools](development/common_tools_writing_lints.md) - [Infrastructure](development/infrastructure/README.md) - [Syncing changes between Clippy and rust-lang/rust](development/infrastructure/sync.md) diff --git a/book/src/development/type_checking.md b/book/src/development/type_checking.md new file mode 100644 index 000000000000..ff08cb1e5240 --- /dev/null +++ b/book/src/development/type_checking.md @@ -0,0 +1,126 @@ +# Type Checking + +When we work on a new lint or improve an existing lint, we might want +to retrieve the type `Ty` of an expression `Expr` for a variety of +reasons. This can be achieved by utilizing the [`LateContext`][LateContext] +that is available for [`LateLintPass`][LateLintPass]. + +## `LateContext` and `TypeckResults` + +The lint context [`LateContext`][LateContext] and [`TypeckResults`][TypeckResults] +(returned by `LateContext::typeck_results`) are the two most useful data structures +in `LateLintPass`. They allow us to jump to type definitions and other compilation +stages such as HIR. + +> Note: `LateContext.typeck_results`'s return value is [`TypeckResults`][TypeckResults] +> and is created in the type checking step, it includes useful information such as types of +> expressions, ways to resolve methods and so on. + +`TypeckResults` contains useful methods such as [`expr_ty`][expr_ty], +which gives us access to the underlying structure [`Ty`][Ty] of a given expression. + +```rust +pub fn expr_ty(&self, expr: &Expr<'_>) -> Ty<'tcx> +``` + +As a side note, besides `expr_ty`, [`TypeckResults`][TypeckResults] contains a +[`pat_ty()`][pat_ty] method that is useful for retrieving a type from a pattern. + +## `Ty` + +`Ty` struct contains the type information of an expression. +Let's take a look at `rustc_middle`'s [`Ty`][Ty] struct to examine this struct: + +```rust +pub struct Ty<'tcx>(Interned<'tcx, WithStableHash>>); +``` + +At a first glance, this struct looks quite esoteric. But at a closer look, +we will see that this struct contains many useful methods for type checking. + +For instance, [`is_char`][is_char] checks if the given `Ty` struct corresponds +to the primitive character type. + +### `is_*` Usage + +In some scenarios, all we need to do is check if the `Ty` of an expression +is a specific type, such as `char` type, so we could write the following: + +```rust +impl LateLintPass<'_> for MyStructLint { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + // Get type of `expr` + let ty = cx.typeck_results().expr_ty(expr); + + // Check if the `Ty` of this expression is of character type + if ty.is_char() { + println!("Our expression is a char!"); + } + } +} +``` + +Furthermore, if we examine the [source code][is_char_source] for `is_char`, +we find something very interesting: + +```rust +#[inline] +pub fn is_char(self) -> bool { + matches!(self.kind(), Char) +} +``` + +Indeed, we just discovered `Ty`'s [`kind` method][kind], which provides us +with [`TyKind`][TyKind] of a `Ty`. + +## `TyKind` + +`TyKind` defines the kinds of types in Rust's type system. +Peeking into [`TyKind` documentation][TyKind], we will see that it is an +enum of 27 variants, including items such as `Bool`, `Int`, `Ref`, etc. + +### `kind` Usage + +The `TyKind` of `Ty` can be returned by calling [`Ty.kind` method][kind]. +We often use this method to perform pattern matching in Clippy. + +For instance, if we want to check for a `struct`, we could examine if the +`ty.kind` corresponds to an [`Adt`][Adt] (algebraic data type) and if its +[`AdtDef`][AdtDef] is a struct: + +```rust +impl LateLintPass<'_> for MyStructLint { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + // Get type of `expr` + let ty = cx.typeck_results().expr_ty(expr); + // Match its kind to enter the type + match ty.kind { + ty::Adt(adt_def, _) if adt_def.is_struct() => println!("Our `expr` is a struct!"), + _ => () + } + } +} +``` + +## Useful Links + +Below are some useful links to further explore the concepts covered +in this chapter: + +- [Stages of compilation](https://rustc-dev-guide.rust-lang.org/compiler-src.html#the-main-stages-of-compilation) +- [Diagnostic items](https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html) +- [Type checking](https://rustc-dev-guide.rust-lang.org/type-checking.html) +- [Ty module](https://rustc-dev-guide.rust-lang.org/ty.html) + +[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html#variant.Adt +[AdtDef]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/adt/struct.AdtDef.html +[expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.expr_ty +[is_char]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.is_char +[is_char_source]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_middle/ty/sty.rs.html#1831-1834 +[kind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.kind +[LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html +[LateLintPass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html +[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckResults.html#method.pat_ty +[Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html +[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html +[TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html From 9ec542873cde1332baf2a0ed33088ba98eba25cf Mon Sep 17 00:00:00 2001 From: bluthej Date: Thu, 6 Apr 2023 07:49:59 +0200 Subject: [PATCH 131/272] Add 5 other container types and start testing --- clippy_lints/src/methods/clear_with_drain.rs | 33 +++++++++++++---- clippy_lints/src/methods/mod.rs | 11 +++--- tests/ui/clear_with_drain.fixed | 25 ++++++++++++- tests/ui/clear_with_drain.rs | 25 ++++++++++++- tests/ui/clear_with_drain.stderr | 38 ++++++++++++++++---- 5 files changed, 112 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs index 24496bd4689f..4f5b7762e3c7 100644 --- a/clippy_lints/src/methods/clear_with_drain.rs +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_range_full; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; +use rustc_hir as hir; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; @@ -9,17 +10,37 @@ use rustc_span::Span; use super::CLEAR_WITH_DRAIN; -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: &Expr<'_>) { - let ty = cx.typeck_results().expr_ty(recv); - if is_type_diagnostic_item(cx, ty, sym::Vec) - && let ExprKind::Path(QPath::Resolved(None, container_path)) = recv.kind - && is_range_full(cx, arg, Some(container_path)) +const ACCEPTABLE_TYPES_WITH_ARG: [rustc_span::Symbol; 3] = [sym::String, sym::Vec, sym::VecDeque]; + +const ACCEPTABLE_TYPES_WITHOUT_ARG: [rustc_span::Symbol; 3] = [sym::BinaryHeap, sym::HashMap, sym::HashSet]; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: Option<&Expr<'_>>) { + if let Some(arg) = arg { + if match_acceptable_type(cx, recv, &ACCEPTABLE_TYPES_WITH_ARG) + && let ExprKind::Path(QPath::Resolved(None, container_path)) = recv.kind + && is_range_full(cx, arg, Some(container_path)) + { + suggest(cx, expr, recv, span); + } + } else if match_acceptable_type(cx, recv, &ACCEPTABLE_TYPES_WITHOUT_ARG) { + suggest(cx, expr, recv, span); + } +} + +fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, types: &[rustc_span::Symbol]) -> bool { + let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs(); + types.iter().any(|&ty| is_type_diagnostic_item(cx, expr_ty, ty)) +} + +fn suggest(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span) { + if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def() + && let Some(ty_name) = cx.tcx.get_diagnostic_name(adt.did()) { span_lint_and_sugg( cx, CLEAR_WITH_DRAIN, span.with_hi(expr.span.hi()), - "`drain` used to clear a `Vec`", + &format!("`drain` used to clear a `{}`", ty_name), "try", "clear()".to_string(), Applicability::MachineApplicable, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 257bc4eccc30..c25f1b60aa5f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3589,12 +3589,13 @@ impl Methods { Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2), _ => {}, }, - ("drain", [arg]) => { - if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.hir().get_parent(expr.hir_id) - && matches!(kind, StmtKind::Semi(_)) + ("drain", ..) => { + if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.hir().get_parent(expr.hir_id) + && matches!(kind, StmtKind::Semi(_)) + && args.len() <= 1 { - clear_with_drain::check(cx, expr, recv, span, arg); - } else { + clear_with_drain::check(cx, expr, recv, span, args.first()); + } else if let [arg] = args { iter_with_drain::check(cx, expr, recv, span, arg); } }, diff --git a/tests/ui/clear_with_drain.fixed b/tests/ui/clear_with_drain.fixed index 9c4dc010ca7f..dd02cc9148f7 100644 --- a/tests/ui/clear_with_drain.fixed +++ b/tests/ui/clear_with_drain.fixed @@ -2,6 +2,11 @@ #![allow(unused)] #![warn(clippy::clear_with_drain)] +use std::collections::BinaryHeap; +use std::collections::HashMap; +use std::collections::HashSet; +use std::collections::VecDeque; + fn range() { let mut v = vec![1, 2, 3]; let iter = v.drain(0..v.len()); // Yay @@ -83,4 +88,22 @@ fn partial_drains() { let w: Vec = v.drain(1..v.len() - 1).collect(); // Yay } -fn main() {} +fn main() { + let mut deque: VecDeque<_> = [1, 2, 3].into(); + deque.clear(); + + let mut set = HashSet::from([1, 2, 3]); + set.clear(); + + let mut a = HashMap::new(); + a.insert(1, "a"); + a.insert(2, "b"); + a.clear(); + + let mut heap = BinaryHeap::from([1, 3]); + heap.clear(); + + // Not firing for now because `String` is not reckognized by `is_type_diagnostic_item` + let mut s = String::from("α is alpha, β is beta"); + s.drain(..); +} diff --git a/tests/ui/clear_with_drain.rs b/tests/ui/clear_with_drain.rs index f00dbab234cc..af2fe503d9a6 100644 --- a/tests/ui/clear_with_drain.rs +++ b/tests/ui/clear_with_drain.rs @@ -2,6 +2,11 @@ #![allow(unused)] #![warn(clippy::clear_with_drain)] +use std::collections::BinaryHeap; +use std::collections::HashMap; +use std::collections::HashSet; +use std::collections::VecDeque; + fn range() { let mut v = vec![1, 2, 3]; let iter = v.drain(0..v.len()); // Yay @@ -83,4 +88,22 @@ fn partial_drains() { let w: Vec = v.drain(1..v.len() - 1).collect(); // Yay } -fn main() {} +fn main() { + let mut deque: VecDeque<_> = [1, 2, 3].into(); + deque.drain(..); + + let mut set = HashSet::from([1, 2, 3]); + set.drain(); + + let mut a = HashMap::new(); + a.insert(1, "a"); + a.insert(2, "b"); + a.drain(); + + let mut heap = BinaryHeap::from([1, 3]); + heap.drain(); + + // Not firing for now because `String` is not reckognized by `is_type_diagnostic_item` + let mut s = String::from("α is alpha, β is beta"); + s.drain(..); +} diff --git a/tests/ui/clear_with_drain.stderr b/tests/ui/clear_with_drain.stderr index c88aa1a23cb6..2c0cc846de2d 100644 --- a/tests/ui/clear_with_drain.stderr +++ b/tests/ui/clear_with_drain.stderr @@ -1,5 +1,5 @@ error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:17:7 + --> $DIR/clear_with_drain.rs:22:7 | LL | v.drain(0..v.len()); // Nay | ^^^^^^^^^^^^^^^^^ help: try: `clear()` @@ -7,34 +7,58 @@ LL | v.drain(0..v.len()); // Nay = note: `-D clippy::clear-with-drain` implied by `-D warnings` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:20:7 + --> $DIR/clear_with_drain.rs:25:7 | LL | v.drain(usize::MIN..v.len()); // Nay | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:35:7 + --> $DIR/clear_with_drain.rs:40:7 | LL | v.drain(0..); // Nay | ^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:38:7 + --> $DIR/clear_with_drain.rs:43:7 | LL | v.drain(usize::MIN..); // Nay | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:52:7 + --> $DIR/clear_with_drain.rs:57:7 | LL | v.drain(..); // Nay | ^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:66:7 + --> $DIR/clear_with_drain.rs:71:7 | LL | v.drain(..v.len()); // Nay | ^^^^^^^^^^^^^^^^ help: try: `clear()` -error: aborting due to 6 previous errors +error: `drain` used to clear a `VecDeque` + --> $DIR/clear_with_drain.rs:93:11 + | +LL | deque.drain(..); + | ^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `HashSet` + --> $DIR/clear_with_drain.rs:96:9 + | +LL | set.drain(); + | ^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `HashMap` + --> $DIR/clear_with_drain.rs:101:7 + | +LL | a.drain(); + | ^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `BinaryHeap` + --> $DIR/clear_with_drain.rs:104:10 + | +LL | heap.drain(); + | ^^^^^^^ help: try: `clear()` + +error: aborting due to 10 previous errors From bf1758d229d08a1a40fb78c0031bba26060a8fe6 Mon Sep 17 00:00:00 2001 From: zhaixiaojuan Date: Fri, 3 Feb 2023 16:24:11 +0800 Subject: [PATCH 132/272] Define UNWIND_DATA_REG for loongarch64 --- library/std/src/personality/gcc.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/std/src/personality/gcc.rs b/library/std/src/personality/gcc.rs index 41c0fe725a54..0421b47be024 100644 --- a/library/std/src/personality/gcc.rs +++ b/library/std/src/personality/gcc.rs @@ -77,6 +77,9 @@ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 #[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] const UNWIND_DATA_REG: (i32, i32) = (10, 11); // x10, x11 +#[cfg(target_arch = "loongarch64")] +const UNWIND_DATA_REG: (i32, i32) = (4, 5); // a0, a1 + // The following code is based on GCC's C and C++ personality routines. For reference, see: // https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c From a3f0046142aec8e00d3e8192f83a8cc0bacef9e8 Mon Sep 17 00:00:00 2001 From: zhaixiaojuan Date: Tue, 28 Mar 2023 16:18:12 +0800 Subject: [PATCH 133/272] Define MIN_ALIGN for loongarch64 --- compiler/rustc_codegen_gcc/example/alloc_system.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_codegen_gcc/example/alloc_system.rs b/compiler/rustc_codegen_gcc/example/alloc_system.rs index 9ec18da90d81..046903fe5aca 100644 --- a/compiler/rustc_codegen_gcc/example/alloc_system.rs +++ b/compiler/rustc_codegen_gcc/example/alloc_system.rs @@ -15,6 +15,7 @@ const MIN_ALIGN: usize = 8; #[cfg(any(target_arch = "x86_64", target_arch = "aarch64", + target_arch = "loongarch64", target_arch = "mips64", target_arch = "s390x", target_arch = "sparc64"))] From ed0b8af50527de7b368a87828ec9de0fb0292158 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 7 Apr 2023 20:09:15 -0700 Subject: [PATCH 134/272] The `wrapping_neg` example for unsigned types shouldn't use `i8` --- library/core/src/num/uint_macros.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 932038a0b012..114deeea3876 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1363,12 +1363,11 @@ macro_rules! uint_impl { /// /// Basic usage: /// - /// Please note that this example is shared between integer types. - /// Which explains why `i8` is used here. - /// /// ``` - /// assert_eq!(100i8.wrapping_neg(), -100); - /// assert_eq!((-128i8).wrapping_neg(), -128); + #[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".wrapping_neg(), 0);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.wrapping_neg(), 1);")] + #[doc = concat!("assert_eq!(13_", stringify!($SelfT), ".wrapping_neg(), (!13) + 1);")] + #[doc = concat!("assert_eq!(42_", stringify!($SelfT), ".wrapping_neg(), !(42 - 1));")] /// ``` #[stable(feature = "num_wrapping", since = "1.2.0")] #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] From 3b187c32534978fa26f4ade1cf29190a517e871e Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sat, 8 Apr 2023 09:31:55 +0000 Subject: [PATCH 135/272] Bump serde to use syn 2.0 --- Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d4fca32d750f..94be53cf8f57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5719,9 +5719,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.147" +version = "1.0.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" dependencies = [ "serde_derive", ] @@ -5738,13 +5738,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.147" +version = "1.0.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" dependencies = [ "proc-macro2", "quote", - "syn 1.0.102", + "syn 2.0.8", ] [[package]] From 2c64688d4d22e2672daa4a3eb34e8d48b37f30e4 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sat, 8 Apr 2023 09:38:57 +0000 Subject: [PATCH 136/272] bump `futures` to use syn 2.0 --- Cargo.lock | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d4fca32d750f..4461428d6dd5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1691,9 +1691,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.19" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -1706,9 +1706,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.19" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -1716,15 +1716,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.19" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.19" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -1733,38 +1733,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.19" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-macro" -version = "0.3.19" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 1.0.102", + "syn 2.0.8", ] [[package]] name = "futures-sink" -version = "0.3.19" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.19" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.19" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", From 4905a2130ad0866761ccf99b4d1a134517b7f4ab Mon Sep 17 00:00:00 2001 From: beetrees Date: Sat, 8 Apr 2023 15:03:34 +0100 Subject: [PATCH 137/272] Add `max_line_length` to `.editorconfig`, matching `rustfmt.toml` --- .editorconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/.editorconfig b/.editorconfig index ec6e107d547f..bc7642bf8c7c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,6 +11,7 @@ trim_trailing_whitespace = true insert_final_newline = true indent_style = space indent_size = 4 +max_line_length = 120 [*.md] # double whitespace at end of line From 1cf64060e37f1cafca05beb61113f82635da08b4 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Sat, 8 Apr 2023 17:08:06 +0200 Subject: [PATCH 138/272] Add "`hir::Ty` and `ty::Ty`" section --- book/src/development/type_checking.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/book/src/development/type_checking.md b/book/src/development/type_checking.md index ff08cb1e5240..5ce434b99a1a 100644 --- a/book/src/development/type_checking.md +++ b/book/src/development/type_checking.md @@ -102,6 +102,21 @@ impl LateLintPass<'_> for MyStructLint { } ``` +## `hir::Ty` and `ty::Ty` + +We've been talking about [`ty::Ty`][middle_ty] this whole time without addressing [`hir::Ty`][hir_ty], but the latter +is also important to understand. + +`hir::Ty` would represent *what* an user wrote, while `ty::Ty` would understand the meaning of it (because it has more +information). + +**Example: `fn foo(x: u32) -> u32 { x }`** + +Here the HIR sees the types without "thinking" about them, it knows that the function takes an `u32` and returns +an `u32`. But at the `ty::Ty` level the compiler understands that they're the same type, in-depth lifetimes, etc... + +you can use the [`hir_ty_to_ty`][hir_ty_to_ty] function to convert from a `hir::Ty` to a `ty::Ty` + ## Useful Links Below are some useful links to further explore the concepts covered @@ -124,3 +139,6 @@ in this chapter: [Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html [TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html [TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html +[middle_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_middle/ty/struct.Ty.html +[hir_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/struct.Ty.html +[hir_ty_to_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir_analysis/fn.hir_ty_to_ty.html From f0d487dce529d46ffe7925e9f8f0435781e49422 Mon Sep 17 00:00:00 2001 From: Petros Angelatos Date: Sat, 8 Apr 2023 19:41:50 +0200 Subject: [PATCH 139/272] sync::mpsc: synchronize receiver disconnect with initialization Receiver disconnection relies on the incorrect assumption that `head.index != tail.index` implies that the channel is initialized (i.e `head.block` and `tail.block` point to allocated blocks). However, it can happen that `head.index != tail.index` and `head.block == null` at the same time which leads to a segfault when a channel is dropped in that state. This can happen because initialization is performed in two steps. First, the tail block is allocated and the `tail.block` is set. If that is successful `head.block` is set to the same pointer. Importantly, initialization is skipped if `tail.block` is not null. Therefore we can have the following situation: 1. Thread A starts to send the first value of the channel, observes that `tail.block` is null and begins initialization. It sets `tail.block` to point to a newly allocated block and then gets preempted. `head.block` is still null at this point. 2. Thread B starts to send the second value of the channel, observes that `tail.block` *is not* null and proceeds with writing its value in the allocated tail block and sets `tail.index` to 1. 3. Thread B drops the receiver of the channel which observes that `head.index != tail.index` (0 and 1 respectively), therefore there must be messages to drop. It starts traversing the linked list from `head.block` which is still a null pointer, leading to a segfault. This PR fixes this problem by waiting for initialization to complete when `head.index != tail.index` and the `head.block` is still null. A similar check exists in `start_recv` for similar reasons. Fixes #110001 Signed-off-by: Petros Angelatos --- library/std/src/sync/mpmc/list.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/std/src/sync/mpmc/list.rs b/library/std/src/sync/mpmc/list.rs index ec6c0726ac79..406a331a3096 100644 --- a/library/std/src/sync/mpmc/list.rs +++ b/library/std/src/sync/mpmc/list.rs @@ -549,6 +549,18 @@ impl Channel { let mut head = self.head.index.load(Ordering::Acquire); let mut block = self.head.block.load(Ordering::Acquire); + // If we're going to be dropping messages we need to synchronize with initialization + if head >> SHIFT != tail >> SHIFT { + // The block can be null here only if a sender is in the process of initializing the + // channel while another sender managed to send a message by inserting it into the + // semi-initialized channel and advanced the tail. + // In that case, just wait until it gets initialized. + while block.is_null() { + backoff.spin_heavy(); + block = self.head.block.load(Ordering::Acquire); + } + } + unsafe { // Drop all messages between head and tail and deallocate the heap-allocated blocks. while head >> SHIFT != tail >> SHIFT { From 53fa6fe56fda45fc9ed0c3ae2a847e2745611f05 Mon Sep 17 00:00:00 2001 From: Patrik Kormosi Date: Sun, 9 Apr 2023 10:38:35 +0200 Subject: [PATCH 140/272] Fix typo in todo! macro docstring --- library/core/src/macros/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 529f62f4d6cd..c39a269c1de4 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -713,7 +713,7 @@ macro_rules! unimplemented { /// Indicates unfinished code. /// /// This can be useful if you are prototyping and are just looking to have your -/// code typecheck. +/// code typechecked. /// /// The difference between [`unimplemented!`] and `todo!` is that while `todo!` conveys /// an intent of implementing the functionality later and the message is "not yet From 5b57e5cec84a9c3c2f6240c9f0f4071f391fe6ab Mon Sep 17 00:00:00 2001 From: bluthej Date: Sun, 9 Apr 2023 12:20:59 +0200 Subject: [PATCH 141/272] Fix false negative with `String` and add tests `String` is currently not a diagnostic item so it needs special treatment --- clippy_lints/src/methods/clear_with_drain.rs | 12 +- tests/ui/clear_with_drain.fixed | 343 ++++++++++++++++--- tests/ui/clear_with_drain.rs | 339 +++++++++++++++--- tests/ui/clear_with_drain.stderr | 104 +++++- 4 files changed, 683 insertions(+), 115 deletions(-) diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs index 4f5b7762e3c7..6ce3fdae4074 100644 --- a/clippy_lints/src/methods/clear_with_drain.rs +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -1,16 +1,17 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_range_full; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_hir::{Expr, ExprKind, LangItem, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; use rustc_span::Span; use super::CLEAR_WITH_DRAIN; -const ACCEPTABLE_TYPES_WITH_ARG: [rustc_span::Symbol; 3] = [sym::String, sym::Vec, sym::VecDeque]; +// Add `String` here when it is added to diagnostic items +const ACCEPTABLE_TYPES_WITH_ARG: [rustc_span::Symbol; 2] = [sym::Vec, sym::VecDeque]; const ACCEPTABLE_TYPES_WITHOUT_ARG: [rustc_span::Symbol; 3] = [sym::BinaryHeap, sym::HashMap, sym::HashSet]; @@ -30,11 +31,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, types: &[rustc_span::Symbol]) -> bool { let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs(); types.iter().any(|&ty| is_type_diagnostic_item(cx, expr_ty, ty)) + // String type is a lang item but not a diagnostic item for now so we need a separate check + || is_type_lang_item(cx, expr_ty, LangItem::String) } fn suggest(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span) { if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def() - && let Some(ty_name) = cx.tcx.get_diagnostic_name(adt.did()) + // Use `opt_item_name` while `String` is not a diagnostic item + && let Some(ty_name) = cx.tcx.opt_item_name(adt.did()) { span_lint_and_sugg( cx, diff --git a/tests/ui/clear_with_drain.fixed b/tests/ui/clear_with_drain.fixed index dd02cc9148f7..2d9545eeed19 100644 --- a/tests/ui/clear_with_drain.fixed +++ b/tests/ui/clear_with_drain.fixed @@ -2,108 +2,357 @@ #![allow(unused)] #![warn(clippy::clear_with_drain)] -use std::collections::BinaryHeap; -use std::collections::HashMap; -use std::collections::HashSet; -use std::collections::VecDeque; +use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; -fn range() { +fn vec_range() { + // Do not lint because iterator is assigned let mut v = vec![1, 2, 3]; - let iter = v.drain(0..v.len()); // Yay + let iter = v.drain(0..v.len()); + // Do not lint because iterator is used let mut v = vec![1, 2, 3]; - let n = v.drain(0..v.len()).count(); // Yay + let n = v.drain(0..v.len()).count(); + // Do not lint because iterator is assigned and used let mut v = vec![1, 2, 3]; - let iter = v.drain(usize::MIN..v.len()); // Yay + let iter = v.drain(usize::MIN..v.len()); let n = iter.count(); + // Do lint let mut v = vec![1, 2, 3]; - v.clear(); // Nay + v.clear(); + // Do lint let mut v = vec![1, 2, 3]; - v.clear(); // Nay + v.clear(); } -fn range_from() { +fn vec_range_from() { + // Do not lint because iterator is assigned let mut v = vec![1, 2, 3]; - let iter = v.drain(0..); // Yay + let iter = v.drain(0..); + // Do not lint because iterator is assigned and used let mut v = vec![1, 2, 3]; - let mut iter = v.drain(0..); // Yay + let mut iter = v.drain(0..); let next = iter.next(); + // Do not lint because iterator is used let mut v = vec![1, 2, 3]; - let next = v.drain(usize::MIN..).next(); // Yay + let next = v.drain(usize::MIN..).next(); + // Do lint let mut v = vec![1, 2, 3]; - v.clear(); // Nay + v.clear(); + // Do lint let mut v = vec![1, 2, 3]; - v.clear(); // Nay + v.clear(); } -fn range_full() { +fn vec_range_full() { + // Do not lint because iterator is assigned let mut v = vec![1, 2, 3]; - let iter = v.drain(..); // Yay + let iter = v.drain(..); + // Do not lint because iterator is used let mut v = vec![1, 2, 3]; - // Yay for x in v.drain(..) { let y = format!("x = {x}"); } + // Do lint let mut v = vec![1, 2, 3]; - v.clear(); // Nay + v.clear(); } -fn range_to() { +fn vec_range_to() { + // Do not lint because iterator is assigned let mut v = vec![1, 2, 3]; - let iter = v.drain(..v.len()); // Yay + let iter = v.drain(..v.len()); + // Do not lint because iterator is assigned and used let mut v = vec![1, 2, 3]; - let iter = v.drain(..v.len()); // Yay + let iter = v.drain(..v.len()); for x in iter { let y = format!("x = {x}"); } + // Do lint let mut v = vec![1, 2, 3]; - v.clear(); // Nay + v.clear(); } -fn partial_drains() { - let mut v = vec![1, 2, 3]; - v.drain(1..); // Yay - let mut v = vec![1, 2, 3]; - v.drain(1..).max(); // Yay +fn vec_partial_drains() { + // Do not lint any of these because the ranges are not full let mut v = vec![1, 2, 3]; - v.drain(..v.len() - 1); // Yay + v.drain(1..); let mut v = vec![1, 2, 3]; - v.drain(..v.len() - 1).min(); // Yay + v.drain(1..).max(); let mut v = vec![1, 2, 3]; - v.drain(1..v.len() - 1); // Yay + v.drain(..v.len() - 1); let mut v = vec![1, 2, 3]; - let w: Vec = v.drain(1..v.len() - 1).collect(); // Yay + v.drain(..v.len() - 1).min(); + + let mut v = vec![1, 2, 3]; + v.drain(1..v.len() - 1); + let mut v = vec![1, 2, 3]; + let w: Vec = v.drain(1..v.len() - 1).collect(); } -fn main() { - let mut deque: VecDeque<_> = [1, 2, 3].into(); +fn vec_deque_range() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(0..deque.len()); + + // Do not lint because iterator is used + let mut deque = VecDeque::from([1, 2, 3]); + let n = deque.drain(0..deque.len()).count(); + + // Do not lint because iterator is assigned and used + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(usize::MIN..deque.len()); + let n = iter.count(); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); deque.clear(); + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.clear(); +} + +fn vec_deque_range_from() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(0..); + + // Do not lint because iterator is assigned and used + let mut deque = VecDeque::from([1, 2, 3]); + let mut iter = deque.drain(0..); + let next = iter.next(); + + // Do not lint because iterator is used + let mut deque = VecDeque::from([1, 2, 3]); + let next = deque.drain(usize::MIN..).next(); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.clear(); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.clear(); +} + +fn vec_deque_range_full() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(..); + + // Do not lint because iterator is used + let mut deque = VecDeque::from([1, 2, 3]); + for x in deque.drain(..) { + let y = format!("x = {x}"); + } + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.clear(); +} + +fn vec_deque_range_to() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(..deque.len()); + + // Do not lint because iterator is assigned and used + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(..deque.len()); + for x in iter { + let y = format!("x = {x}"); + } + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.clear(); +} + +fn vec_deque_partial_drains() { + // Do not lint any of these because the ranges are not full + + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(1..); + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(1..).max(); + + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(..deque.len() - 1); + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(..deque.len() - 1).min(); + + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(1..deque.len() - 1); + let mut deque = VecDeque::from([1, 2, 3]); + let w: Vec = deque.drain(1..deque.len() - 1).collect(); +} + +fn string_range() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(0..s.len()); + + // Do not lint because iterator is used + let mut s = String::from("Hello, world!"); + let n = s.drain(0..s.len()).count(); + + // Do not lint because iterator is assigned and used + let mut s = String::from("Hello, world!"); + let iter = s.drain(usize::MIN..s.len()); + let n = iter.count(); + + // Do lint + let mut s = String::from("Hello, world!"); + s.clear(); + + // Do lint + let mut s = String::from("Hello, world!"); + s.clear(); +} + +fn string_range_from() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(0..); + + // Do not lint because iterator is assigned and used + let mut s = String::from("Hello, world!"); + let mut iter = s.drain(0..); + let next = iter.next(); + + // Do not lint because iterator is used + let mut s = String::from("Hello, world!"); + let next = s.drain(usize::MIN..).next(); + + // Do lint + let mut s = String::from("Hello, world!"); + s.clear(); + + // Do lint + let mut s = String::from("Hello, world!"); + s.clear(); +} + +fn string_range_full() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(..); + + // Do not lint because iterator is used + let mut s = String::from("Hello, world!"); + for x in s.drain(..) { + let y = format!("x = {x}"); + } + + // Do lint + let mut s = String::from("Hello, world!"); + s.clear(); +} + +fn string_range_to() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(..s.len()); + + // Do not lint because iterator is assigned and used + let mut s = String::from("Hello, world!"); + let iter = s.drain(..s.len()); + for x in iter { + let y = format!("x = {x}"); + } + + // Do lint + let mut s = String::from("Hello, world!"); + s.clear(); +} + +fn string_partial_drains() { + // Do not lint any of these because the ranges are not full + + let mut s = String::from("Hello, world!"); + s.drain(1..); + let mut s = String::from("Hello, world!"); + s.drain(1..).max(); + + let mut s = String::from("Hello, world!"); + s.drain(..s.len() - 1); + let mut s = String::from("Hello, world!"); + s.drain(..s.len() - 1).min(); + + let mut s = String::from("Hello, world!"); + s.drain(1..s.len() - 1); + let mut s = String::from("Hello, world!"); + let w: String = s.drain(1..s.len() - 1).collect(); +} + +fn hash_set() { + // Do not lint because iterator is assigned + let mut set = HashSet::from([1, 2, 3]); + let iter = set.drain(); + + // Do not lint because iterator is assigned and used + let mut set = HashSet::from([1, 2, 3]); + let mut iter = set.drain(); + let next = iter.next(); + + // Do not lint because iterator is used + let mut set = HashSet::from([1, 2, 3]); + let next = set.drain().next(); + + // Do lint let mut set = HashSet::from([1, 2, 3]); set.clear(); - - let mut a = HashMap::new(); - a.insert(1, "a"); - a.insert(2, "b"); - a.clear(); - - let mut heap = BinaryHeap::from([1, 3]); - heap.clear(); - - // Not firing for now because `String` is not reckognized by `is_type_diagnostic_item` - let mut s = String::from("α is alpha, β is beta"); - s.drain(..); } + +fn hash_map() { + // Do not lint because iterator is assigned + let mut map = HashMap::from([(1, "a"), (2, "b")]); + let iter = map.drain(); + + // Do not lint because iterator is assigned and used + let mut map = HashMap::from([(1, "a"), (2, "b")]); + let mut iter = map.drain(); + let next = iter.next(); + + // Do not lint because iterator is used + let mut map = HashMap::from([(1, "a"), (2, "b")]); + let next = map.drain().next(); + + // Do lint + let mut map = HashMap::from([(1, "a"), (2, "b")]); + map.clear(); +} + +fn binary_heap() { + // Do not lint because iterator is assigned + let mut heap = BinaryHeap::from([1, 2]); + let iter = heap.drain(); + + // Do not lint because iterator is assigned and used + let mut heap = BinaryHeap::from([1, 2]); + let mut iter = heap.drain(); + let next = iter.next(); + + // Do not lint because iterator is used + let mut heap = BinaryHeap::from([1, 2]); + let next = heap.drain().next(); + + // Do lint + let mut heap = BinaryHeap::from([1, 2]); + heap.clear(); +} + +fn main() {} diff --git a/tests/ui/clear_with_drain.rs b/tests/ui/clear_with_drain.rs index af2fe503d9a6..4d60ee46e186 100644 --- a/tests/ui/clear_with_drain.rs +++ b/tests/ui/clear_with_drain.rs @@ -2,108 +2,357 @@ #![allow(unused)] #![warn(clippy::clear_with_drain)] -use std::collections::BinaryHeap; -use std::collections::HashMap; -use std::collections::HashSet; -use std::collections::VecDeque; +use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; -fn range() { +fn vec_range() { + // Do not lint because iterator is assigned let mut v = vec![1, 2, 3]; - let iter = v.drain(0..v.len()); // Yay + let iter = v.drain(0..v.len()); + // Do not lint because iterator is used let mut v = vec![1, 2, 3]; - let n = v.drain(0..v.len()).count(); // Yay + let n = v.drain(0..v.len()).count(); + // Do not lint because iterator is assigned and used let mut v = vec![1, 2, 3]; - let iter = v.drain(usize::MIN..v.len()); // Yay + let iter = v.drain(usize::MIN..v.len()); let n = iter.count(); + // Do lint let mut v = vec![1, 2, 3]; - v.drain(0..v.len()); // Nay + v.drain(0..v.len()); + // Do lint let mut v = vec![1, 2, 3]; - v.drain(usize::MIN..v.len()); // Nay + v.drain(usize::MIN..v.len()); } -fn range_from() { +fn vec_range_from() { + // Do not lint because iterator is assigned let mut v = vec![1, 2, 3]; - let iter = v.drain(0..); // Yay + let iter = v.drain(0..); + // Do not lint because iterator is assigned and used let mut v = vec![1, 2, 3]; - let mut iter = v.drain(0..); // Yay + let mut iter = v.drain(0..); let next = iter.next(); + // Do not lint because iterator is used let mut v = vec![1, 2, 3]; - let next = v.drain(usize::MIN..).next(); // Yay + let next = v.drain(usize::MIN..).next(); + // Do lint let mut v = vec![1, 2, 3]; - v.drain(0..); // Nay + v.drain(0..); + // Do lint let mut v = vec![1, 2, 3]; - v.drain(usize::MIN..); // Nay + v.drain(usize::MIN..); } -fn range_full() { +fn vec_range_full() { + // Do not lint because iterator is assigned let mut v = vec![1, 2, 3]; - let iter = v.drain(..); // Yay + let iter = v.drain(..); + // Do not lint because iterator is used let mut v = vec![1, 2, 3]; - // Yay for x in v.drain(..) { let y = format!("x = {x}"); } + // Do lint let mut v = vec![1, 2, 3]; - v.drain(..); // Nay + v.drain(..); } -fn range_to() { +fn vec_range_to() { + // Do not lint because iterator is assigned let mut v = vec![1, 2, 3]; - let iter = v.drain(..v.len()); // Yay + let iter = v.drain(..v.len()); + // Do not lint because iterator is assigned and used let mut v = vec![1, 2, 3]; - let iter = v.drain(..v.len()); // Yay + let iter = v.drain(..v.len()); for x in iter { let y = format!("x = {x}"); } + // Do lint let mut v = vec![1, 2, 3]; - v.drain(..v.len()); // Nay + v.drain(..v.len()); } -fn partial_drains() { - let mut v = vec![1, 2, 3]; - v.drain(1..); // Yay - let mut v = vec![1, 2, 3]; - v.drain(1..).max(); // Yay +fn vec_partial_drains() { + // Do not lint any of these because the ranges are not full let mut v = vec![1, 2, 3]; - v.drain(..v.len() - 1); // Yay + v.drain(1..); let mut v = vec![1, 2, 3]; - v.drain(..v.len() - 1).min(); // Yay + v.drain(1..).max(); let mut v = vec![1, 2, 3]; - v.drain(1..v.len() - 1); // Yay + v.drain(..v.len() - 1); let mut v = vec![1, 2, 3]; - let w: Vec = v.drain(1..v.len() - 1).collect(); // Yay + v.drain(..v.len() - 1).min(); + + let mut v = vec![1, 2, 3]; + v.drain(1..v.len() - 1); + let mut v = vec![1, 2, 3]; + let w: Vec = v.drain(1..v.len() - 1).collect(); } -fn main() { - let mut deque: VecDeque<_> = [1, 2, 3].into(); +fn vec_deque_range() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(0..deque.len()); + + // Do not lint because iterator is used + let mut deque = VecDeque::from([1, 2, 3]); + let n = deque.drain(0..deque.len()).count(); + + // Do not lint because iterator is assigned and used + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(usize::MIN..deque.len()); + let n = iter.count(); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(0..deque.len()); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(usize::MIN..deque.len()); +} + +fn vec_deque_range_from() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(0..); + + // Do not lint because iterator is assigned and used + let mut deque = VecDeque::from([1, 2, 3]); + let mut iter = deque.drain(0..); + let next = iter.next(); + + // Do not lint because iterator is used + let mut deque = VecDeque::from([1, 2, 3]); + let next = deque.drain(usize::MIN..).next(); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(0..); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(usize::MIN..); +} + +fn vec_deque_range_full() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(..); + + // Do not lint because iterator is used + let mut deque = VecDeque::from([1, 2, 3]); + for x in deque.drain(..) { + let y = format!("x = {x}"); + } + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); deque.drain(..); +} - let mut set = HashSet::from([1, 2, 3]); - set.drain(); +fn vec_deque_range_to() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(..deque.len()); - let mut a = HashMap::new(); - a.insert(1, "a"); - a.insert(2, "b"); - a.drain(); + // Do not lint because iterator is assigned and used + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(..deque.len()); + for x in iter { + let y = format!("x = {x}"); + } - let mut heap = BinaryHeap::from([1, 3]); - heap.drain(); + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(..deque.len()); +} - // Not firing for now because `String` is not reckognized by `is_type_diagnostic_item` - let mut s = String::from("α is alpha, β is beta"); +fn vec_deque_partial_drains() { + // Do not lint any of these because the ranges are not full + + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(1..); + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(1..).max(); + + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(..deque.len() - 1); + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(..deque.len() - 1).min(); + + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(1..deque.len() - 1); + let mut deque = VecDeque::from([1, 2, 3]); + let w: Vec = deque.drain(1..deque.len() - 1).collect(); +} + +fn string_range() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(0..s.len()); + + // Do not lint because iterator is used + let mut s = String::from("Hello, world!"); + let n = s.drain(0..s.len()).count(); + + // Do not lint because iterator is assigned and used + let mut s = String::from("Hello, world!"); + let iter = s.drain(usize::MIN..s.len()); + let n = iter.count(); + + // Do lint + let mut s = String::from("Hello, world!"); + s.drain(0..s.len()); + + // Do lint + let mut s = String::from("Hello, world!"); + s.drain(usize::MIN..s.len()); +} + +fn string_range_from() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(0..); + + // Do not lint because iterator is assigned and used + let mut s = String::from("Hello, world!"); + let mut iter = s.drain(0..); + let next = iter.next(); + + // Do not lint because iterator is used + let mut s = String::from("Hello, world!"); + let next = s.drain(usize::MIN..).next(); + + // Do lint + let mut s = String::from("Hello, world!"); + s.drain(0..); + + // Do lint + let mut s = String::from("Hello, world!"); + s.drain(usize::MIN..); +} + +fn string_range_full() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(..); + + // Do not lint because iterator is used + let mut s = String::from("Hello, world!"); + for x in s.drain(..) { + let y = format!("x = {x}"); + } + + // Do lint + let mut s = String::from("Hello, world!"); s.drain(..); } + +fn string_range_to() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(..s.len()); + + // Do not lint because iterator is assigned and used + let mut s = String::from("Hello, world!"); + let iter = s.drain(..s.len()); + for x in iter { + let y = format!("x = {x}"); + } + + // Do lint + let mut s = String::from("Hello, world!"); + s.drain(..s.len()); +} + +fn string_partial_drains() { + // Do not lint any of these because the ranges are not full + + let mut s = String::from("Hello, world!"); + s.drain(1..); + let mut s = String::from("Hello, world!"); + s.drain(1..).max(); + + let mut s = String::from("Hello, world!"); + s.drain(..s.len() - 1); + let mut s = String::from("Hello, world!"); + s.drain(..s.len() - 1).min(); + + let mut s = String::from("Hello, world!"); + s.drain(1..s.len() - 1); + let mut s = String::from("Hello, world!"); + let w: String = s.drain(1..s.len() - 1).collect(); +} + +fn hash_set() { + // Do not lint because iterator is assigned + let mut set = HashSet::from([1, 2, 3]); + let iter = set.drain(); + + // Do not lint because iterator is assigned and used + let mut set = HashSet::from([1, 2, 3]); + let mut iter = set.drain(); + let next = iter.next(); + + // Do not lint because iterator is used + let mut set = HashSet::from([1, 2, 3]); + let next = set.drain().next(); + + // Do lint + let mut set = HashSet::from([1, 2, 3]); + set.drain(); +} + +fn hash_map() { + // Do not lint because iterator is assigned + let mut map = HashMap::from([(1, "a"), (2, "b")]); + let iter = map.drain(); + + // Do not lint because iterator is assigned and used + let mut map = HashMap::from([(1, "a"), (2, "b")]); + let mut iter = map.drain(); + let next = iter.next(); + + // Do not lint because iterator is used + let mut map = HashMap::from([(1, "a"), (2, "b")]); + let next = map.drain().next(); + + // Do lint + let mut map = HashMap::from([(1, "a"), (2, "b")]); + map.drain(); +} + +fn binary_heap() { + // Do not lint because iterator is assigned + let mut heap = BinaryHeap::from([1, 2]); + let iter = heap.drain(); + + // Do not lint because iterator is assigned and used + let mut heap = BinaryHeap::from([1, 2]); + let mut iter = heap.drain(); + let next = iter.next(); + + // Do not lint because iterator is used + let mut heap = BinaryHeap::from([1, 2]); + let next = heap.drain().next(); + + // Do lint + let mut heap = BinaryHeap::from([1, 2]); + heap.drain(); +} + +fn main() {} diff --git a/tests/ui/clear_with_drain.stderr b/tests/ui/clear_with_drain.stderr index 2c0cc846de2d..20158da1121b 100644 --- a/tests/ui/clear_with_drain.stderr +++ b/tests/ui/clear_with_drain.stderr @@ -1,64 +1,130 @@ error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:22:7 + --> $DIR/clear_with_drain.rs:23:7 | -LL | v.drain(0..v.len()); // Nay +LL | v.drain(0..v.len()); | ^^^^^^^^^^^^^^^^^ help: try: `clear()` | = note: `-D clippy::clear-with-drain` implied by `-D warnings` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:25:7 + --> $DIR/clear_with_drain.rs:27:7 | -LL | v.drain(usize::MIN..v.len()); // Nay +LL | v.drain(usize::MIN..v.len()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:40:7 + --> $DIR/clear_with_drain.rs:46:7 | -LL | v.drain(0..); // Nay +LL | v.drain(0..); | ^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:43:7 + --> $DIR/clear_with_drain.rs:50:7 | -LL | v.drain(usize::MIN..); // Nay +LL | v.drain(usize::MIN..); | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:57:7 + --> $DIR/clear_with_drain.rs:66:7 | -LL | v.drain(..); // Nay +LL | v.drain(..); | ^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:71:7 + --> $DIR/clear_with_drain.rs:83:7 | -LL | v.drain(..v.len()); // Nay +LL | v.drain(..v.len()); | ^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `VecDeque` - --> $DIR/clear_with_drain.rs:93:11 + --> $DIR/clear_with_drain.rs:121:11 + | +LL | deque.drain(0..deque.len()); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `VecDeque` + --> $DIR/clear_with_drain.rs:125:11 + | +LL | deque.drain(usize::MIN..deque.len()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `VecDeque` + --> $DIR/clear_with_drain.rs:144:11 + | +LL | deque.drain(0..); + | ^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `VecDeque` + --> $DIR/clear_with_drain.rs:148:11 + | +LL | deque.drain(usize::MIN..); + | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `VecDeque` + --> $DIR/clear_with_drain.rs:164:11 | LL | deque.drain(..); | ^^^^^^^^^ help: try: `clear()` +error: `drain` used to clear a `VecDeque` + --> $DIR/clear_with_drain.rs:181:11 + | +LL | deque.drain(..deque.len()); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `String` + --> $DIR/clear_with_drain.rs:219:7 + | +LL | s.drain(0..s.len()); + | ^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `String` + --> $DIR/clear_with_drain.rs:223:7 + | +LL | s.drain(usize::MIN..s.len()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `String` + --> $DIR/clear_with_drain.rs:242:7 + | +LL | s.drain(0..); + | ^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `String` + --> $DIR/clear_with_drain.rs:246:7 + | +LL | s.drain(usize::MIN..); + | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `String` + --> $DIR/clear_with_drain.rs:262:7 + | +LL | s.drain(..); + | ^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `String` + --> $DIR/clear_with_drain.rs:279:7 + | +LL | s.drain(..s.len()); + | ^^^^^^^^^^^^^^^^ help: try: `clear()` + error: `drain` used to clear a `HashSet` - --> $DIR/clear_with_drain.rs:96:9 + --> $DIR/clear_with_drain.rs:317:9 | LL | set.drain(); | ^^^^^^^ help: try: `clear()` error: `drain` used to clear a `HashMap` - --> $DIR/clear_with_drain.rs:101:7 + --> $DIR/clear_with_drain.rs:336:9 | -LL | a.drain(); - | ^^^^^^^ help: try: `clear()` +LL | map.drain(); + | ^^^^^^^ help: try: `clear()` error: `drain` used to clear a `BinaryHeap` - --> $DIR/clear_with_drain.rs:104:10 + --> $DIR/clear_with_drain.rs:355:10 | LL | heap.drain(); | ^^^^^^^ help: try: `clear()` -error: aborting due to 10 previous errors +error: aborting due to 21 previous errors From 32aa07f8323d0f1896376443b389a95f7b141bf3 Mon Sep 17 00:00:00 2001 From: bluthej Date: Sun, 9 Apr 2023 13:25:50 +0200 Subject: [PATCH 142/272] Fix false negative for `Strings` `String` is not a diagnostic item and was thus not picked up by `is_type_diagnostic_item`, leading to a false negative for `collection_is_never_read` --- clippy_lints/src/collection_is_never_read.rs | 18 ++++++++++++------ tests/ui/collection_is_never_read.rs | 20 ++++++++++++++++++++ tests/ui/collection_is_never_read.stderr | 14 +++++++++++++- 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index 10f2bef268a2..15a5b7dd2748 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -1,9 +1,9 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::for_each_expr_with_closures; use clippy_utils::{get_enclosing_block, get_parent_node, path_to_local_id}; use core::ops::ControlFlow; -use rustc_hir::{Block, ExprKind, HirId, Local, Node, PatKind}; +use rustc_hir::{Block, ExprKind, HirId, LangItem, Local, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; @@ -44,7 +44,8 @@ declare_clippy_lint! { } declare_lint_pass!(CollectionIsNeverRead => [COLLECTION_IS_NEVER_READ]); -static COLLECTIONS: [Symbol; 10] = [ +// Add `String` here when it is added to diagnostic items +static COLLECTIONS: [Symbol; 9] = [ sym::BTreeMap, sym::BTreeSet, sym::BinaryHeap, @@ -52,7 +53,6 @@ static COLLECTIONS: [Symbol; 10] = [ sym::HashSet, sym::LinkedList, sym::Option, - sym::String, sym::Vec, sym::VecDeque, ]; @@ -60,8 +60,7 @@ static COLLECTIONS: [Symbol; 10] = [ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { // Look for local variables whose type is a container. Search surrounding bock for read access. - let ty = cx.typeck_results().pat_ty(local.pat); - if COLLECTIONS.iter().any(|&sym| is_type_diagnostic_item(cx, ty, sym)) + if match_acceptable_type(cx, local, &COLLECTIONS) && let PatKind::Binding(_, local_id, _, _) = local.pat.kind && let Some(enclosing_block) = get_enclosing_block(cx, local.hir_id) && has_no_read_access(cx, local_id, enclosing_block) @@ -71,6 +70,13 @@ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead { } } +fn match_acceptable_type(cx: &LateContext<'_>, local: &Local<'_>, collections: &[rustc_span::Symbol]) -> bool { + let ty = cx.typeck_results().pat_ty(local.pat); + collections.iter().any(|&sym| is_type_diagnostic_item(cx, ty, sym)) + // String type is a lang item but not a diagnostic item for now so we need a separate check + || is_type_lang_item(cx, ty, LangItem::String) +} + fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Block<'tcx>) -> bool { let mut has_access = false; let mut has_read_access = false; diff --git a/tests/ui/collection_is_never_read.rs b/tests/ui/collection_is_never_read.rs index 068a49486cf8..ca20031bfbef 100644 --- a/tests/ui/collection_is_never_read.rs +++ b/tests/ui/collection_is_never_read.rs @@ -163,3 +163,23 @@ fn function_argument() { let x = vec![1, 2, 3]; // Ok foo(&x); } + +fn string() { + // Do lint (write without read) + let mut s = String::new(); + s.push_str("Hello, World!"); + + // Do not lint (read without write) + let mut s = String::from("Hello, World!"); + let _ = s.len(); + + // Do not lint (write and read) + let mut s = String::from("Hello, World!"); + s.push_str("foo, bar"); + let _ = s.len(); + + // Do lint the first line, but not the second + let mut s = String::from("Hello, World!"); + let t = String::from("foo, bar"); + s = t; +} diff --git a/tests/ui/collection_is_never_read.stderr b/tests/ui/collection_is_never_read.stderr index 7654b74be3d1..f5dea96116f8 100644 --- a/tests/ui/collection_is_never_read.stderr +++ b/tests/ui/collection_is_never_read.stderr @@ -48,5 +48,17 @@ error: collection is never read LL | let x = vec![1, 2, 3]; // WARNING | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: collection is never read + --> $DIR/collection_is_never_read.rs:169:5 + | +LL | let mut s = String::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:182:5 + | +LL | let mut s = String::from("Hello, World!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 10 previous errors From 423b54ac121038aefb4b9972dbab9cce13e53086 Mon Sep 17 00:00:00 2001 From: bluthej Date: Sun, 9 Apr 2023 13:29:27 +0200 Subject: [PATCH 143/272] Update documentation for `clear_with_drain` The specific type `Vec` is replaced with the generic term 'container' --- clippy_lints/src/methods/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c25f1b60aa5f..64bf55ba24c9 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3193,7 +3193,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usage of `.drain(..)` for the sole purpose of clearing a `Vec`. + /// Checks for usage of `.drain(..)` for the sole purpose of clearing a container. /// /// ### Why is this bad? /// This creates an unnecessary iterator that is dropped immediately. @@ -3213,7 +3213,7 @@ declare_clippy_lint! { #[clippy::version = "1.69.0"] pub CLEAR_WITH_DRAIN, nursery, - "calling `drain` in order to `clear` a `Vec`" + "calling `drain` in order to `clear` a container" } pub struct Methods { From 7852962820cf2cdbedf6a9a27b4c3795c09a1cff Mon Sep 17 00:00:00 2001 From: bluthej Date: Sun, 9 Apr 2023 13:37:02 +0200 Subject: [PATCH 144/272] Change `format!` style to please dogfood test --- clippy_lints/src/methods/clear_with_drain.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs index 6ce3fdae4074..67ad58d5a8c6 100644 --- a/clippy_lints/src/methods/clear_with_drain.rs +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -44,7 +44,7 @@ fn suggest(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span) { cx, CLEAR_WITH_DRAIN, span.with_hi(expr.span.hi()), - &format!("`drain` used to clear a `{}`", ty_name), + &format!("`drain` used to clear a `{ty_name}`"), "try", "clear()".to_string(), Applicability::MachineApplicable, From 5109a8a840bab0db9909a9ea3237987de45b28be Mon Sep 17 00:00:00 2001 From: Kisaragi <48310258+KisaragiEffective@users.noreply.github.com> Date: Mon, 10 Apr 2023 00:55:32 +0900 Subject: [PATCH 145/272] [missing_const_for_fn] fix #7121 --- clippy_lints/src/missing_const_for_fn.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 87bd007a26a2..0cde9cb08f8b 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -41,6 +41,7 @@ declare_clippy_lint! { /// can't be const as it calls a non-const function. Making `a` const and running Clippy again, /// will suggest to make `b` const, too. /// + /// If you are marking public function with const, doing opposite will break API compatibility. /// ### Example /// ```rust /// # struct Foo { From ba1f19ee3087f6c47a4ba0f06b21361e1d38d90f Mon Sep 17 00:00:00 2001 From: Kisaragi <48310258+KisaragiEffective@users.noreply.github.com> Date: Mon, 10 Apr 2023 01:31:30 +0900 Subject: [PATCH 146/272] apply code review suggestion Co-authored-by: llogiq --- clippy_lints/src/missing_const_for_fn.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 0cde9cb08f8b..f1831a30461a 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -41,7 +41,7 @@ declare_clippy_lint! { /// can't be const as it calls a non-const function. Making `a` const and running Clippy again, /// will suggest to make `b` const, too. /// - /// If you are marking public function with const, doing opposite will break API compatibility. + /// If you are marking a public function with `const`, removing it again will break API compatibility. /// ### Example /// ```rust /// # struct Foo { From fb927968cc3dd76353dcc9627dd5eca6ac07bf31 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 9 Apr 2023 14:56:58 -0500 Subject: [PATCH 147/272] Separate out a `rustc_llvm_env` function --- src/bootstrap/compile.rs | 130 ++++++++++++++++++++------------------- 1 file changed, 68 insertions(+), 62 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 67bd573a855c..8fb5c1460d8e 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -867,8 +867,6 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS cargo.env("RUSTC_VERIFY_LLVM_IR", "1"); } - // Pass down configuration from the LLVM build into the build of - // rustc_llvm and rustc_codegen_llvm. // // Note that this is disabled if LLVM itself is disabled or we're in a check // build. If we are in a check build we still go ahead here presuming we've @@ -878,72 +876,80 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS && (builder.kind != Kind::Check || crate::llvm::prebuilt_llvm_config(builder, target).is_ok()) { - if builder.is_rust_llvm(target) { - cargo.env("LLVM_RUSTLLVM", "1"); - } - let llvm::LlvmResult { llvm_config, .. } = builder.ensure(llvm::Llvm { target }); - cargo.env("LLVM_CONFIG", &llvm_config); - if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { - cargo.env("CFG_LLVM_ROOT", s); - } + rustc_llvm_env(builder, cargo, target) + } +} - // Some LLVM linker flags (-L and -l) may be needed to link `rustc_llvm`. Its build script - // expects these to be passed via the `LLVM_LINKER_FLAGS` env variable, separated by - // whitespace. - // - // For example: - // - on windows, when `clang-cl` is used with instrumentation, we need to manually add - // clang's runtime library resource directory so that the profiler runtime library can be - // found. This is to avoid the linker errors about undefined references to - // `__llvm_profile_instrument_memop` when linking `rustc_driver`. - let mut llvm_linker_flags = String::new(); - if builder.config.llvm_profile_generate && target.contains("msvc") { - if let Some(ref clang_cl_path) = builder.config.llvm_clang_cl { - // Add clang's runtime library directory to the search path - let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path); - llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display())); - } - } +/// Pass down configuration from the LLVM build into the build of +/// rustc_llvm and rustc_codegen_llvm. +fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) { + let target_config = builder.config.target_config.get(&target); - // The config can also specify its own llvm linker flags. - if let Some(ref s) = builder.config.llvm_ldflags { - if !llvm_linker_flags.is_empty() { - llvm_linker_flags.push_str(" "); - } - llvm_linker_flags.push_str(s); - } + if builder.is_rust_llvm(target) { + cargo.env("LLVM_RUSTLLVM", "1"); + } + let llvm::LlvmResult { llvm_config, .. } = builder.ensure(llvm::Llvm { target }); + cargo.env("LLVM_CONFIG", &llvm_config); + if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { + cargo.env("CFG_LLVM_ROOT", s); + } - // Set the linker flags via the env var that `rustc_llvm`'s build script will read. + // Some LLVM linker flags (-L and -l) may be needed to link `rustc_llvm`. Its build script + // expects these to be passed via the `LLVM_LINKER_FLAGS` env variable, separated by + // whitespace. + // + // For example: + // - on windows, when `clang-cl` is used with instrumentation, we need to manually add + // clang's runtime library resource directory so that the profiler runtime library can be + // found. This is to avoid the linker errors about undefined references to + // `__llvm_profile_instrument_memop` when linking `rustc_driver`. + let mut llvm_linker_flags = String::new(); + if builder.config.llvm_profile_generate && target.contains("msvc") { + if let Some(ref clang_cl_path) = builder.config.llvm_clang_cl { + // Add clang's runtime library directory to the search path + let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path); + llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display())); + } + } + + // The config can also specify its own llvm linker flags. + if let Some(ref s) = builder.config.llvm_ldflags { if !llvm_linker_flags.is_empty() { - cargo.env("LLVM_LINKER_FLAGS", llvm_linker_flags); + llvm_linker_flags.push_str(" "); } + llvm_linker_flags.push_str(s); + } - // Building with a static libstdc++ is only supported on linux right now, - // not for MSVC or macOS - if builder.config.llvm_static_stdcpp - && !target.contains("freebsd") - && !target.contains("msvc") - && !target.contains("apple") - && !target.contains("solaris") - { - let file = compiler_file( - builder, - builder.cxx(target).unwrap(), - target, - CLang::Cxx, - "libstdc++.a", - ); - cargo.env("LLVM_STATIC_STDCPP", file); - } - if builder.llvm_link_shared() { - cargo.env("LLVM_LINK_SHARED", "1"); - } - if builder.config.llvm_use_libcxx { - cargo.env("LLVM_USE_LIBCXX", "1"); - } - if builder.config.llvm_optimize && !builder.config.llvm_release_debuginfo { - cargo.env("LLVM_NDEBUG", "1"); - } + // Set the linker flags via the env var that `rustc_llvm`'s build script will read. + if !llvm_linker_flags.is_empty() { + cargo.env("LLVM_LINKER_FLAGS", llvm_linker_flags); + } + + // Building with a static libstdc++ is only supported on linux right now, + // not for MSVC or macOS + if builder.config.llvm_static_stdcpp + && !target.contains("freebsd") + && !target.contains("msvc") + && !target.contains("apple") + && !target.contains("solaris") + { + let file = compiler_file( + builder, + builder.cxx(target).unwrap(), + target, + CLang::Cxx, + "libstdc++.a", + ); + cargo.env("LLVM_STATIC_STDCPP", file); + } + if builder.llvm_link_shared() { + cargo.env("LLVM_LINK_SHARED", "1"); + } + if builder.config.llvm_use_libcxx { + cargo.env("LLVM_USE_LIBCXX", "1"); + } + if builder.config.llvm_optimize && !builder.config.llvm_release_debuginfo { + cargo.env("LLVM_NDEBUG", "1"); } } From 0f96c717924178c47491e94e802cca8a4a3a7175 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Tue, 17 Jan 2023 21:56:34 +0100 Subject: [PATCH 148/272] Improve the floating point parser in `dec2flt`. * Remove all remaining traces of unsafe. * Put `parse_8digits` inside a loop. * Rework parsing of inf/NaN values. --- library/core/src/num/dec2flt/common.rs | 194 ++++---------------- library/core/src/num/dec2flt/decimal.rs | 65 ++++--- library/core/src/num/dec2flt/mod.rs | 7 +- library/core/src/num/dec2flt/parse.rs | 224 +++++++++++++----------- library/core/tests/num/dec2flt/parse.rs | 2 +- 5 files changed, 196 insertions(+), 296 deletions(-) diff --git a/library/core/src/num/dec2flt/common.rs b/library/core/src/num/dec2flt/common.rs index 3e8d75df3786..11a626485191 100644 --- a/library/core/src/num/dec2flt/common.rs +++ b/library/core/src/num/dec2flt/common.rs @@ -1,165 +1,60 @@ //! Common utilities, for internal use only. -use crate::ptr; - /// Helper methods to process immutable bytes. -pub(crate) trait ByteSlice: AsRef<[u8]> { - unsafe fn first_unchecked(&self) -> u8 { - debug_assert!(!self.is_empty()); - // SAFETY: safe as long as self is not empty - unsafe { *self.as_ref().get_unchecked(0) } - } - - /// Get if the slice contains no elements. - fn is_empty(&self) -> bool { - self.as_ref().is_empty() - } - - /// Check if the slice at least `n` length. - fn check_len(&self, n: usize) -> bool { - n <= self.as_ref().len() - } - - /// Check if the first character in the slice is equal to c. - fn first_is(&self, c: u8) -> bool { - self.as_ref().first() == Some(&c) - } - - /// Check if the first character in the slice is equal to c1 or c2. - fn first_is2(&self, c1: u8, c2: u8) -> bool { - if let Some(&c) = self.as_ref().first() { c == c1 || c == c2 } else { false } - } - - /// Bounds-checked test if the first character in the slice is a digit. - fn first_isdigit(&self) -> bool { - if let Some(&c) = self.as_ref().first() { c.is_ascii_digit() } else { false } - } - - /// Check if self starts with u with a case-insensitive comparison. - fn starts_with_ignore_case(&self, u: &[u8]) -> bool { - debug_assert!(self.as_ref().len() >= u.len()); - let iter = self.as_ref().iter().zip(u.iter()); - let d = iter.fold(0, |i, (&x, &y)| i | (x ^ y)); - d == 0 || d == 32 - } - - /// Get the remaining slice after the first N elements. - fn advance(&self, n: usize) -> &[u8] { - &self.as_ref()[n..] - } - - /// Get the slice after skipping all leading characters equal c. - fn skip_chars(&self, c: u8) -> &[u8] { - let mut s = self.as_ref(); - while s.first_is(c) { - s = s.advance(1); - } - s - } - - /// Get the slice after skipping all leading characters equal c1 or c2. - fn skip_chars2(&self, c1: u8, c2: u8) -> &[u8] { - let mut s = self.as_ref(); - while s.first_is2(c1, c2) { - s = s.advance(1); - } - s - } - +pub(crate) trait ByteSlice { /// Read 8 bytes as a 64-bit integer in little-endian order. - unsafe fn read_u64_unchecked(&self) -> u64 { - debug_assert!(self.check_len(8)); - let src = self.as_ref().as_ptr() as *const u64; - // SAFETY: safe as long as self is at least 8 bytes - u64::from_le(unsafe { ptr::read_unaligned(src) }) - } + fn read_u64(&self) -> u64; - /// Try to read the next 8 bytes from the slice. - fn read_u64(&self) -> Option { - if self.check_len(8) { - // SAFETY: self must be at least 8 bytes. - Some(unsafe { self.read_u64_unchecked() }) - } else { - None - } - } - - /// Calculate the offset of slice from another. - fn offset_from(&self, other: &Self) -> isize { - other.as_ref().len() as isize - self.as_ref().len() as isize - } -} - -impl ByteSlice for [u8] {} - -/// Helper methods to process mutable bytes. -pub(crate) trait ByteSliceMut: AsMut<[u8]> { /// Write a 64-bit integer as 8 bytes in little-endian order. - unsafe fn write_u64_unchecked(&mut self, value: u64) { - debug_assert!(self.as_mut().len() >= 8); - let dst = self.as_mut().as_mut_ptr() as *mut u64; - // NOTE: we must use `write_unaligned`, since dst is not - // guaranteed to be properly aligned. Miri will warn us - // if we use `write` instead of `write_unaligned`, as expected. - // SAFETY: safe as long as self is at least 8 bytes - unsafe { - ptr::write_unaligned(dst, u64::to_le(value)); - } - } -} + fn write_u64(&mut self, value: u64); -impl ByteSliceMut for [u8] {} - -/// Bytes wrapper with specialized methods for ASCII characters. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) struct AsciiStr<'a> { - slc: &'a [u8], -} - -impl<'a> AsciiStr<'a> { - pub fn new(slc: &'a [u8]) -> Self { - Self { slc } - } - - /// Advance the view by n, advancing it in-place to (n..). - pub unsafe fn step_by(&mut self, n: usize) -> &mut Self { - // SAFETY: safe as long n is less than the buffer length - self.slc = unsafe { self.slc.get_unchecked(n..) }; - self - } - - /// Advance the view by n, advancing it in-place to (1..). - pub unsafe fn step(&mut self) -> &mut Self { - // SAFETY: safe as long as self is not empty - unsafe { self.step_by(1) } - } + /// Calculate the offset of a slice from another. + fn offset_from(&self, other: &Self) -> isize; /// Iteratively parse and consume digits from bytes. - pub fn parse_digits(&mut self, mut func: impl FnMut(u8)) { - while let Some(&c) = self.as_ref().first() { + /// Returns the same bytes with consumed digits being + /// elided. + fn parse_digits(&self, func: impl FnMut(u8)) -> &Self; +} + +impl ByteSlice for [u8] { + #[inline(always)] // inlining this is crucial to remove bound checks + fn read_u64(&self) -> u64 { + let mut tmp = [0; 8]; + tmp.copy_from_slice(&self[..8]); + u64::from_le_bytes(tmp) + } + + #[inline(always)] // inlining this is crucial to remove bound checks + fn write_u64(&mut self, value: u64) { + self[..8].copy_from_slice(&value.to_le_bytes()) + } + + #[inline] + fn offset_from(&self, other: &Self) -> isize { + other.len() as isize - self.len() as isize + } + + #[inline] + fn parse_digits(&self, mut func: impl FnMut(u8)) -> &Self { + let mut s = self; + + // FIXME: Can't use s.split_first() here yet, + // see https://github.com/rust-lang/rust/issues/109328 + while let [c, s_next @ ..] = s { let c = c.wrapping_sub(b'0'); if c < 10 { func(c); - // SAFETY: self cannot be empty - unsafe { - self.step(); - } + s = s_next; } else { break; } } + + s } } -impl<'a> AsRef<[u8]> for AsciiStr<'a> { - #[inline] - fn as_ref(&self) -> &[u8] { - self.slc - } -} - -impl<'a> ByteSlice for AsciiStr<'a> {} - /// Determine if 8 bytes are all decimal digits. /// This does not care about the order in which the bytes were loaded. pub(crate) fn is_8digits(v: u64) -> bool { @@ -168,19 +63,6 @@ pub(crate) fn is_8digits(v: u64) -> bool { (a | b) & 0x8080_8080_8080_8080 == 0 } -/// Iteratively parse and consume digits from bytes. -pub(crate) fn parse_digits(s: &mut &[u8], mut f: impl FnMut(u8)) { - while let Some(&c) = s.get(0) { - let c = c.wrapping_sub(b'0'); - if c < 10 { - f(c); - *s = s.advance(1); - } else { - break; - } - } -} - /// A custom 64-bit floating point type, representing `f * 2^e`. /// e is biased, so it be directly shifted into the exponent bits. #[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] diff --git a/library/core/src/num/dec2flt/decimal.rs b/library/core/src/num/dec2flt/decimal.rs index 2019f71e69b8..350f64bb4f7a 100644 --- a/library/core/src/num/dec2flt/decimal.rs +++ b/library/core/src/num/dec2flt/decimal.rs @@ -9,7 +9,7 @@ //! algorithm can be found in "ParseNumberF64 by Simple Decimal Conversion", //! available online: . -use crate::num::dec2flt::common::{is_8digits, parse_digits, ByteSlice, ByteSliceMut}; +use crate::num::dec2flt::common::{is_8digits, ByteSlice}; #[derive(Clone)] pub struct Decimal { @@ -205,29 +205,32 @@ impl Decimal { pub fn parse_decimal(mut s: &[u8]) -> Decimal { let mut d = Decimal::default(); let start = s; - s = s.skip_chars(b'0'); - parse_digits(&mut s, |digit| d.try_add_digit(digit)); - if s.first_is(b'.') { - s = s.advance(1); + + while let Some((&b'0', s_next)) = s.split_first() { + s = s_next; + } + + s = s.parse_digits(|digit| d.try_add_digit(digit)); + + if let Some((b'.', s_next)) = s.split_first() { + s = s_next; let first = s; // Skip leading zeros. if d.num_digits == 0 { - s = s.skip_chars(b'0'); + while let Some((&b'0', s_next)) = s.split_first() { + s = s_next; + } } while s.len() >= 8 && d.num_digits + 8 < Decimal::MAX_DIGITS { - // SAFETY: s is at least 8 bytes. - let v = unsafe { s.read_u64_unchecked() }; + let v = s.read_u64(); if !is_8digits(v) { break; } - // SAFETY: d.num_digits + 8 is less than d.digits.len() - unsafe { - d.digits[d.num_digits..].write_u64_unchecked(v - 0x3030_3030_3030_3030); - } + d.digits[d.num_digits..].write_u64(v - 0x3030_3030_3030_3030); d.num_digits += 8; - s = s.advance(8); + s = &s[8..]; } - parse_digits(&mut s, |digit| d.try_add_digit(digit)); + s = s.parse_digits(|digit| d.try_add_digit(digit)); d.decimal_point = s.len() as i32 - first.len() as i32; } if d.num_digits != 0 { @@ -248,22 +251,26 @@ pub fn parse_decimal(mut s: &[u8]) -> Decimal { d.num_digits = Decimal::MAX_DIGITS; } } - if s.first_is2(b'e', b'E') { - s = s.advance(1); - let mut neg_exp = false; - if s.first_is(b'-') { - neg_exp = true; - s = s.advance(1); - } else if s.first_is(b'+') { - s = s.advance(1); - } - let mut exp_num = 0_i32; - parse_digits(&mut s, |digit| { - if exp_num < 0x10000 { - exp_num = 10 * exp_num + digit as i32; + if let Some((&ch, s_next)) = s.split_first() { + if ch == b'e' || ch == b'E' { + s = s_next; + let mut neg_exp = false; + if let Some((&ch, s_next)) = s.split_first() { + neg_exp = ch == b'-'; + if ch == b'-' || ch == b'+' { + s = s_next; + } } - }); - d.decimal_point += if neg_exp { -exp_num } else { exp_num }; + let mut exp_num = 0_i32; + + s.parse_digits(|digit| { + if exp_num < 0x10000 { + exp_num = 10 * exp_num + digit as i32; + } + }); + + d.decimal_point += if neg_exp { -exp_num } else { exp_num }; + } } for i in d.num_digits..Decimal::MAX_DIGITS_WITHOUT_OVERFLOW { d.digits[i] = 0; diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index 58ffb950ad86..a4bc8b1c9b0c 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -79,7 +79,7 @@ use crate::error::Error; use crate::fmt; use crate::str::FromStr; -use self::common::{BiasedFp, ByteSlice}; +use self::common::BiasedFp; use self::float::RawFloat; use self::lemire::compute_float; use self::parse::{parse_inf_nan, parse_number}; @@ -238,17 +238,18 @@ pub fn dec2flt(s: &str) -> Result { }; let negative = c == b'-'; if c == b'-' || c == b'+' { - s = s.advance(1); + s = &s[1..]; } if s.is_empty() { return Err(pfe_invalid()); } - let num = match parse_number(s, negative) { + let mut num = match parse_number(s) { Some(r) => r, None if let Some(value) = parse_inf_nan(s, negative) => return Ok(value), None => return Err(pfe_invalid()), }; + num.negative = negative; if let Some(value) = num.try_fast_path::() { return Ok(value); } diff --git a/library/core/src/num/dec2flt/parse.rs b/library/core/src/num/dec2flt/parse.rs index 1a90e0d206fd..b0a23835c5bd 100644 --- a/library/core/src/num/dec2flt/parse.rs +++ b/library/core/src/num/dec2flt/parse.rs @@ -1,6 +1,6 @@ //! Functions to parse floating-point numbers. -use crate::num::dec2flt::common::{is_8digits, AsciiStr, ByteSlice}; +use crate::num::dec2flt::common::{is_8digits, ByteSlice}; use crate::num::dec2flt::float::RawFloat; use crate::num::dec2flt::number::Number; @@ -26,24 +26,39 @@ fn parse_8digits(mut v: u64) -> u64 { } /// Parse digits until a non-digit character is found. -fn try_parse_digits(s: &mut AsciiStr<'_>, x: &mut u64) { +fn try_parse_digits(mut s: &[u8], mut x: u64) -> (&[u8], u64) { // may cause overflows, to be handled later - s.parse_digits(|digit| { - *x = x.wrapping_mul(10).wrapping_add(digit as _); + + while s.len() >= 8 { + let num = s.read_u64(); + if is_8digits(num) { + x = x.wrapping_mul(1_0000_0000).wrapping_add(parse_8digits(num)); + s = &s[8..]; + } else { + break; + } + } + + s = s.parse_digits(|digit| { + x = x.wrapping_mul(10).wrapping_add(digit as _); }); + + (s, x) } /// Parse up to 19 digits (the max that can be stored in a 64-bit integer). -fn try_parse_19digits(s: &mut AsciiStr<'_>, x: &mut u64) { +fn try_parse_19digits(s_ref: &mut &[u8], x: &mut u64) { + let mut s = *s_ref; + while *x < MIN_19DIGIT_INT { - if let Some(&c) = s.as_ref().first() { + // FIXME: Can't use s.split_first() here yet, + // see https://github.com/rust-lang/rust/issues/109328 + if let [c, s_next @ ..] = s { let digit = c.wrapping_sub(b'0'); + if digit < 10 { *x = (*x * 10) + digit as u64; // no overflows here - // SAFETY: cannot be empty - unsafe { - s.step(); - } + s = s_next; } else { break; } @@ -51,46 +66,26 @@ fn try_parse_19digits(s: &mut AsciiStr<'_>, x: &mut u64) { break; } } -} -/// Try to parse 8 digits at a time, using an optimized algorithm. -fn try_parse_8digits(s: &mut AsciiStr<'_>, x: &mut u64) { - // may cause overflows, to be handled later - if let Some(v) = s.read_u64() { - if is_8digits(v) { - *x = x.wrapping_mul(1_0000_0000).wrapping_add(parse_8digits(v)); - // SAFETY: already ensured the buffer was >= 8 bytes in read_u64. - unsafe { - s.step_by(8); - } - if let Some(v) = s.read_u64() { - if is_8digits(v) { - *x = x.wrapping_mul(1_0000_0000).wrapping_add(parse_8digits(v)); - // SAFETY: already ensured the buffer was >= 8 bytes in try_read_u64. - unsafe { - s.step_by(8); - } - } - } - } - } + *s_ref = s; } /// Parse the scientific notation component of a float. -fn parse_scientific(s: &mut AsciiStr<'_>) -> Option { - let mut exponent = 0_i64; +fn parse_scientific(s_ref: &mut &[u8]) -> Option { + let mut exponent = 0i64; let mut negative = false; - if let Some(&c) = s.as_ref().get(0) { + + let mut s = *s_ref; + + if let Some((&c, s_next)) = s.split_first() { negative = c == b'-'; if c == b'-' || c == b'+' { - // SAFETY: s cannot be empty - unsafe { - s.step(); - } + s = s_next; } } - if s.first_isdigit() { - s.parse_digits(|digit| { + + if matches!(s.first(), Some(&x) if x.is_ascii_digit()) { + *s_ref = s.parse_digits(|digit| { // no overflows here, saturate well before overflow if exponent < 0x10000 { exponent = 10 * exponent + digit as i64; @@ -98,6 +93,7 @@ fn parse_scientific(s: &mut AsciiStr<'_>) -> Option { }); if negative { Some(-exponent) } else { Some(exponent) } } else { + *s_ref = s; None } } @@ -106,28 +102,29 @@ fn parse_scientific(s: &mut AsciiStr<'_>) -> Option { /// /// This creates a representation of the float as the /// significant digits and the decimal exponent. -fn parse_partial_number(s: &[u8], negative: bool) -> Option<(Number, usize)> { - let mut s = AsciiStr::new(s); - let start = s; +fn parse_partial_number(mut s: &[u8]) -> Option<(Number, usize)> { debug_assert!(!s.is_empty()); // parse initial digits before dot let mut mantissa = 0_u64; - let digits_start = s; - try_parse_digits(&mut s, &mut mantissa); - let mut n_digits = s.offset_from(&digits_start); + let start = s; + let tmp = try_parse_digits(s, mantissa); + s = tmp.0; + mantissa = tmp.1; + let mut n_digits = s.offset_from(start); // handle dot with the following digits let mut n_after_dot = 0; let mut exponent = 0_i64; let int_end = s; - if s.first_is(b'.') { - // SAFETY: s cannot be empty due to first_is - unsafe { s.step() }; + + if let Some((&b'.', s_next)) = s.split_first() { + s = s_next; let before = s; - try_parse_8digits(&mut s, &mut mantissa); - try_parse_digits(&mut s, &mut mantissa); - n_after_dot = s.offset_from(&before); + let tmp = try_parse_digits(s, mantissa); + s = tmp.0; + mantissa = tmp.1; + n_after_dot = s.offset_from(before); exponent = -n_after_dot as i64; } @@ -138,65 +135,60 @@ fn parse_partial_number(s: &[u8], negative: bool) -> Option<(Number, usize)> { // handle scientific format let mut exp_number = 0_i64; - if s.first_is2(b'e', b'E') { - // SAFETY: s cannot be empty - unsafe { - s.step(); + if let Some((&c, s_next)) = s.split_first() { + if c == b'e' || c == b'E' { + s = s_next; + // If None, we have no trailing digits after exponent, or an invalid float. + exp_number = parse_scientific(&mut s)?; + exponent += exp_number; } - // If None, we have no trailing digits after exponent, or an invalid float. - exp_number = parse_scientific(&mut s)?; - exponent += exp_number; } - let len = s.offset_from(&start) as _; + let len = s.offset_from(start) as _; // handle uncommon case with many digits if n_digits <= 19 { - return Some((Number { exponent, mantissa, negative, many_digits: false }, len)); + return Some((Number { exponent, mantissa, negative: false, many_digits: false }, len)); } n_digits -= 19; let mut many_digits = false; - let mut p = digits_start; - while p.first_is2(b'0', b'.') { - // SAFETY: p cannot be empty due to first_is2 - unsafe { - // '0' = b'.' + 2 - n_digits -= p.first_unchecked().saturating_sub(b'0' - 1) as isize; - p.step(); + let mut p = start; + while let Some((&c, p_next)) = p.split_first() { + if c == b'.' || c == b'0' { + n_digits -= c.saturating_sub(b'0' - 1) as isize; + p = p_next; + } else { + break; } } if n_digits > 0 { // at this point we have more than 19 significant digits, let's try again many_digits = true; mantissa = 0; - let mut s = digits_start; + let mut s = start; try_parse_19digits(&mut s, &mut mantissa); exponent = if mantissa >= MIN_19DIGIT_INT { // big int - int_end.offset_from(&s) + int_end.offset_from(s) } else { - // SAFETY: the next byte must be present and be '.' - // We know this is true because we had more than 19 - // digits previously, so we overflowed a 64-bit integer, - // but parsing only the integral digits produced less - // than 19 digits. That means we must have a decimal - // point, and at least 1 fractional digit. - unsafe { s.step() }; + s = &s[1..]; let before = s; try_parse_19digits(&mut s, &mut mantissa); - -s.offset_from(&before) + -s.offset_from(before) } as i64; // add back the explicit part exponent += exp_number; } - Some((Number { exponent, mantissa, negative, many_digits }, len)) + Some((Number { exponent, mantissa, negative: false, many_digits }, len)) } -/// Try to parse a non-special floating point number. -pub fn parse_number(s: &[u8], negative: bool) -> Option { - if let Some((float, rest)) = parse_partial_number(s, negative) { +/// Try to parse a non-special floating point number, +/// as well as two slices with integer and fractional parts +/// and the parsed exponent. +pub fn parse_number(s: &[u8]) -> Option { + if let Some((float, rest)) = parse_partial_number(s) { if rest == s.len() { return Some(float); } @@ -204,30 +196,48 @@ pub fn parse_number(s: &[u8], negative: bool) -> Option { None } -/// Parse a partial representation of a special, non-finite float. -fn parse_partial_inf_nan(s: &[u8]) -> Option<(F, usize)> { - fn parse_inf_rest(s: &[u8]) -> usize { - if s.len() >= 8 && s[3..].as_ref().starts_with_ignore_case(b"inity") { 8 } else { 3 } - } - if s.len() >= 3 { - if s.starts_with_ignore_case(b"nan") { - return Some((F::NAN, 3)); - } else if s.starts_with_ignore_case(b"inf") { - return Some((F::INFINITY, parse_inf_rest(s))); - } - } - None -} - /// Try to parse a special, non-finite float. -pub fn parse_inf_nan(s: &[u8], negative: bool) -> Option { - if let Some((mut float, rest)) = parse_partial_inf_nan::(s) { - if rest == s.len() { - if negative { - float = -float; - } - return Some(float); - } +pub(crate) fn parse_inf_nan(s: &[u8], negative: bool) -> Option { + // Since a valid string has at most the length 8, we can load + // all relevant characters into a u64 and work from there. + // This also generates much better code. + + let mut register; + let len: usize; + + // All valid strings are either of length 8 or 3. + if s.len() == 8 { + register = s.read_u64(); + len = 8; + } else if s.len() == 3 { + let a = s[0] as u64; + let b = s[1] as u64; + let c = s[2] as u64; + register = (c << 16) | (b << 8) | a; + len = 3; + } else { + return None; } - None + + // Clear out the bits which turn ASCII uppercase characters into + // lowercase characters. The resulting string is all uppercase. + // What happens to other characters is irrelevant. + register &= 0xDFDFDFDFDFDFDFDF; + + // u64 values corresponding to relevant cases + const INF_3: u64 = 0x464E49; // "INF" + const INF_8: u64 = 0x5954494E49464E49; // "INFINITY" + const NAN: u64 = 0x4E414E; // "NAN" + + // Match register value to constant to parse string. + // Also match on the string length to catch edge cases + // like "inf\0\0\0\0\0". + let float = match (register, len) { + (INF_3, 3) => F::INFINITY, + (INF_8, 8) => F::INFINITY, + (NAN, 3) => F::NAN, + _ => return None, + }; + + if negative { Some(-float) } else { Some(float) } } diff --git a/library/core/tests/num/dec2flt/parse.rs b/library/core/tests/num/dec2flt/parse.rs index edc77377d582..4a5d24ba7d5f 100644 --- a/library/core/tests/num/dec2flt/parse.rs +++ b/library/core/tests/num/dec2flt/parse.rs @@ -32,7 +32,7 @@ fn invalid_chars() { } fn parse_positive(s: &[u8]) -> Option { - parse_number(s, false) + parse_number(s) } #[test] From d8ed2fb0bb8aecfe7622134d5aba7b670056ee6d Mon Sep 17 00:00:00 2001 From: Jakob Degen Date: Tue, 4 Apr 2023 23:07:10 -0700 Subject: [PATCH 149/272] Fix transmute intrinsic mir validation ICE --- .../rustc_const_eval/src/transform/validate.rs | 12 ++++++++++-- tests/ui/mir/validate/transmute_cast_sized.rs | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 tests/ui/mir/validate/transmute_cast_sized.rs diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 0f56fda18f56..d4bed97380ba 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -679,13 +679,21 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // Unlike `mem::transmute`, a MIR `Transmute` is well-formed // for any two `Sized` types, just potentially UB to run. - if !op_ty.is_sized(self.tcx, self.param_env) { + if !self + .tcx + .normalize_erasing_regions(self.param_env, op_ty) + .is_sized(self.tcx, self.param_env) + { self.fail( location, format!("Cannot transmute from non-`Sized` type {op_ty:?}"), ); } - if !target_type.is_sized(self.tcx, self.param_env) { + if !self + .tcx + .normalize_erasing_regions(self.param_env, *target_type) + .is_sized(self.tcx, self.param_env) + { self.fail( location, format!("Cannot transmute to non-`Sized` type {target_type:?}"), diff --git a/tests/ui/mir/validate/transmute_cast_sized.rs b/tests/ui/mir/validate/transmute_cast_sized.rs new file mode 100644 index 000000000000..eaaf7eb3ecd0 --- /dev/null +++ b/tests/ui/mir/validate/transmute_cast_sized.rs @@ -0,0 +1,17 @@ +// build-pass +// compile-flags: -Zvalidate-mir +// edition: 2021 + +#![crate_type = "lib"] + +// Use `PhantomData` to get target-independent size +async fn get(_r: std::marker::PhantomData<&i32>) { + loop {} +} + +pub fn check() { + let mut v = get(loop {}); + let _ = || unsafe { + v = std::mem::transmute([0_u8; 1]); + }; +} From b369c8ecbde710ab23977137c71b3c974a94d445 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 10 Apr 2023 06:06:01 +0000 Subject: [PATCH 150/272] Do not use ImplDerivedObligationCause for inherent impl method error reporting --- compiler/rustc_hir_typeck/src/method/probe.rs | 29 +++++------ .../rustc_hir_typeck/src/method/suggest.rs | 43 +++++++++------- tests/ui/methods/inherent-bound-in-probe.rs | 49 +++++++++++++++++++ .../ui/methods/inherent-bound-in-probe.stderr | 38 ++++++++++++++ 4 files changed, 124 insertions(+), 35 deletions(-) create mode 100644 tests/ui/methods/inherent-bound-in-probe.rs create mode 100644 tests/ui/methods/inherent-bound-in-probe.stderr diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 0092bd2c6e64..badb1a3c1882 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1522,23 +1522,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // Convert the bounds into obligations. let impl_obligations = traits::predicates_for_generics( - |_idx, span| { - let misc = traits::ObligationCause::misc(span, self.body_id); - let parent_trait_pred = ty::Binder::dummy(ty::TraitPredicate { - trait_ref: ty::TraitRef::from_method(self.tcx, impl_def_id, substs), - constness: ty::BoundConstness::NotConst, - polarity: ty::ImplPolarity::Positive, - }); - misc.derived_cause(parent_trait_pred, |derived| { - traits::ImplDerivedObligation(Box::new( - traits::ImplDerivedObligationCause { - derived, - impl_or_alias_def_id: impl_def_id, - impl_def_predicate_index: None, - span, - }, - )) - }) + |idx, span| { + let code = if span.is_dummy() { + traits::ExprItemObligation(impl_def_id, self.scope_expr_id, idx) + } else { + traits::ExprBindingObligation( + impl_def_id, + span, + self.scope_expr_id, + idx, + ) + }; + ObligationCause::new(self.span, self.body_id, code) }, self.param_env, impl_bounds, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 5c50619f4c3c..6e77c7281074 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -661,19 +661,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Find all the requirements that come from a local `impl` block. let mut skip_list: FxHashSet<_> = Default::default(); let mut spanned_predicates = FxHashMap::default(); - for (p, parent_p, impl_def_id, cause) in unsatisfied_predicates - .iter() - .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c))) - .filter_map(|(p, parent, c)| match c.code() { - ObligationCauseCode::ImplDerivedObligation(data) - if matches!(p.kind().skip_binder(), ty::PredicateKind::Clause(_)) => - { - Some((p, parent, data.impl_or_alias_def_id, data)) + for (p, parent_p, cause) in unsatisfied_predicates { + // Extract the predicate span and parent def id of the cause, + // if we have one. + let (item_def_id, cause_span) = match cause.as_ref().map(|cause| cause.code()) { + Some(ObligationCauseCode::ImplDerivedObligation(data)) => { + (data.impl_or_alias_def_id, data.span) } - _ => None, - }) - { - match self.tcx.hir().get_if_local(impl_def_id) { + Some( + ObligationCauseCode::ExprBindingObligation(def_id, span, _, _) + | ObligationCauseCode::BindingObligation(def_id, span), + ) => (*def_id, *span), + _ => continue, + }; + + // Don't point out the span of `WellFormed` predicates. + if !matches!(p.kind().skip_binder(), ty::PredicateKind::Clause(_)) { + continue; + }; + + match self.tcx.hir().get_if_local(item_def_id) { // Unmet obligation comes from a `derive` macro, point at it once to // avoid multiple span labels pointing at the same place. Some(Node::Item(hir::Item { @@ -718,7 +725,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }); for param in generics.params { - if param.span == cause.span && sized_pred { + if param.span == cause_span && sized_pred { let (sp, sugg) = match param.colon_span { Some(sp) => (sp.shrink_to_hi(), " ?Sized +"), None => (param.span.shrink_to_hi(), ": ?Sized"), @@ -741,9 +748,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (FxHashSet::default(), FxHashSet::default(), Vec::new()) }); entry.2.push(p); - if cause.span != *item_span { - entry.0.insert(cause.span); - entry.1.insert((cause.span, "unsatisfied trait bound introduced here")); + if cause_span != *item_span { + entry.0.insert(cause_span); + entry.1.insert((cause_span, "unsatisfied trait bound introduced here")); } else { if let Some(trait_ref) = of_trait { entry.0.insert(trait_ref.path.span); @@ -775,9 +782,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let entry = entry.or_insert_with(|| { (FxHashSet::default(), FxHashSet::default(), Vec::new()) }); - entry.0.insert(cause.span); + entry.0.insert(cause_span); entry.1.insert((ident.span, "")); - entry.1.insert((cause.span, "unsatisfied trait bound introduced here")); + entry.1.insert((cause_span, "unsatisfied trait bound introduced here")); entry.2.push(p); } Some(node) => unreachable!("encountered `{node:?}`"), diff --git a/tests/ui/methods/inherent-bound-in-probe.rs b/tests/ui/methods/inherent-bound-in-probe.rs new file mode 100644 index 000000000000..81a99ca010e5 --- /dev/null +++ b/tests/ui/methods/inherent-bound-in-probe.rs @@ -0,0 +1,49 @@ +// normalize-stderr-test: "long-type-\d+" -> "long-type-hash" + +// Fixes #110131 +// +// The issue is that we were constructing an `ImplDerived` cause code for the +// `&'a T: IntoIterator` obligation for `Helper::new`, which is +// incorrect because derived obligations are only expected to come from *traits*. + +struct SeqBuffer<'a, T> +where + &'a T: IntoIterator, +{ + iter: <&'a T as IntoIterator>::IntoIter, +} + +struct Helper<'a, T> +where + &'a T: IntoIterator, +{ + buf: SeqBuffer<'a, T>, +} + +impl<'a, T> Helper<'a, T> +where + &'a T: IntoIterator, +{ + fn new(sq: &'a T) -> Self { + loop {} + } +} + +struct BitReaderWrapper(T); + +impl<'a, T> IntoIterator for &'a BitReaderWrapper +where + &'a T: IntoIterator, +{ + type Item = u32; + + type IntoIter = Helper<'a, T>; + //~^ ERROR `Helper<'a, T>` is not an iterator + + fn into_iter(self) -> Self::IntoIter { + Helper::new(&self.0) + //~^ ERROR overflow evaluating the requirement `&_: IntoIterator` + } +} + +fn main() {} diff --git a/tests/ui/methods/inherent-bound-in-probe.stderr b/tests/ui/methods/inherent-bound-in-probe.stderr new file mode 100644 index 000000000000..ff03a7edb054 --- /dev/null +++ b/tests/ui/methods/inherent-bound-in-probe.stderr @@ -0,0 +1,38 @@ +error[E0277]: `Helper<'a, T>` is not an iterator + --> $DIR/inherent-bound-in-probe.rs:40:21 + | +LL | type IntoIter = Helper<'a, T>; + | ^^^^^^^^^^^^^ `Helper<'a, T>` is not an iterator + | + = help: the trait `Iterator` is not implemented for `Helper<'a, T>` +note: required by a bound in `std::iter::IntoIterator::IntoIter` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + +error[E0275]: overflow evaluating the requirement `&_: IntoIterator` + --> $DIR/inherent-bound-in-probe.rs:44:17 + | +LL | Helper::new(&self.0) + | ^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_bound_in_probe`) +note: required for `&BitReaderWrapper<_>` to implement `IntoIterator` + --> $DIR/inherent-bound-in-probe.rs:34:13 + | +LL | impl<'a, T> IntoIterator for &'a BitReaderWrapper + | ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ +LL | where +LL | &'a T: IntoIterator, + | ------------- unsatisfied trait bound introduced here + = note: 126 redundant requirements hidden + = note: required for `&BitReaderWrapper>>>>` to implement `IntoIterator` + = note: the full type name has been written to '$TEST_BUILD_DIR/methods/inherent-bound-in-probe/inherent-bound-in-probe.long-type-hash.txt' +note: required by a bound in `Helper<'a, T>` + --> $DIR/inherent-bound-in-probe.rs:25:25 + | +LL | &'a T: IntoIterator, + | ^^^^^^^^^^^^^ required by this bound in `Helper<'a, T>` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0275, E0277. +For more information about an error, try `rustc --explain E0275`. From a047064d6b0ddf82443e5e478d4dae3d0db6f379 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 10 Apr 2023 06:52:18 +0000 Subject: [PATCH 151/272] Revert "Don't recover lifetimes/labels containing emojis as character literals" Reverts PR #108031 Fixes (doesnt close until beta backported) #109746 This reverts commit e3f9db5fc319c6d8eee5d47d216ea6a426070c41. This reverts commit 98b82aedba3f3f581e89df54352914b27f42c6f7. This reverts commit 380fa264132ad481e73cbbf0f3a0feefd99a1d78. --- compiler/rustc_errors/src/lib.rs | 2 - compiler/rustc_lexer/src/lib.rs | 43 +++------- compiler/rustc_lexer/src/tests.rs | 2 +- compiler/rustc_parse/src/lexer/mod.rs | 9 +- .../lexer/issue-108019-bad-emoji-recovery.rs | 45 ---------- .../issue-108019-bad-emoji-recovery.stderr | 86 ------------------- tests/ui/parser/numeric-lifetime.rs | 4 +- tests/ui/parser/numeric-lifetime.stderr | 4 +- 8 files changed, 17 insertions(+), 178 deletions(-) delete mode 100644 tests/ui/lexer/issue-108019-bad-emoji-recovery.rs delete mode 100644 tests/ui/lexer/issue-108019-bad-emoji-recovery.stderr diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 9866a9bffe0e..17944044aae1 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -473,8 +473,6 @@ pub enum StashKey { /// When an invalid lifetime e.g. `'2` should be reinterpreted /// as a char literal in the parser LifetimeIsChar, - /// When an invalid lifetime e.g. `'🐱` contains emoji. - LifetimeContainsEmoji, /// Maybe there was a typo where a comma was forgotten before /// FRU syntax MaybeFruTypo, diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 322ec31fb2cf..b3f4b5cd5e5a 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -95,7 +95,7 @@ pub enum TokenKind { Literal { kind: LiteralKind, suffix_start: u32 }, /// "'a" - Lifetime { starts_with_number: bool, contains_emoji: bool }, + Lifetime { starts_with_number: bool }, // One-char tokens: /// ";" @@ -632,13 +632,7 @@ impl Cursor<'_> { // If the first symbol is valid for identifier, it can be a lifetime. // Also check if it's a number for a better error reporting (so '0 will // be reported as invalid lifetime and not as unterminated char literal). - // We also have to account for potential `'🐱` emojis to avoid reporting - // it as an unterminated char literal. - is_id_start(self.first()) - || self.first().is_digit(10) - // FIXME(#108019): `unic-emoji-char` seems to have data tables only up to Unicode - // 5.0, but Unicode is already newer than this. - || unic_emoji_char::is_emoji(self.first()) + is_id_start(self.first()) || self.first().is_digit(10) }; if !can_be_a_lifetime { @@ -651,33 +645,16 @@ impl Cursor<'_> { return Literal { kind, suffix_start }; } - // Either a lifetime or a character literal. + // Either a lifetime or a character literal with + // length greater than 1. let starts_with_number = self.first().is_digit(10); - let mut contains_emoji = false; - // FIXME(#108019): `unic-emoji-char` seems to have data tables only up to Unicode - // 5.0, but Unicode is already newer than this. - if unic_emoji_char::is_emoji(self.first()) { - contains_emoji = true; - } else { - // Skip the literal contents. - // First symbol can be a number (which isn't a valid identifier start), - // so skip it without any checks. - self.bump(); - } - self.eat_while(|c| { - if is_id_continue(c) { - true - // FIXME(#108019): `unic-emoji-char` seems to have data tables only up to Unicode - // 5.0, but Unicode is already newer than this. - } else if unic_emoji_char::is_emoji(c) { - contains_emoji = true; - true - } else { - false - } - }); + // Skip the literal contents. + // First symbol can be a number (which isn't a valid identifier start), + // so skip it without any checks. + self.bump(); + self.eat_while(is_id_continue); // Check if after skipping literal contents we've met a closing // single quote (which means that user attempted to create a @@ -687,7 +664,7 @@ impl Cursor<'_> { let kind = Char { terminated: true }; Literal { kind, suffix_start: self.pos_within_token() } } else { - Lifetime { starts_with_number, contains_emoji } + Lifetime { starts_with_number } } } diff --git a/compiler/rustc_lexer/src/tests.rs b/compiler/rustc_lexer/src/tests.rs index 670d64fb983f..e4c1787f2cce 100644 --- a/compiler/rustc_lexer/src/tests.rs +++ b/compiler/rustc_lexer/src/tests.rs @@ -235,7 +235,7 @@ fn lifetime() { check_lexing( "'abc", expect![[r#" - Token { kind: Lifetime { starts_with_number: false, contains_emoji: false }, len: 4 } + Token { kind: Lifetime { starts_with_number: false }, len: 4 } "#]], ); } diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 4a7da11a0978..399a86c9297a 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -223,21 +223,16 @@ impl<'a> StringReader<'a> { }; token::Literal(token::Lit { kind, symbol, suffix }) } - rustc_lexer::TokenKind::Lifetime { starts_with_number, contains_emoji } => { + rustc_lexer::TokenKind::Lifetime { starts_with_number } => { // Include the leading `'` in the real identifier, for macro // expansion purposes. See #12512 for the gory details of why // this is necessary. let lifetime_name = self.str_from(start); if starts_with_number { let span = self.mk_sp(start, self.pos); - let mut diag = self.sess.struct_err("lifetimes or labels cannot start with a number"); + let mut diag = self.sess.struct_err("lifetimes cannot start with a number"); diag.set_span(span); diag.stash(span, StashKey::LifetimeIsChar); - } else if contains_emoji { - let span = self.mk_sp(start, self.pos); - let mut diag = self.sess.struct_err("lifetimes or labels cannot contain emojis"); - diag.set_span(span); - diag.stash(span, StashKey::LifetimeContainsEmoji); } let ident = Symbol::intern(lifetime_name); token::Lifetime(ident) diff --git a/tests/ui/lexer/issue-108019-bad-emoji-recovery.rs b/tests/ui/lexer/issue-108019-bad-emoji-recovery.rs deleted file mode 100644 index f0f862245601..000000000000 --- a/tests/ui/lexer/issue-108019-bad-emoji-recovery.rs +++ /dev/null @@ -1,45 +0,0 @@ -#![allow(unused_labels)] - -// FIXME(#108019): outdated Unicode table -// fn foo() { -// '🥺 loop { -// break -// } -// } - -fn bar() { - '🐱 loop { - //~^ ERROR labeled expression must be followed by `:` - //~| ERROR lifetimes or labels cannot contain emojis - break - } -} - -fn qux() { - 'a🐱 loop { - //~^ ERROR labeled expression must be followed by `:` - //~| ERROR lifetimes or labels cannot contain emojis - break - } -} - -fn quux() { - '1🐱 loop { - //~^ ERROR labeled expression must be followed by `:` - //~| ERROR lifetimes or labels cannot start with a number - break - } -} - -fn x<'🐱>() -> &'🐱 () { - //~^ ERROR lifetimes or labels cannot contain emojis - //~| ERROR lifetimes or labels cannot contain emojis - &() -} - -fn y() { - 'a🐱: loop {} - //~^ ERROR lifetimes or labels cannot contain emojis -} - -fn main() {} diff --git a/tests/ui/lexer/issue-108019-bad-emoji-recovery.stderr b/tests/ui/lexer/issue-108019-bad-emoji-recovery.stderr deleted file mode 100644 index be77ffdea349..000000000000 --- a/tests/ui/lexer/issue-108019-bad-emoji-recovery.stderr +++ /dev/null @@ -1,86 +0,0 @@ -error: labeled expression must be followed by `:` - --> $DIR/issue-108019-bad-emoji-recovery.rs:11:5 - | -LL | '🐱 loop { - | ^--- help: add `:` after the label - | | - | _____the label - | | -LL | | -LL | | -LL | | break -LL | | } - | |_____^ - | - = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them - -error: labeled expression must be followed by `:` - --> $DIR/issue-108019-bad-emoji-recovery.rs:19:5 - | -LL | 'a🐱 loop { - | ^---- help: add `:` after the label - | | - | _____the label - | | -LL | | -LL | | -LL | | break -LL | | } - | |_____^ - | - = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them - -error: labeled expression must be followed by `:` - --> $DIR/issue-108019-bad-emoji-recovery.rs:27:5 - | -LL | '1🐱 loop { - | ^---- help: add `:` after the label - | | - | _____the label - | | -LL | | -LL | | -LL | | break -LL | | } - | |_____^ - | - = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them - -error: lifetimes or labels cannot contain emojis - --> $DIR/issue-108019-bad-emoji-recovery.rs:11:5 - | -LL | '🐱 loop { - | ^^^ - -error: lifetimes or labels cannot contain emojis - --> $DIR/issue-108019-bad-emoji-recovery.rs:19:5 - | -LL | 'a🐱 loop { - | ^^^^ - -error: lifetimes or labels cannot start with a number - --> $DIR/issue-108019-bad-emoji-recovery.rs:27:5 - | -LL | '1🐱 loop { - | ^^^^ - -error: lifetimes or labels cannot contain emojis - --> $DIR/issue-108019-bad-emoji-recovery.rs:34:6 - | -LL | fn x<'🐱>() -> &'🐱 () { - | ^^^ - -error: lifetimes or labels cannot contain emojis - --> $DIR/issue-108019-bad-emoji-recovery.rs:34:16 - | -LL | fn x<'🐱>() -> &'🐱 () { - | ^^^ - -error: lifetimes or labels cannot contain emojis - --> $DIR/issue-108019-bad-emoji-recovery.rs:41:5 - | -LL | 'a🐱: loop {} - | ^^^^ - -error: aborting due to 9 previous errors - diff --git a/tests/ui/parser/numeric-lifetime.rs b/tests/ui/parser/numeric-lifetime.rs index a082a8a44df2..2d82354c62cc 100644 --- a/tests/ui/parser/numeric-lifetime.rs +++ b/tests/ui/parser/numeric-lifetime.rs @@ -1,6 +1,6 @@ struct S<'1> { s: &'1 usize } -//~^ ERROR lifetimes or labels cannot start with a number -//~| ERROR lifetimes or labels cannot start with a number +//~^ ERROR lifetimes cannot start with a number +//~| ERROR lifetimes cannot start with a number fn main() { // verify that the parse error doesn't stop type checking let x: usize = ""; diff --git a/tests/ui/parser/numeric-lifetime.stderr b/tests/ui/parser/numeric-lifetime.stderr index 66e35dca9231..7c1bcb726317 100644 --- a/tests/ui/parser/numeric-lifetime.stderr +++ b/tests/ui/parser/numeric-lifetime.stderr @@ -6,13 +6,13 @@ LL | let x: usize = ""; | | | expected due to this -error: lifetimes or labels cannot start with a number +error: lifetimes cannot start with a number --> $DIR/numeric-lifetime.rs:1:10 | LL | struct S<'1> { s: &'1 usize } | ^^ -error: lifetimes or labels cannot start with a number +error: lifetimes cannot start with a number --> $DIR/numeric-lifetime.rs:1:20 | LL | struct S<'1> { s: &'1 usize } From afd45c2e10d9a5dbb277852384bb3d2245239f63 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 8 Apr 2023 14:24:16 +0900 Subject: [PATCH 152/272] Stabilize IsTerminal closes: https://github.com/rust-lang/rust/issues/98070 --- compiler/rustc_driver_impl/src/lib.rs | 1 - compiler/rustc_errors/src/lib.rs | 1 - compiler/rustc_log/src/lib.rs | 1 - library/std/src/io/mod.rs | 2 +- library/std/src/io/stdio.rs | 5 +++-- library/std/src/lib.rs | 1 - library/std/src/os/fd/owned.rs | 2 +- library/std/src/os/windows/io/handle.rs | 2 +- library/test/src/lib.rs | 1 - src/librustdoc/lib.rs | 1 - src/tools/miri/src/lib.rs | 1 - src/tools/miri/tests/pass/shims/fs.rs | 1 - src/tools/miri/tests/pass/shims/io.rs | 2 -- 13 files changed, 6 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 730d41ab962f..ba5873d79a29 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -5,7 +5,6 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(is_terminal)] #![feature(lazy_cell)] #![feature(decl_macro)] #![recursion_limit = "256"] diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 9866a9bffe0e..cee62d237544 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -6,7 +6,6 @@ #![feature(array_windows)] #![feature(drain_filter)] #![feature(if_let_guard)] -#![feature(is_terminal)] #![feature(adt_const_params)] #![feature(let_chains)] #![feature(never_type)] diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs index 21f6a404a015..3cbb2c21e289 100644 --- a/compiler/rustc_log/src/lib.rs +++ b/compiler/rustc_log/src/lib.rs @@ -40,7 +40,6 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -#![feature(is_terminal)] use std::env::{self, VarError}; use std::fmt::{self, Display}; diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 4b31c552eedd..020c723925ae 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -268,7 +268,7 @@ pub(crate) use self::stdio::attempt_print_to_stderr; #[unstable(feature = "internal_output_capture", issue = "none")] #[doc(no_inline, hidden)] pub use self::stdio::set_output_capture; -#[unstable(feature = "is_terminal", issue = "98070")] +#[stable(feature = "is_terminal", since = "CURRENT_RUSTC_VERSION")] pub use self::stdio::IsTerminal; #[unstable(feature = "print_internals", issue = "none")] pub use self::stdio::{_eprint, _print}; diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 1a3200a5c62b..b2c57b8ddc78 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -1047,7 +1047,7 @@ pub(crate) fn attempt_print_to_stderr(args: fmt::Arguments<'_>) { } /// Trait to determine if a descriptor/handle refers to a terminal/tty. -#[unstable(feature = "is_terminal", issue = "98070")] +#[stable(feature = "is_terminal", since = "CURRENT_RUSTC_VERSION")] pub trait IsTerminal: crate::sealed::Sealed { /// Returns `true` if the descriptor/handle refers to a terminal/tty. /// @@ -1063,6 +1063,7 @@ pub trait IsTerminal: crate::sealed::Sealed { /// Note that this [may change in the future][changes]. /// /// [changes]: io#platform-specific-behavior + #[stable(feature = "is_terminal", since = "CURRENT_RUSTC_VERSION")] fn is_terminal(&self) -> bool; } @@ -1071,7 +1072,7 @@ macro_rules! impl_is_terminal { #[unstable(feature = "sealed", issue = "none")] impl crate::sealed::Sealed for $t {} - #[unstable(feature = "is_terminal", issue = "98070")] + #[stable(feature = "is_terminal", since = "CURRENT_RUSTC_VERSION")] impl IsTerminal for $t { #[inline] fn is_terminal(&self) -> bool { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 736b3c0497c4..71f3576c93d4 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -254,7 +254,6 @@ #![feature(exhaustive_patterns)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] -#![feature(is_terminal)] #![feature(lang_items)] #![feature(let_chains)] #![feature(linkage)] diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index a40d39c5e44f..6a6e6f33158f 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -201,7 +201,7 @@ macro_rules! impl_is_terminal { #[unstable(feature = "sealed", issue = "none")] impl crate::sealed::Sealed for $t {} - #[unstable(feature = "is_terminal", issue = "98070")] + #[stable(feature = "is_terminal", since = "CURRENT_RUSTC_VERSION")] impl crate::io::IsTerminal for $t { #[inline] fn is_terminal(&self) -> bool { diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 1dfecc57338a..f6622874625f 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -389,7 +389,7 @@ macro_rules! impl_is_terminal { #[unstable(feature = "sealed", issue = "none")] impl crate::sealed::Sealed for $t {} - #[unstable(feature = "is_terminal", issue = "98070")] + #[stable(feature = "is_terminal", since = "CURRENT_RUSTC_VERSION")] impl crate::io::IsTerminal for $t { #[inline] fn is_terminal(&self) -> bool { diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 88d8e5fe97ad..9fb31ed7663d 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -17,7 +17,6 @@ #![unstable(feature = "test", issue = "50297")] #![doc(test(attr(deny(warnings))))] #![feature(internal_output_capture)] -#![feature(is_terminal)] #![feature(staged_api)] #![feature(process_exitcode_internals)] #![feature(panic_can_unwind)] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 79f53ee57cc9..8ab212099e34 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -7,7 +7,6 @@ #![feature(assert_matches)] #![feature(box_patterns)] #![feature(drain_filter)] -#![feature(is_terminal)] #![feature(let_chains)] #![feature(test)] #![feature(never_type)] diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index fb4e59acd001..dcdec0627b70 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -7,7 +7,6 @@ #![feature(yeet_expr)] #![feature(nonzero_ops)] #![feature(local_key_cell_methods)] -#![feature(is_terminal)] #![feature(round_ties_even)] // Configure clippy and other lints #![allow( diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 7a9974f39389..e379288de01c 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -3,7 +3,6 @@ #![feature(io_error_more)] #![feature(io_error_uncategorized)] -#![feature(is_terminal)] use std::collections::HashMap; use std::ffi::{c_char, OsString}; diff --git a/src/tools/miri/tests/pass/shims/io.rs b/src/tools/miri/tests/pass/shims/io.rs index 4d43549a930b..295723957a42 100644 --- a/src/tools/miri/tests/pass/shims/io.rs +++ b/src/tools/miri/tests/pass/shims/io.rs @@ -1,5 +1,3 @@ -#![feature(is_terminal)] - use std::io::IsTerminal; fn main() { From d6fe73db3fea55511db95969d13de5e1f5be327e Mon Sep 17 00:00:00 2001 From: The 8472 Date: Mon, 10 Apr 2023 13:13:09 +0200 Subject: [PATCH 153/272] remove unusued feature --- clippy_lints/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index bac82eca8174..b0ec14855e71 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1,7 +1,6 @@ #![feature(array_windows)] #![feature(binary_heap_into_iter_sorted)] #![feature(box_patterns)] -#![feature(drain_filter)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(let_chains)] From 9dd27b31bac5a001ab3fe638c8c95f14023bd61c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 23 Mar 2023 19:34:18 +0400 Subject: [PATCH 154/272] rustc_metadata: Cleanup `fn encode_info_for_item` --- compiler/rustc_metadata/src/rmeta/encoder.rs | 95 +++++++------------- 1 file changed, 33 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 4291b9aa1426..1b2c4b53de5b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1523,23 +1523,32 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }) } - fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) { + fn encode_info_for_item(&mut self, item: &'tcx hir::Item<'tcx>) { let tcx = self.tcx; - + let def_id = item.owner_id.to_def_id(); debug!("EncodeContext::encode_info_for_item({:?})", def_id); + let record_associated_item_def_ids = |this: &mut Self, def_ids: &[DefId]| { + record_array!(this.tables.children[def_id] <- def_ids.iter().map(|&def_id| { + assert!(def_id.is_local()); + def_id.index + })) + }; + match item.kind { hir::ItemKind::Fn(ref sig, .., body) => { self.tables.asyncness.set_some(def_id.index, sig.header.asyncness); record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); self.tables.constness.set_some(def_id.index, sig.header.constness); + record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); + self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id)); } hir::ItemKind::Macro(ref macro_def, _) => { self.tables.is_macro_rules.set(def_id.index, macro_def.macro_rules); record!(self.tables.macro_definition[def_id] <- &*macro_def.body); } hir::ItemKind::Mod(ref m) => { - return self.encode_info_for_mod(item.owner_id.def_id, m); + self.encode_info_for_mod(item.owner_id.def_id, m); } hir::ItemKind::OpaqueTy(ref opaque) => { self.encode_explicit_item_bounds(def_id); @@ -1550,9 +1559,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => { self.tables.impl_defaultness.set_some(def_id.index, *defaultness); self.tables.constness.set_some(def_id.index, *constness); + self.tables.impl_polarity.set_some(def_id.index, self.tcx.impl_polarity(def_id)); + + if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) { + record!(self.tables.impl_trait_ref[def_id] <- trait_ref); - let trait_ref = self.tcx.impl_trait_ref(def_id); - if let Some(trait_ref) = trait_ref { let trait_ref = trait_ref.skip_binder(); let trait_def = self.tcx.trait_def(trait_ref.def_id); if let Ok(mut an) = trait_def.ancestors(self.tcx, def_id) { @@ -1570,21 +1581,27 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - let polarity = self.tcx.impl_polarity(def_id); - self.tables.impl_polarity.set_some(def_id.index, polarity); + let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id); + record_associated_item_def_ids(self, associated_item_def_ids); + for &trait_item_def_id in associated_item_def_ids { + self.encode_info_for_impl_item(trait_item_def_id); + } } hir::ItemKind::Trait(..) => { - let trait_def = self.tcx.trait_def(def_id); - record!(self.tables.trait_def[def_id] <- trait_def); + record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); + + let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id); + record_associated_item_def_ids(self, associated_item_def_ids); + for &item_def_id in associated_item_def_ids { + self.encode_info_for_trait_item(item_def_id); + } } hir::ItemKind::TraitAlias(..) => { - let trait_def = self.tcx.trait_def(def_id); - record!(self.tables.trait_def[def_id] <- trait_def); + record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); } - hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => { - bug!("cannot encode info for item {:?}", item) - } - hir::ItemKind::Static(..) + hir::ItemKind::ExternCrate(_) + | hir::ItemKind::Use(..) + | hir::ItemKind::Static(..) | hir::ItemKind::Const(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) @@ -1592,49 +1609,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::GlobalAsm(..) | hir::ItemKind::TyAlias(..) => {} - }; - // FIXME(eddyb) there should be a nicer way to do this. - match item.kind { - hir::ItemKind::Impl { .. } | hir::ItemKind::Trait(..) => { - let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id); - record_array!(self.tables.children[def_id] <- - associated_item_def_ids.iter().map(|&def_id| { - assert!(def_id.is_local()); - def_id.index - }) - ); - } - _ => {} - } - if let hir::ItemKind::Fn(..) = item.kind { - record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); - self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id)); - } - if let hir::ItemKind::Impl { .. } = item.kind { - if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) { - record!(self.tables.impl_trait_ref[def_id] <- trait_ref); - } - } - // In some cases, along with the item itself, we also - // encode some sub-items. Usually we want some info from the item - // so it's easier to do that here then to wait until we would encounter - // normally in the visitor walk. - match item.kind { - hir::ItemKind::Impl { .. } => { - for &trait_item_def_id in - self.tcx.associated_item_def_ids(item.owner_id.to_def_id()).iter() - { - self.encode_info_for_impl_item(trait_item_def_id); - } - } - hir::ItemKind::Trait(..) => { - for &item_def_id in - self.tcx.associated_item_def_ids(item.owner_id.to_def_id()).iter() - { - self.encode_info_for_trait_item(item_def_id); - } - } - _ => {} } } @@ -2020,10 +1994,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> { } fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { intravisit::walk_item(self, item); - match item.kind { - hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => {} // ignore these - _ => self.encode_info_for_item(item.owner_id.to_def_id(), item), - } + self.encode_info_for_item(item); } fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem<'tcx>) { intravisit::walk_foreign_item(self, ni); From f5a9f6fb7eccc1545ff871c6f15b8a2d49df2efc Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 29 Mar 2023 22:15:38 +0400 Subject: [PATCH 155/272] rustc_metadata: Filter encoded data more aggressively using `DefKind` --- .../rustc_hir_analysis/src/astconv/mod.rs | 2 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 24 ++- compiler/rustc_metadata/src/rmeta/encoder.rs | 139 ++++++++++++++++-- src/librustdoc/clean/types.rs | 2 +- .../associated-types-in-ambiguous-context.rs | 2 + ...sociated-types-in-ambiguous-context.stderr | 21 ++- 6 files changed, 165 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index acca3fa26418..37c894348cd4 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2580,7 +2580,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.all_impls(trait_def_id) .filter(|impl_def_id| { // Consider only accessible traits - tcx.visibility(*impl_def_id).is_accessible_from(self.item_def_id(), tcx) + tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx) && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative }) .filter_map(|impl_def_id| tcx.impl_trait_ref(impl_def_id)) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index f9d32ffceef6..77308212c32d 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -749,6 +749,10 @@ impl CrateRoot { } impl<'a, 'tcx> CrateMetadataRef<'a> { + fn missing(self, descr: &str, id: DefIndex) -> ! { + bug!("missing `{descr}` for {:?}", self.local_def_id(id)) + } + fn raw_proc_macro(self, id: DefIndex) -> &'a ProcMacro { // DefIndex's in root.proc_macro_data have a one-to-one correspondence // with items in 'raw_proc_macros'. @@ -782,8 +786,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn opt_item_ident(self, item_index: DefIndex, sess: &Session) -> Option { let name = self.opt_item_name(item_index)?; - let span = - self.root.tables.def_ident_span.get(self, item_index).unwrap().decode((self, sess)); + let span = self + .root + .tables + .def_ident_span + .get(self, item_index) + .unwrap_or_else(|| self.missing("def_ident_span", item_index)) + .decode((self, sess)); Some(Ident::new(name, span)) } @@ -812,7 +821,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .def_span .get(self, index) - .unwrap_or_else(|| panic!("Missing span for {index:?}")) + .unwrap_or_else(|| self.missing("def_span", index)) .decode((self, sess)) } @@ -924,7 +933,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .visibility .get(self, id) - .unwrap() + .unwrap_or_else(|| self.missing("visibility", id)) .decode(self) .map_id(|index| self.local_def_id(index)) } @@ -934,7 +943,12 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_expn_that_defined(self, id: DefIndex, sess: &Session) -> ExpnId { - self.root.tables.expn_that_defined.get(self, id).unwrap().decode((self, sess)) + self.root + .tables + .expn_that_defined + .get(self, id) + .unwrap_or_else(|| self.missing("expn_that_defined", id)) + .decode((self, sess)) } fn get_debugger_visualizers(self) -> Vec { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 1b2c4b53de5b..77ec03165fbf 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -811,6 +811,117 @@ fn analyze_attr(attr: &Attribute, state: &mut AnalyzeAttrState) -> bool { should_encode } +fn should_encode_span(def_kind: DefKind) -> bool { + match def_kind { + DefKind::Mod + | DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Trait + | DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::TraitAlias + | DefKind::AssocTy + | DefKind::TyParam + | DefKind::Fn + | DefKind::Const + | DefKind::Static(_) + | DefKind::Ctor(..) + | DefKind::AssocFn + | DefKind::AssocConst + | DefKind::Macro(_) + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::OpaqueTy + | DefKind::Field + | DefKind::Impl { .. } + | DefKind::Closure + | DefKind::Generator => true, + DefKind::ConstParam + | DefKind::ExternCrate + | DefKind::Use + | DefKind::ForeignMod + | DefKind::ImplTraitPlaceholder + | DefKind::LifetimeParam + | DefKind::GlobalAsm => false, + } +} + +fn should_encode_attrs(def_kind: DefKind) -> bool { + match def_kind { + DefKind::Mod + | DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Trait + | DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::TraitAlias + | DefKind::AssocTy + | DefKind::Fn + | DefKind::Const + | DefKind::Static(_) + | DefKind::AssocFn + | DefKind::AssocConst + | DefKind::Macro(_) + | DefKind::Field + | DefKind::Impl { .. } => true, + DefKind::TyParam + | DefKind::ConstParam + | DefKind::Ctor(..) + | DefKind::ExternCrate + | DefKind::Use + | DefKind::ForeignMod + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::Closure + | DefKind::Generator => false, + } +} + +fn should_encode_expn_that_defined(def_kind: DefKind) -> bool { + match def_kind { + DefKind::Mod + | DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Trait + | DefKind::Impl { .. } => true, + DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::TraitAlias + | DefKind::AssocTy + | DefKind::TyParam + | DefKind::Fn + | DefKind::Const + | DefKind::ConstParam + | DefKind::Static(_) + | DefKind::Ctor(..) + | DefKind::AssocFn + | DefKind::AssocConst + | DefKind::Macro(_) + | DefKind::ExternCrate + | DefKind::Use + | DefKind::ForeignMod + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder + | DefKind::Field + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::Closure + | DefKind::Generator => false, + } +} + fn should_encode_visibility(def_kind: DefKind) -> bool { match def_kind { DefKind::Mod @@ -830,18 +941,18 @@ fn should_encode_visibility(def_kind: DefKind) -> bool { | DefKind::AssocFn | DefKind::AssocConst | DefKind::Macro(..) - | DefKind::Use - | DefKind::ForeignMod - | DefKind::OpaqueTy - | DefKind::ImplTraitPlaceholder - | DefKind::Impl { .. } | DefKind::Field => true, - DefKind::TyParam + DefKind::Use + | DefKind::ForeignMod + | DefKind::TyParam | DefKind::ConstParam | DefKind::LifetimeParam | DefKind::AnonConst | DefKind::InlineConst + | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder | DefKind::GlobalAsm + | DefKind::Impl { .. } | DefKind::Closure | DefKind::Generator | DefKind::ExternCrate => false, @@ -1160,11 +1271,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let def_kind = tcx.opt_def_kind(local_id); let Some(def_kind) = def_kind else { continue }; self.tables.opt_def_kind.set_some(def_id.index, def_kind); - let def_span = tcx.def_span(local_id); - record!(self.tables.def_span[def_id] <- def_span); - self.encode_attrs(local_id); - record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id)); - if let Some(ident_span) = tcx.def_ident_span(def_id) { + if should_encode_span(def_kind) { + let def_span = tcx.def_span(local_id); + record!(self.tables.def_span[def_id] <- def_span); + } + if should_encode_attrs(def_kind) { + self.encode_attrs(local_id); + } + if should_encode_expn_that_defined(def_kind) { + record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id)); + } + if should_encode_span(def_kind) && let Some(ident_span) = tcx.def_ident_span(def_id) { record!(self.tables.def_ident_span[def_id] <- ident_span); } if def_kind.has_codegen_attrs() { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index a37d4f316439..bbf4503f74e8 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -687,7 +687,7 @@ impl Item { return None; } // Variants always inherit visibility - VariantItem(..) => return None, + VariantItem(..) | ImplItem(..) => return None, // Trait items inherit the trait's visibility AssocConstItem(..) | TyAssocConstItem(..) | AssocTypeItem(..) | TyAssocTypeItem(..) | TyMethodItem(..) | MethodItem(..) => { diff --git a/tests/ui/associated-types/associated-types-in-ambiguous-context.rs b/tests/ui/associated-types/associated-types-in-ambiguous-context.rs index 51b53908f98c..5d6b1b591810 100644 --- a/tests/ui/associated-types/associated-types-in-ambiguous-context.rs +++ b/tests/ui/associated-types/associated-types-in-ambiguous-context.rs @@ -1,3 +1,5 @@ +// normalize-stderr-test: "and \d+ other candidates" -> "and N other candidates" + trait Get { type Value; fn get(&self) -> ::Value; diff --git a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr index 00856b55df5e..1ff6fd4b821e 100644 --- a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr +++ b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr @@ -1,5 +1,5 @@ error[E0223]: ambiguous associated type - --> $DIR/associated-types-in-ambiguous-context.rs:6:36 + --> $DIR/associated-types-in-ambiguous-context.rs:8:36 | LL | fn get(x: T, y: U) -> Get::Value {} | ^^^^^^^^^^ @@ -10,30 +10,37 @@ LL | fn get(x: T, y: U) -> ::Value {} | ~~~~~~~~~~~~~~~~~~~~~~~ error[E0223]: ambiguous associated type - --> $DIR/associated-types-in-ambiguous-context.rs:20:17 + --> $DIR/associated-types-in-ambiguous-context.rs:22:17 | LL | trait Foo where Foo::Assoc: Bar { | ^^^^^^^^^^ help: use the fully-qualified path: `::Assoc` error[E0223]: ambiguous associated type - --> $DIR/associated-types-in-ambiguous-context.rs:25:10 + --> $DIR/associated-types-in-ambiguous-context.rs:27:10 | LL | type X = std::ops::Deref::Target; | ^^^^^^^^^^^^^^^^^^^^^^^ | -help: if there were a type named `Example` that implemented `Deref`, you could use the fully-qualified path +help: use the fully-qualified path | -LL | type X = ::Target; +LL | type X = ::Target; | ~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | type X = as Deref>::Target; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | type X = as Deref>::Target; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | type X = ::Target; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + and N other candidates error[E0223]: ambiguous associated type - --> $DIR/associated-types-in-ambiguous-context.rs:11:23 + --> $DIR/associated-types-in-ambiguous-context.rs:13:23 | LL | fn grab(&self) -> Grab::Value; | ^^^^^^^^^^^ help: use the fully-qualified path: `::Value` error[E0223]: ambiguous associated type - --> $DIR/associated-types-in-ambiguous-context.rs:14:22 + --> $DIR/associated-types-in-ambiguous-context.rs:16:22 | LL | fn get(&self) -> Get::Value; | ^^^^^^^^^^ From 271ac7b528989c571ad85a5561f10aace5a6a674 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Tue, 11 Apr 2023 00:01:53 +0900 Subject: [PATCH 156/272] Add regression test for #104916 Signed-off-by: Yuki Okushi --- tests/ui/associated-type-bounds/issue-104916.rs | 14 ++++++++++++++ .../ui/associated-type-bounds/issue-104916.stderr | 8 ++++++++ 2 files changed, 22 insertions(+) create mode 100644 tests/ui/associated-type-bounds/issue-104916.rs create mode 100644 tests/ui/associated-type-bounds/issue-104916.stderr diff --git a/tests/ui/associated-type-bounds/issue-104916.rs b/tests/ui/associated-type-bounds/issue-104916.rs new file mode 100644 index 000000000000..3361fa011ed8 --- /dev/null +++ b/tests/ui/associated-type-bounds/issue-104916.rs @@ -0,0 +1,14 @@ +#![feature(associated_type_bounds)] + +trait B { + type AssocType; +} + +fn f() +where + dyn for<'j> B:, + //~^ ERROR: associated type bounds are only allowed in where clauses and function signatures +{ +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/issue-104916.stderr b/tests/ui/associated-type-bounds/issue-104916.stderr new file mode 100644 index 000000000000..35435962ffe9 --- /dev/null +++ b/tests/ui/associated-type-bounds/issue-104916.stderr @@ -0,0 +1,8 @@ +error: associated type bounds are only allowed in where clauses and function signatures, not in bounds + --> $DIR/issue-104916.rs:9:19 + | +LL | dyn for<'j> B:, + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + From c127020b0fe6bcdc9cf26c5b814046639cbc38a4 Mon Sep 17 00:00:00 2001 From: bohan Date: Mon, 10 Apr 2023 23:00:21 +0800 Subject: [PATCH 157/272] fix(doc): do not parse inline when output is json for external crate --- src/librustdoc/clean/mod.rs | 3 ++- src/librustdoc/clean/types.rs | 2 +- tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-enum.rs | 3 +++ tests/rustdoc-ui/intra-doc/inline-external-enum.rs | 8 ++++++++ 4 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-enum.rs create mode 100644 tests/rustdoc-ui/intra-doc/inline-external-enum.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7f150f380253..b3df12a9df13 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2381,7 +2381,8 @@ fn clean_extern_crate<'tcx>( Some(l) => attr::list_contains_name(&l, sym::inline), None => false, } - }); + }) + && !cx.output_format.is_json(); let krate_owner_def_id = krate.owner_id.to_def_id(); if please_inline { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index a37d4f316439..cd97766752d2 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2019,7 +2019,7 @@ impl Variant { #[derive(Clone, Debug)] pub(crate) struct Discriminant { - // In the case of cross crate re-exports, we don't have the nessesary information + // In the case of cross crate re-exports, we don't have the necessary information // to reconstruct the expression of the discriminant, only the value. pub(super) expr: Option, pub(super) value: DefId, diff --git a/tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-enum.rs b/tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-enum.rs new file mode 100644 index 000000000000..6c48f5aa01f9 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-enum.rs @@ -0,0 +1,3 @@ +pub enum O { + L = -1, +} diff --git a/tests/rustdoc-ui/intra-doc/inline-external-enum.rs b/tests/rustdoc-ui/intra-doc/inline-external-enum.rs new file mode 100644 index 000000000000..363dd7f64c22 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/inline-external-enum.rs @@ -0,0 +1,8 @@ +// check-pass +// aux-build: inner-crate-enum.rs +// compile-flags:-Z unstable-options --output-format json + +#[doc(inline)] +pub extern crate inner_crate_enum; + +fn main() {} From d07b1cd4a8e0f88b2b93090172ec4d257210d172 Mon Sep 17 00:00:00 2001 From: IQuant Date: Mon, 10 Apr 2023 18:08:35 +0300 Subject: [PATCH 158/272] Call `into_diagnostic_arg` on Binder's contained value directly. --- compiler/rustc_middle/src/ty/sty.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 061f26384bd0..7b84c4e41d67 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -27,7 +27,7 @@ use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use rustc_target::spec::abi::{self, Abi}; use std::borrow::Cow; use std::cmp::Ordering; -use std::fmt::{self, Display}; +use std::fmt; use std::marker::PhantomData; use std::ops::{ControlFlow, Deref, Range}; use ty::util::IntTypeExt; @@ -878,6 +878,12 @@ impl<'tcx> PolyTraitRef<'tcx> { } } +impl<'tcx> IntoDiagnosticArg for TraitRef<'tcx> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + /// An existential reference to a trait, where `Self` is erased. /// For example, the trait object `Trait<'a, 'b, X, Y>` is: /// ```ignore (illustrative) @@ -918,6 +924,12 @@ impl<'tcx> ExistentialTraitRef<'tcx> { } } +impl<'tcx> IntoDiagnosticArg for ExistentialTraitRef<'tcx> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + pub type PolyExistentialTraitRef<'tcx> = Binder<'tcx, ExistentialTraitRef<'tcx>>; impl<'tcx> PolyExistentialTraitRef<'tcx> { @@ -1150,10 +1162,10 @@ impl<'tcx, T: IntoIterator> Binder<'tcx, T> { impl<'tcx, T> IntoDiagnosticArg for Binder<'tcx, T> where - Binder<'tcx, T>: Display, + T: IntoDiagnosticArg, { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - self.to_string().into_diagnostic_arg() + self.0.into_diagnostic_arg() } } @@ -1373,6 +1385,12 @@ impl<'tcx> FnSig<'tcx> { } } +impl<'tcx> IntoDiagnosticArg for FnSig<'tcx> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + pub type PolyFnSig<'tcx> = Binder<'tcx, FnSig<'tcx>>; impl<'tcx> PolyFnSig<'tcx> { From 8d2dbba63eaa61252c4c533e1490ac75f97374b9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 3 Apr 2023 23:24:47 +0000 Subject: [PATCH 159/272] Stall auto-trait assembly for int/float vars in new solver --- .../src/solve/assembly/structural_traits.rs | 10 +-- .../src/solve/trait_goals.rs | 78 ++++++++++++++----- tests/ui/traits/new-solver/int-var-is-send.rs | 8 ++ .../stall-num-var-auto-trait.fallback.stderr | 17 ++++ .../new-solver/stall-num-var-auto-trait.rs | 25 ++++++ 5 files changed, 114 insertions(+), 24 deletions(-) create mode 100644 tests/ui/traits/new-solver/int-var-is-send.rs create mode 100644 tests/ui/traits/new-solver/stall-num-var-auto-trait.fallback.stderr create mode 100644 tests/ui/traits/new-solver/stall-num-var-auto-trait.rs diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index cbec39d82856..1a566e87dc8e 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -24,21 +24,19 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( | ty::FnDef(..) | ty::FnPtr(_) | ty::Error(_) - | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Never | ty::Char => Ok(vec![]), - // Treat this like `struct str([u8]);` + // Treat `str` like it's defined as `struct str([u8]);` ty::Str => Ok(vec![tcx.mk_slice(tcx.types.u8)]), ty::Dynamic(..) | ty::Param(..) | ty::Foreign(..) | ty::Alias(ty::Projection, ..) - | ty::Placeholder(..) => Err(NoSolution), - - ty::Bound(..) - | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + | ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(_) => { bug!("unexpected type `{ty}`") } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 81f89fd950c8..cb7cf9b936cf 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -147,24 +147,66 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { - // This differs from the current stable behavior and - // fixes #84857. Due to breakage found via crater, we - // currently instead lint patterns which can be used to - // exploit this unsoundness on stable, see #93367 for - // more details. - // - // Using `TreatProjections::NextSolverLookup` is fine here because - // `instantiate_constituent_tys_for_auto_trait` returns nothing for - // projection types anyways. So it doesn't really matter what we do - // here, and this is faster. - if let Some(def_id) = ecx.tcx().find_map_relevant_impl( - goal.predicate.def_id(), - goal.predicate.self_ty(), - TreatProjections::NextSolverLookup, - Some, - ) { - debug!(?def_id, ?goal, "disqualified auto-trait implementation"); - return Err(NoSolution); + let self_ty = goal.predicate.self_ty(); + match *self_ty.kind() { + // Stall int and float vars until they are resolved to a concrete + // numerical type. That's because the check for impls below treats + // int vars as matching any impl. Even if we filtered such impls, + // we probably don't want to treat an `impl !AutoTrait for i32` as + // disqualifying the built-in auto impl for `i64: AutoTrait` either. + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => { + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + } + + // These types cannot be structurally decomposed into constitutent + // types, and therefore have no builtin impl. + ty::Dynamic(..) + | ty::Param(..) + | ty::Foreign(..) + | ty::Alias(ty::Projection, ..) + | ty::Placeholder(..) => return Err(NoSolution), + + ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"), + + // For rigid types, we only register a builtin auto implementation + // if there is no implementation that could ever apply to the self + // type. + // + // This differs from the current stable behavior and fixes #84857. + // Due to breakage found via crater, we currently instead lint + // patterns which can be used to exploit this unsoundness on stable, + // see #93367 for more details. + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Closure(_, _) + | ty::Generator(_, _, _) + | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(_, _) + | ty::Never + | ty::Tuple(_) + | ty::Error(_) + | ty::Adt(_, _) + | ty::Alias(ty::Opaque, _) => { + if let Some(def_id) = ecx.tcx().find_map_relevant_impl( + goal.predicate.def_id(), + goal.predicate.self_ty(), + TreatProjections::NextSolverLookup, + Some, + ) { + debug!(?def_id, ?goal, "disqualified auto-trait implementation"); + return Err(NoSolution); + } + } } ecx.probe_and_evaluate_goal_for_constituent_tys( diff --git a/tests/ui/traits/new-solver/int-var-is-send.rs b/tests/ui/traits/new-solver/int-var-is-send.rs new file mode 100644 index 000000000000..083aa90e1f64 --- /dev/null +++ b/tests/ui/traits/new-solver/int-var-is-send.rs @@ -0,0 +1,8 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +fn needs_send(_: impl Send) {} + +fn main() { + needs_send(1); +} diff --git a/tests/ui/traits/new-solver/stall-num-var-auto-trait.fallback.stderr b/tests/ui/traits/new-solver/stall-num-var-auto-trait.fallback.stderr new file mode 100644 index 000000000000..a3ab7836c193 --- /dev/null +++ b/tests/ui/traits/new-solver/stall-num-var-auto-trait.fallback.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `i32: Foo` is not satisfied + --> $DIR/stall-num-var-auto-trait.rs:18:15 + | +LL | needs_foo(x); + | --------- ^ the trait `Foo` is not implemented for `i32` + | | + | required by a bound introduced by this call + | +note: required by a bound in `needs_foo` + --> $DIR/stall-num-var-auto-trait.rs:14:22 + | +LL | fn needs_foo(x: impl Foo) {} + | ^^^ required by this bound in `needs_foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/new-solver/stall-num-var-auto-trait.rs b/tests/ui/traits/new-solver/stall-num-var-auto-trait.rs new file mode 100644 index 000000000000..0539c3a4292f --- /dev/null +++ b/tests/ui/traits/new-solver/stall-num-var-auto-trait.rs @@ -0,0 +1,25 @@ +// compile-flags: -Ztrait-solver=next +// revisions: fallback constrain +//[constrain] check-pass + +// Tests that we stall the `{integer}: Foo` obligation until after we +// constrain the int type (or fallback occurs). + +#![feature(negative_impls, auto_traits)] + +auto trait Foo {} + +impl !Foo for i32 {} + +fn needs_foo(x: impl Foo) {} + +fn main() { + let mut x = 0; + needs_foo(x); + //[fallback]~^ ERROR the trait bound `i32: Foo` is not satisfied + + #[cfg(constrain)] + { + x = 1u64; + } +} From d92f74e43b76a7ec37d2ef7dfe6d930331ff5157 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 9 Apr 2023 00:09:53 +0000 Subject: [PATCH 160/272] Support safe transmute in new solver --- compiler/rustc_middle/src/ty/visit.rs | 3 ++ .../src/solve/assembly/mod.rs | 7 +++++ .../src/solve/eval_ctxt.rs | 21 ++++++++++++++ .../src/solve/project_goals.rs | 7 +++++ .../src/solve/trait_goals.rs | 29 +++++++++++++++++++ 5 files changed, 67 insertions(+) diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 6814cadb9a8e..08a62c900f97 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -83,6 +83,9 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable> { | TypeFlags::HAS_CT_PLACEHOLDER, ) } + fn has_non_region_placeholders(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER) + } fn needs_subst(&self) -> bool { self.has_type_flags(TypeFlags::NEEDS_SUBST) } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 12ee80b6722b..a33e8ef4b4a3 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -225,6 +225,11 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable> + Copy + Eq { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + + fn consider_builtin_transmute_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; } impl<'tcx> EvalCtxt<'_, 'tcx> { @@ -373,6 +378,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { G::consider_builtin_discriminant_kind_candidate(self, goal) } else if lang_items.destruct_trait() == Some(trait_def_id) { G::consider_builtin_destruct_candidate(self, goal) + } else if lang_items.transmute_trait() == Some(trait_def_id) { + G::consider_builtin_transmute_candidate(self, goal) } else { Err(NoSolution) }; diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 28aca76cceb6..c29b5b04e000 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -639,4 +639,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { crate::traits::wf::unnormalized_obligations(self.infcx, param_env, arg) .map(|obligations| obligations.into_iter().map(|obligation| obligation.into())) } + + pub(super) fn is_transmutable( + &self, + src_and_dst: rustc_transmute::Types<'tcx>, + scope: Ty<'tcx>, + assume: rustc_transmute::Assume, + ) -> Result { + // FIXME(transmutability): This really should be returning nested goals for `Answer::If*` + match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable( + ObligationCause::dummy(), + ty::Binder::dummy(src_and_dst), + scope, + assume, + ) { + rustc_transmute::Answer::Yes => Ok(Certainty::Yes), + rustc_transmute::Answer::No(_) + | rustc_transmute::Answer::IfTransmutable { .. } + | rustc_transmute::Answer::IfAll(_) + | rustc_transmute::Answer::IfAny(_) => Err(NoSolution), + } + } } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 2a47da81ec76..14cb43b89c3a 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -524,6 +524,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ) -> QueryResult<'tcx> { bug!("`Destruct` does not have an associated type: {:?}", goal); } + + fn consider_builtin_transmute_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal) + } } /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code. diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 81f89fd950c8..c7375c9ffa64 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -556,6 +556,35 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { Err(NoSolution) } } + + fn consider_builtin_transmute_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + // `rustc_transmute` does not have support for type or const params + if goal.has_non_region_placeholders() { + return Err(NoSolution); + } + + // Erase regions because we compute layouts in `rustc_transmute`, + // which will ICE for region vars. + let substs = ecx.tcx().erase_regions(goal.predicate.trait_ref.substs); + + let Some(assume) = rustc_transmute::Assume::from_const( + ecx.tcx(), + goal.param_env, + substs.const_at(3), + ) else { + return Err(NoSolution); + }; + + let certainty = ecx.is_transmutable( + rustc_transmute::Types { dst: substs.type_at(0), src: substs.type_at(1) }, + substs.type_at(2), + assume, + )?; + ecx.evaluate_added_goals_and_make_canonical_response(certainty) + } } impl<'tcx> EvalCtxt<'_, 'tcx> { From 4adee91eac5f9cbe32078303f391cf30671ec61a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 9 Apr 2023 21:22:18 +0000 Subject: [PATCH 161/272] tests --- .../{bool.stderr => bool.current.stderr} | 4 +- .../primitives/bool.next.stderr | 19 + tests/ui/transmutability/primitives/bool.rs | 4 +- ...{numbers.stderr => numbers.current.stderr} | 228 ++--- .../primitives/numbers.next.stderr | 915 ++++++++++++++++++ .../ui/transmutability/primitives/numbers.rs | 3 + .../{unit.stderr => unit.current.stderr} | 4 +- .../primitives/unit.next.stderr | 25 + tests/ui/transmutability/primitives/unit.rs | 3 + ...ences.stderr => references.current.stderr} | 4 +- .../ui/transmutability/references.next.stderr | 26 + tests/ui/transmutability/references.rs | 3 + 12 files changed, 1117 insertions(+), 121 deletions(-) rename tests/ui/transmutability/primitives/{bool.stderr => bool.current.stderr} (94%) create mode 100644 tests/ui/transmutability/primitives/bool.next.stderr rename tests/ui/transmutability/primitives/{numbers.stderr => numbers.current.stderr} (94%) create mode 100644 tests/ui/transmutability/primitives/numbers.next.stderr rename tests/ui/transmutability/primitives/{unit.stderr => unit.current.stderr} (95%) create mode 100644 tests/ui/transmutability/primitives/unit.next.stderr rename tests/ui/transmutability/{references.stderr => references.current.stderr} (95%) create mode 100644 tests/ui/transmutability/references.next.stderr diff --git a/tests/ui/transmutability/primitives/bool.stderr b/tests/ui/transmutability/primitives/bool.current.stderr similarity index 94% rename from tests/ui/transmutability/primitives/bool.stderr rename to tests/ui/transmutability/primitives/bool.current.stderr index 22decf15e546..999302224eeb 100644 --- a/tests/ui/transmutability/primitives/bool.stderr +++ b/tests/ui/transmutability/primitives/bool.current.stderr @@ -1,12 +1,12 @@ error[E0277]: `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`. - --> $DIR/bool.rs:22:35 + --> $DIR/bool.rs:24:35 | LL | assert::is_transmutable::(); | ^^^^ `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `bool` note: required by a bound in `is_transmutable` - --> $DIR/bool.rs:12:14 + --> $DIR/bool.rs:14:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function diff --git a/tests/ui/transmutability/primitives/bool.next.stderr b/tests/ui/transmutability/primitives/bool.next.stderr new file mode 100644 index 000000000000..999302224eeb --- /dev/null +++ b/tests/ui/transmutability/primitives/bool.next.stderr @@ -0,0 +1,19 @@ +error[E0277]: `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`. + --> $DIR/bool.rs:24:35 + | +LL | assert::is_transmutable::(); + | ^^^^ `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `bool` +note: required by a bound in `is_transmutable` + --> $DIR/bool.rs:14:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/primitives/bool.rs b/tests/ui/transmutability/primitives/bool.rs index eebb74fff471..de77cfc78aa8 100644 --- a/tests/ui/transmutability/primitives/bool.rs +++ b/tests/ui/transmutability/primitives/bool.rs @@ -1,8 +1,10 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + #![crate_type = "lib"] #![feature(transmutability)] #![allow(dead_code)] #![allow(incomplete_features)] - mod assert { use std::mem::{Assume, BikeshedIntrinsicFrom}; pub struct Context; diff --git a/tests/ui/transmutability/primitives/numbers.stderr b/tests/ui/transmutability/primitives/numbers.current.stderr similarity index 94% rename from tests/ui/transmutability/primitives/numbers.stderr rename to tests/ui/transmutability/primitives/numbers.current.stderr index c04a0e82aa28..bbf1f1669995 100644 --- a/tests/ui/transmutability/primitives/numbers.stderr +++ b/tests/ui/transmutability/primitives/numbers.current.stderr @@ -1,12 +1,12 @@ error[E0277]: `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:62:40 + --> $DIR/numbers.rs:65:40 | LL | assert::is_transmutable::< i8, i16>(); | ^^^ `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i16` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -15,14 +15,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:63:40 + --> $DIR/numbers.rs:66:40 | LL | assert::is_transmutable::< i8, u16>(); | ^^^ `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u16` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -31,14 +31,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:64:40 + --> $DIR/numbers.rs:67:40 | LL | assert::is_transmutable::< i8, i32>(); | ^^^ `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -47,14 +47,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:65:40 + --> $DIR/numbers.rs:68:40 | LL | assert::is_transmutable::< i8, f32>(); | ^^^ `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -63,14 +63,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:66:40 + --> $DIR/numbers.rs:69:40 | LL | assert::is_transmutable::< i8, u32>(); | ^^^ `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -79,14 +79,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:67:40 + --> $DIR/numbers.rs:70:40 | LL | assert::is_transmutable::< i8, u64>(); | ^^^ `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -95,14 +95,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:68:40 + --> $DIR/numbers.rs:71:40 | LL | assert::is_transmutable::< i8, i64>(); | ^^^ `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -111,14 +111,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:69:40 + --> $DIR/numbers.rs:72:40 | LL | assert::is_transmutable::< i8, f64>(); | ^^^ `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -127,14 +127,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:70:39 + --> $DIR/numbers.rs:73:39 | LL | assert::is_transmutable::< i8, u128>(); | ^^^^ `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -143,14 +143,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:71:39 + --> $DIR/numbers.rs:74:39 | LL | assert::is_transmutable::< i8, i128>(); | ^^^^ `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -159,14 +159,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:73:40 + --> $DIR/numbers.rs:76:40 | LL | assert::is_transmutable::< u8, i16>(); | ^^^ `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i16` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -175,14 +175,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:74:40 + --> $DIR/numbers.rs:77:40 | LL | assert::is_transmutable::< u8, u16>(); | ^^^ `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u16` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -191,14 +191,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:75:40 + --> $DIR/numbers.rs:78:40 | LL | assert::is_transmutable::< u8, i32>(); | ^^^ `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -207,14 +207,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:76:40 + --> $DIR/numbers.rs:79:40 | LL | assert::is_transmutable::< u8, f32>(); | ^^^ `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -223,14 +223,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:77:40 + --> $DIR/numbers.rs:80:40 | LL | assert::is_transmutable::< u8, u32>(); | ^^^ `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -239,14 +239,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:78:40 + --> $DIR/numbers.rs:81:40 | LL | assert::is_transmutable::< u8, u64>(); | ^^^ `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -255,14 +255,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:79:40 + --> $DIR/numbers.rs:82:40 | LL | assert::is_transmutable::< u8, i64>(); | ^^^ `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -271,14 +271,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:80:40 + --> $DIR/numbers.rs:83:40 | LL | assert::is_transmutable::< u8, f64>(); | ^^^ `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -287,14 +287,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:81:39 + --> $DIR/numbers.rs:84:39 | LL | assert::is_transmutable::< u8, u128>(); | ^^^^ `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -303,14 +303,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:82:39 + --> $DIR/numbers.rs:85:39 | LL | assert::is_transmutable::< u8, i128>(); | ^^^^ `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -319,14 +319,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:84:40 + --> $DIR/numbers.rs:87:40 | LL | assert::is_transmutable::< i16, i32>(); | ^^^ `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -335,14 +335,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:85:40 + --> $DIR/numbers.rs:88:40 | LL | assert::is_transmutable::< i16, f32>(); | ^^^ `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -351,14 +351,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:86:40 + --> $DIR/numbers.rs:89:40 | LL | assert::is_transmutable::< i16, u32>(); | ^^^ `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -367,14 +367,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:87:40 + --> $DIR/numbers.rs:90:40 | LL | assert::is_transmutable::< i16, u64>(); | ^^^ `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -383,14 +383,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:88:40 + --> $DIR/numbers.rs:91:40 | LL | assert::is_transmutable::< i16, i64>(); | ^^^ `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -399,14 +399,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:89:40 + --> $DIR/numbers.rs:92:40 | LL | assert::is_transmutable::< i16, f64>(); | ^^^ `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -415,14 +415,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:90:39 + --> $DIR/numbers.rs:93:39 | LL | assert::is_transmutable::< i16, u128>(); | ^^^^ `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -431,14 +431,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:91:39 + --> $DIR/numbers.rs:94:39 | LL | assert::is_transmutable::< i16, i128>(); | ^^^^ `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -447,14 +447,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:93:40 + --> $DIR/numbers.rs:96:40 | LL | assert::is_transmutable::< u16, i32>(); | ^^^ `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -463,14 +463,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:94:40 + --> $DIR/numbers.rs:97:40 | LL | assert::is_transmutable::< u16, f32>(); | ^^^ `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -479,14 +479,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:95:40 + --> $DIR/numbers.rs:98:40 | LL | assert::is_transmutable::< u16, u32>(); | ^^^ `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -495,14 +495,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:96:40 + --> $DIR/numbers.rs:99:40 | LL | assert::is_transmutable::< u16, u64>(); | ^^^ `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -511,14 +511,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:97:40 + --> $DIR/numbers.rs:100:40 | LL | assert::is_transmutable::< u16, i64>(); | ^^^ `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -527,14 +527,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:98:40 + --> $DIR/numbers.rs:101:40 | LL | assert::is_transmutable::< u16, f64>(); | ^^^ `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -543,14 +543,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:99:39 + --> $DIR/numbers.rs:102:39 | LL | assert::is_transmutable::< u16, u128>(); | ^^^^ `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -559,14 +559,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:100:39 + --> $DIR/numbers.rs:103:39 | LL | assert::is_transmutable::< u16, i128>(); | ^^^^ `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -575,14 +575,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:102:40 + --> $DIR/numbers.rs:105:40 | LL | assert::is_transmutable::< i32, u64>(); | ^^^ `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -591,14 +591,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:103:40 + --> $DIR/numbers.rs:106:40 | LL | assert::is_transmutable::< i32, i64>(); | ^^^ `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -607,14 +607,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:104:40 + --> $DIR/numbers.rs:107:40 | LL | assert::is_transmutable::< i32, f64>(); | ^^^ `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -623,14 +623,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:105:39 + --> $DIR/numbers.rs:108:39 | LL | assert::is_transmutable::< i32, u128>(); | ^^^^ `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -639,14 +639,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:106:39 + --> $DIR/numbers.rs:109:39 | LL | assert::is_transmutable::< i32, i128>(); | ^^^^ `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -655,14 +655,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:108:40 + --> $DIR/numbers.rs:111:40 | LL | assert::is_transmutable::< f32, u64>(); | ^^^ `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -671,14 +671,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:109:40 + --> $DIR/numbers.rs:112:40 | LL | assert::is_transmutable::< f32, i64>(); | ^^^ `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -687,14 +687,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:110:40 + --> $DIR/numbers.rs:113:40 | LL | assert::is_transmutable::< f32, f64>(); | ^^^ `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -703,14 +703,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:111:39 + --> $DIR/numbers.rs:114:39 | LL | assert::is_transmutable::< f32, u128>(); | ^^^^ `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -719,14 +719,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:112:39 + --> $DIR/numbers.rs:115:39 | LL | assert::is_transmutable::< f32, i128>(); | ^^^^ `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -735,14 +735,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:114:40 + --> $DIR/numbers.rs:117:40 | LL | assert::is_transmutable::< u32, u64>(); | ^^^ `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -751,14 +751,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:115:40 + --> $DIR/numbers.rs:118:40 | LL | assert::is_transmutable::< u32, i64>(); | ^^^ `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -767,14 +767,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:116:40 + --> $DIR/numbers.rs:119:40 | LL | assert::is_transmutable::< u32, f64>(); | ^^^ `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -783,14 +783,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:117:39 + --> $DIR/numbers.rs:120:39 | LL | assert::is_transmutable::< u32, u128>(); | ^^^^ `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -799,14 +799,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:118:39 + --> $DIR/numbers.rs:121:39 | LL | assert::is_transmutable::< u32, i128>(); | ^^^^ `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -815,14 +815,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:120:39 + --> $DIR/numbers.rs:123:39 | LL | assert::is_transmutable::< u64, u128>(); | ^^^^ `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -831,14 +831,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:121:39 + --> $DIR/numbers.rs:124:39 | LL | assert::is_transmutable::< u64, i128>(); | ^^^^ `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -847,14 +847,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:123:39 + --> $DIR/numbers.rs:126:39 | LL | assert::is_transmutable::< i64, u128>(); | ^^^^ `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -863,14 +863,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:124:39 + --> $DIR/numbers.rs:127:39 | LL | assert::is_transmutable::< i64, i128>(); | ^^^^ `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -879,14 +879,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:126:39 + --> $DIR/numbers.rs:129:39 | LL | assert::is_transmutable::< f64, u128>(); | ^^^^ `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function @@ -895,14 +895,14 @@ LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` error[E0277]: `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. - --> $DIR/numbers.rs:127:39 + --> $DIR/numbers.rs:130:39 | LL | assert::is_transmutable::< f64, i128>(); | ^^^^ `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` - --> $DIR/numbers.rs:12:14 + --> $DIR/numbers.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function diff --git a/tests/ui/transmutability/primitives/numbers.next.stderr b/tests/ui/transmutability/primitives/numbers.next.stderr new file mode 100644 index 000000000000..bbf1f1669995 --- /dev/null +++ b/tests/ui/transmutability/primitives/numbers.next.stderr @@ -0,0 +1,915 @@ +error[E0277]: `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:65:40 + | +LL | assert::is_transmutable::< i8, i16>(); + | ^^^ `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i16` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:66:40 + | +LL | assert::is_transmutable::< i8, u16>(); + | ^^^ `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u16` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:67:40 + | +LL | assert::is_transmutable::< i8, i32>(); + | ^^^ `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:68:40 + | +LL | assert::is_transmutable::< i8, f32>(); + | ^^^ `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:69:40 + | +LL | assert::is_transmutable::< i8, u32>(); + | ^^^ `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:70:40 + | +LL | assert::is_transmutable::< i8, u64>(); + | ^^^ `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:71:40 + | +LL | assert::is_transmutable::< i8, i64>(); + | ^^^ `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:72:40 + | +LL | assert::is_transmutable::< i8, f64>(); + | ^^^ `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:73:39 + | +LL | assert::is_transmutable::< i8, u128>(); + | ^^^^ `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:74:39 + | +LL | assert::is_transmutable::< i8, i128>(); + | ^^^^ `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:76:40 + | +LL | assert::is_transmutable::< u8, i16>(); + | ^^^ `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i16` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:77:40 + | +LL | assert::is_transmutable::< u8, u16>(); + | ^^^ `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u16` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:78:40 + | +LL | assert::is_transmutable::< u8, i32>(); + | ^^^ `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:79:40 + | +LL | assert::is_transmutable::< u8, f32>(); + | ^^^ `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:80:40 + | +LL | assert::is_transmutable::< u8, u32>(); + | ^^^ `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:81:40 + | +LL | assert::is_transmutable::< u8, u64>(); + | ^^^ `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:82:40 + | +LL | assert::is_transmutable::< u8, i64>(); + | ^^^ `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:83:40 + | +LL | assert::is_transmutable::< u8, f64>(); + | ^^^ `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:84:39 + | +LL | assert::is_transmutable::< u8, u128>(); + | ^^^^ `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:85:39 + | +LL | assert::is_transmutable::< u8, i128>(); + | ^^^^ `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:87:40 + | +LL | assert::is_transmutable::< i16, i32>(); + | ^^^ `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:88:40 + | +LL | assert::is_transmutable::< i16, f32>(); + | ^^^ `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:89:40 + | +LL | assert::is_transmutable::< i16, u32>(); + | ^^^ `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:90:40 + | +LL | assert::is_transmutable::< i16, u64>(); + | ^^^ `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:91:40 + | +LL | assert::is_transmutable::< i16, i64>(); + | ^^^ `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:92:40 + | +LL | assert::is_transmutable::< i16, f64>(); + | ^^^ `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:93:39 + | +LL | assert::is_transmutable::< i16, u128>(); + | ^^^^ `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:94:39 + | +LL | assert::is_transmutable::< i16, i128>(); + | ^^^^ `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:96:40 + | +LL | assert::is_transmutable::< u16, i32>(); + | ^^^ `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:97:40 + | +LL | assert::is_transmutable::< u16, f32>(); + | ^^^ `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:98:40 + | +LL | assert::is_transmutable::< u16, u32>(); + | ^^^ `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:99:40 + | +LL | assert::is_transmutable::< u16, u64>(); + | ^^^ `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:100:40 + | +LL | assert::is_transmutable::< u16, i64>(); + | ^^^ `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:101:40 + | +LL | assert::is_transmutable::< u16, f64>(); + | ^^^ `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:102:39 + | +LL | assert::is_transmutable::< u16, u128>(); + | ^^^^ `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:103:39 + | +LL | assert::is_transmutable::< u16, i128>(); + | ^^^^ `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:105:40 + | +LL | assert::is_transmutable::< i32, u64>(); + | ^^^ `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:106:40 + | +LL | assert::is_transmutable::< i32, i64>(); + | ^^^ `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:107:40 + | +LL | assert::is_transmutable::< i32, f64>(); + | ^^^ `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:108:39 + | +LL | assert::is_transmutable::< i32, u128>(); + | ^^^^ `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:109:39 + | +LL | assert::is_transmutable::< i32, i128>(); + | ^^^^ `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:111:40 + | +LL | assert::is_transmutable::< f32, u64>(); + | ^^^ `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:112:40 + | +LL | assert::is_transmutable::< f32, i64>(); + | ^^^ `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:113:40 + | +LL | assert::is_transmutable::< f32, f64>(); + | ^^^ `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:114:39 + | +LL | assert::is_transmutable::< f32, u128>(); + | ^^^^ `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:115:39 + | +LL | assert::is_transmutable::< f32, i128>(); + | ^^^^ `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:117:40 + | +LL | assert::is_transmutable::< u32, u64>(); + | ^^^ `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:118:40 + | +LL | assert::is_transmutable::< u32, i64>(); + | ^^^ `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:119:40 + | +LL | assert::is_transmutable::< u32, f64>(); + | ^^^ `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:120:39 + | +LL | assert::is_transmutable::< u32, u128>(); + | ^^^^ `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:121:39 + | +LL | assert::is_transmutable::< u32, i128>(); + | ^^^^ `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:123:39 + | +LL | assert::is_transmutable::< u64, u128>(); + | ^^^^ `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:124:39 + | +LL | assert::is_transmutable::< u64, i128>(); + | ^^^^ `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:126:39 + | +LL | assert::is_transmutable::< i64, u128>(); + | ^^^^ `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:127:39 + | +LL | assert::is_transmutable::< i64, i128>(); + | ^^^^ `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:129:39 + | +LL | assert::is_transmutable::< f64, u128>(); + | ^^^^ `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + --> $DIR/numbers.rs:130:39 + | +LL | assert::is_transmutable::< f64, i128>(); + | ^^^^ `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to 57 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/primitives/numbers.rs b/tests/ui/transmutability/primitives/numbers.rs index 0df43d2045f7..e980e91ed06a 100644 --- a/tests/ui/transmutability/primitives/numbers.rs +++ b/tests/ui/transmutability/primitives/numbers.rs @@ -1,3 +1,6 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + #![crate_type = "lib"] #![feature(transmutability)] #![allow(dead_code)] diff --git a/tests/ui/transmutability/primitives/unit.stderr b/tests/ui/transmutability/primitives/unit.current.stderr similarity index 95% rename from tests/ui/transmutability/primitives/unit.stderr rename to tests/ui/transmutability/primitives/unit.current.stderr index 988cd33b3bf7..c20355e16f5f 100644 --- a/tests/ui/transmutability/primitives/unit.stderr +++ b/tests/ui/transmutability/primitives/unit.current.stderr @@ -1,12 +1,12 @@ error[E0277]: `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`. - --> $DIR/unit.rs:28:35 + --> $DIR/unit.rs:31:35 | LL | assert::is_transmutable::<(), u8, Context>(); | ^^ `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`. | = help: the trait `BikeshedIntrinsicFrom<(), should_have_correct_size::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `u8` note: required by a bound in `is_transmutable` - --> $DIR/unit.rs:12:14 + --> $DIR/unit.rs:15:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function diff --git a/tests/ui/transmutability/primitives/unit.next.stderr b/tests/ui/transmutability/primitives/unit.next.stderr new file mode 100644 index 000000000000..c20355e16f5f --- /dev/null +++ b/tests/ui/transmutability/primitives/unit.next.stderr @@ -0,0 +1,25 @@ +error[E0277]: `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`. + --> $DIR/unit.rs:31:35 + | +LL | assert::is_transmutable::<(), u8, Context>(); + | ^^ `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`. + | + = help: the trait `BikeshedIntrinsicFrom<(), should_have_correct_size::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `u8` +note: required by a bound in `is_transmutable` + --> $DIR/unit.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | |__________^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/primitives/unit.rs b/tests/ui/transmutability/primitives/unit.rs index 1975a61de988..12eac175106e 100644 --- a/tests/ui/transmutability/primitives/unit.rs +++ b/tests/ui/transmutability/primitives/unit.rs @@ -1,3 +1,6 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + //! The unit type, `()`, should be one byte. #![crate_type = "lib"] diff --git a/tests/ui/transmutability/references.stderr b/tests/ui/transmutability/references.current.stderr similarity index 95% rename from tests/ui/transmutability/references.stderr rename to tests/ui/transmutability/references.current.stderr index eb3bd03fd316..39d42cc4fa6c 100644 --- a/tests/ui/transmutability/references.stderr +++ b/tests/ui/transmutability/references.current.stderr @@ -1,12 +1,12 @@ error[E0277]: `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`. - --> $DIR/references.rs:26:52 + --> $DIR/references.rs:29:52 | LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); | ^^^^^^^^^^^^^ `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom<&'static Unit, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `&'static Unit` note: required by a bound in `is_maybe_transmutable` - --> $DIR/references.rs:13:14 + --> $DIR/references.rs:16:14 | LL | pub fn is_maybe_transmutable() | --------------------- required by a bound in this function diff --git a/tests/ui/transmutability/references.next.stderr b/tests/ui/transmutability/references.next.stderr new file mode 100644 index 000000000000..39d42cc4fa6c --- /dev/null +++ b/tests/ui/transmutability/references.next.stderr @@ -0,0 +1,26 @@ +error[E0277]: `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`. + --> $DIR/references.rs:29:52 + | +LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); + | ^^^^^^^^^^^^^ `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`. + | + = help: the trait `BikeshedIntrinsicFrom<&'static Unit, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `&'static Unit` +note: required by a bound in `is_maybe_transmutable` + --> $DIR/references.rs:16:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom + | |__________^ required by this bound in `is_maybe_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/references.rs b/tests/ui/transmutability/references.rs index af3ff0ec1d20..8c2b25ebba1e 100644 --- a/tests/ui/transmutability/references.rs +++ b/tests/ui/transmutability/references.rs @@ -1,3 +1,6 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + //! Transmutations involving references are not yet supported. #![crate_type = "lib"] From 05a6daab84ed594e1394ec4b0e1a9776075a7e12 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 9 Apr 2023 04:29:43 +0000 Subject: [PATCH 162/272] Report overflows gracefully with new solver --- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 2 +- .../src/fn_ctxt/adjust_fulfillment_errors.rs | 2 +- compiler/rustc_infer/src/traits/engine.rs | 4 +-- compiler/rustc_infer/src/traits/mod.rs | 6 +++- .../src/traits/structural_impls.rs | 3 +- .../src/solve/fulfill.rs | 29 +++++++++++++++---- .../src/traits/chalk_fulfill.rs | 7 +++-- .../src/traits/error_reporting/mod.rs | 15 +++++++++- .../src/traits/fulfill.rs | 11 +++++-- .../issue-95230.new.stderr | 7 +++-- .../recursive-self-normalization-2.rs | 2 +- .../recursive-self-normalization-2.stderr | 6 ++-- .../recursive-self-normalization.rs | 2 +- .../recursive-self-normalization.stderr | 6 ++-- 14 files changed, 75 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index fdf178c3ea79..f736f7a96207 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -578,7 +578,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub(in super::super) fn report_ambiguity_errors(&self) { - let mut errors = self.fulfillment_cx.borrow_mut().collect_remaining_errors(); + let mut errors = self.fulfillment_cx.borrow_mut().collect_remaining_errors(self); if !errors.is_empty() { self.adjust_fulfillment_errors_for_expr_obligation(&mut errors); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index 3e0c2bf2a553..2899ba0b7e70 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -78,7 +78,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Finally, for ambiguity-related errors, we actually want to look // for a parameter that is the source of the inference type left // over in this predicate. - if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code { + if let traits::FulfillmentErrorCode::CodeAmbiguity { .. } = error.code { fallback_param_to_point_at = None; self_param_to_point_at = None; param_to_point_at = diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index f75344f20b6d..2f0a19b46de9 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -38,7 +38,7 @@ pub trait TraitEngine<'tcx>: 'tcx { fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec>; - fn collect_remaining_errors(&mut self) -> Vec>; + fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec>; fn pending_obligations(&self) -> Vec>; @@ -78,6 +78,6 @@ impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T { return errors; } - self.collect_remaining_errors() + self.collect_remaining_errors(infcx) } } diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index dd9b2e548c73..e01b6caf4306 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -128,7 +128,11 @@ pub enum FulfillmentErrorCode<'tcx> { CodeProjectionError(MismatchedProjectionTypes<'tcx>), CodeSubtypeError(ExpectedFound>, TypeError<'tcx>), // always comes from a SubtypePredicate CodeConstEquateError(ExpectedFound>, TypeError<'tcx>), - CodeAmbiguity, + CodeAmbiguity { + /// Overflow reported from the new solver `-Ztrait-solver=next`, which will + /// be reported as an regular error as opposed to a fatal error. + overflow: bool, + }, } impl<'tcx, O> Obligation<'tcx, O> { diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index 3a5273b0359e..1563d92af0ea 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -46,7 +46,8 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { super::CodeConstEquateError(ref a, ref b) => { write!(f, "CodeConstEquateError({:?}, {:?})", a, b) } - super::CodeAmbiguity => write!(f, "Ambiguity"), + super::CodeAmbiguity { overflow: false } => write!(f, "Ambiguity"), + super::CodeAmbiguity { overflow: true } => write!(f, "Overflow"), super::CodeCycle(ref cycle) => write!(f, "Cycle({:?})", cycle), } } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 76a2a5879114..32bd10f0beba 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -1,6 +1,7 @@ use std::mem; use rustc_infer::infer::InferCtxt; +use rustc_infer::traits::solve::MaybeCause; use rustc_infer::traits::Obligation; use rustc_infer::traits::{ query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, @@ -41,13 +42,31 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { self.obligations.push(obligation); } - fn collect_remaining_errors(&mut self) -> Vec> { + fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { self.obligations .drain(..) - .map(|obligation| FulfillmentError { - obligation: obligation.clone(), - code: FulfillmentErrorCode::CodeAmbiguity, - root_obligation: obligation, + .map(|obligation| { + let code = + infcx.probe(|_| match infcx.evaluate_root_goal(obligation.clone().into()) { + Ok((_, Certainty::Maybe(MaybeCause::Ambiguity), _)) => { + FulfillmentErrorCode::CodeAmbiguity { overflow: false } + } + Ok((_, Certainty::Maybe(MaybeCause::Overflow), _)) => { + FulfillmentErrorCode::CodeAmbiguity { overflow: true } + } + Ok((_, Certainty::Yes, _)) => { + bug!("did not expect successful goal when collecting ambiguity errors") + } + Err(_) => { + bug!("did not expect selection error when collecting ambiguity errors") + } + }); + + FulfillmentError { + obligation: obligation.clone(), + code, + root_obligation: obligation, + } }) .collect() } diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index b42a49eb47b9..28967e1cc55b 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -40,13 +40,16 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { self.obligations.insert(obligation); } - fn collect_remaining_errors(&mut self) -> Vec> { + fn collect_remaining_errors( + &mut self, + _infcx: &InferCtxt<'tcx>, + ) -> Vec> { // any remaining obligations are errors self.obligations .iter() .map(|obligation| FulfillmentError { obligation: obligation.clone(), - code: FulfillmentErrorCode::CodeAmbiguity, + code: FulfillmentErrorCode::CodeAmbiguity { overflow: false }, // FIXME - does Chalk have a notation of 'root obligation'? // This is just for diagnostics, so it's okay if this is wrong root_obligation: obligation.clone(), diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 6ebf056f0e83..5b49684cfceb 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -125,6 +125,8 @@ pub trait TypeErrCtxtExt<'tcx> { + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, >>::Error: std::fmt::Debug; + fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed; + fn report_fulfillment_errors(&self, errors: &[FulfillmentError<'tcx>]) -> ErrorGuaranteed; fn report_overflow_obligation( @@ -602,6 +604,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); } + fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed { + let obligation = self.resolve_vars_if_possible(obligation); + let mut err = self.build_overflow_error(&obligation.predicate, obligation.cause.span, true); + self.note_obligation_cause(&mut err, &obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); + err.emit() + } + fn report_selection_error( &self, mut obligation: PredicateObligation<'tcx>, @@ -1658,9 +1668,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { FulfillmentErrorCode::CodeProjectionError(ref e) => { self.report_projection_error(&error.obligation, e); } - FulfillmentErrorCode::CodeAmbiguity => { + FulfillmentErrorCode::CodeAmbiguity { overflow: false } => { self.maybe_report_ambiguity(&error.obligation); } + FulfillmentErrorCode::CodeAmbiguity { overflow: true } => { + self.report_overflow_no_abort(error.obligation.clone()); + } FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => { self.report_mismatched_types( &error.obligation.cause, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 07e31e87bfb4..26cadab3e9f1 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -133,8 +133,15 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); } - fn collect_remaining_errors(&mut self) -> Vec> { - self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect() + fn collect_remaining_errors( + &mut self, + _infcx: &InferCtxt<'tcx>, + ) -> Vec> { + self.predicates + .to_errors(CodeAmbiguity { overflow: false }) + .into_iter() + .map(to_fulfillment_error) + .collect() } fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { diff --git a/tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr b/tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr index bcb201bf0c37..d4bc5b67220a 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr +++ b/tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr @@ -1,9 +1,10 @@ -error[E0282]: type annotations needed +error[E0275]: overflow evaluating the requirement `for<'a> &'a mut Bar well-formed` --> $DIR/issue-95230.rs:9:13 | LL | for<'a> &'a mut Self:; - | ^^^^^^^^^^^^ cannot infer type for mutable reference `&'a mut Bar` + | ^^^^^^^^^^^^ | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_95230`) note: required by a bound in `Bar` --> $DIR/issue-95230.rs:9:13 | @@ -15,4 +16,4 @@ LL | for<'a> &'a mut Self:; error: aborting due to previous error -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/new-solver/recursive-self-normalization-2.rs b/tests/ui/traits/new-solver/recursive-self-normalization-2.rs index 7417d6018a13..8c029f5179d1 100644 --- a/tests/ui/traits/new-solver/recursive-self-normalization-2.rs +++ b/tests/ui/traits/new-solver/recursive-self-normalization-2.rs @@ -13,7 +13,7 @@ fn needs_bar() {} fn test::Assoc2> + Foo2::Assoc1>>() { needs_bar::(); - //~^ ERROR type annotations needed + //~^ ERROR overflow evaluating the requirement `::Assoc1: Bar` } fn main() {} diff --git a/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr b/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr index e3a92e85e17e..139b0a456801 100644 --- a/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr +++ b/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr @@ -1,10 +1,10 @@ -error[E0283]: type annotations needed: cannot satisfy `::Assoc1: Bar` +error[E0275]: overflow evaluating the requirement `::Assoc1: Bar` --> $DIR/recursive-self-normalization-2.rs:15:5 | LL | needs_bar::(); | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: cannot satisfy `::Assoc1: Bar` + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`) note: required by a bound in `needs_bar` --> $DIR/recursive-self-normalization-2.rs:12:17 | @@ -13,4 +13,4 @@ LL | fn needs_bar() {} error: aborting due to previous error -For more information about this error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/new-solver/recursive-self-normalization.rs b/tests/ui/traits/new-solver/recursive-self-normalization.rs index f3e3d71d813e..06d187b5fdf7 100644 --- a/tests/ui/traits/new-solver/recursive-self-normalization.rs +++ b/tests/ui/traits/new-solver/recursive-self-normalization.rs @@ -9,7 +9,7 @@ fn needs_bar() {} fn test::Assoc>>() { needs_bar::(); - //~^ ERROR type annotations needed + //~^ ERROR overflow evaluating the requirement `::Assoc: Bar` } fn main() {} diff --git a/tests/ui/traits/new-solver/recursive-self-normalization.stderr b/tests/ui/traits/new-solver/recursive-self-normalization.stderr index 773007aebaa6..8e9b9b4b4cec 100644 --- a/tests/ui/traits/new-solver/recursive-self-normalization.stderr +++ b/tests/ui/traits/new-solver/recursive-self-normalization.stderr @@ -1,10 +1,10 @@ -error[E0283]: type annotations needed: cannot satisfy `::Assoc: Bar` +error[E0275]: overflow evaluating the requirement `::Assoc: Bar` --> $DIR/recursive-self-normalization.rs:11:5 | LL | needs_bar::(); | ^^^^^^^^^^^^^^^^^^^^^ | - = note: cannot satisfy `::Assoc: Bar` + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`) note: required by a bound in `needs_bar` --> $DIR/recursive-self-normalization.rs:8:17 | @@ -13,4 +13,4 @@ LL | fn needs_bar() {} error: aborting due to previous error -For more information about this error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0275`. From 687abb0c3508ad0513b4632dd2b76912a659605f Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 10 Apr 2023 13:00:46 -0400 Subject: [PATCH 163/272] Update books --- src/doc/book | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/doc/rustc-dev-guide | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/book b/src/doc/book index 0510ca84c2ce..c06006157b14 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 0510ca84c2ce6bf93c4ccf9248756e9e4fd00b12 +Subproject commit c06006157b14b3d47b5c716fc392b77f3b2e21ce diff --git a/src/doc/reference b/src/doc/reference index 3c47807a3131..1f8dc727e94a 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 3c47807a3131b3c7cacb508f52632078d253cd0a +Subproject commit 1f8dc727e94ae4ef92adf70df979521a1ea1143e diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index ba84bf35d0f1..31961fe22521 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit ba84bf35d0f17d404003349309201654d25f61af +Subproject commit 31961fe22521a779070a44a8f30a2b00a20b6212 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index fca8af6c154c..6337ed17fb8d 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit fca8af6c154c6cde2512f1331cf2704f214a818e +Subproject commit 6337ed17fb8dcd918d78b7d97d213e923530337c From b410f3f7aeea95ba5362bb5dddbf5e66183adc40 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Mon, 10 Apr 2023 21:02:29 +0200 Subject: [PATCH 164/272] Fix typos in librustdoc --- src/librustdoc/clean/types.rs | 2 +- src/librustdoc/config.rs | 2 +- src/librustdoc/html/format.rs | 4 ++-- src/librustdoc/html/render/print_item.rs | 5 +++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index a37d4f316439..cd97766752d2 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2019,7 +2019,7 @@ impl Variant { #[derive(Clone, Debug)] pub(crate) struct Discriminant { - // In the case of cross crate re-exports, we don't have the nessesary information + // In the case of cross crate re-exports, we don't have the necessary information // to reconstruct the expression of the discriminant, only the value. pub(super) expr: Option, pub(super) value: DefId, diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index ea8c7e9a67c3..c848089dad6b 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -230,7 +230,7 @@ pub(crate) struct RenderOptions { pub(crate) extension_css: Option, /// A map of crate names to the URL to use instead of querying the crate's `html_root_url`. pub(crate) extern_html_root_urls: BTreeMap, - /// Whether to give precedence to `html_root_url` or `--exten-html-root-url`. + /// Whether to give precedence to `html_root_url` or `--extern-html-root-url`. pub(crate) extern_html_root_takes_precedence: bool, /// A map of the default settings (values are as for DOM storage API). Keys should lack the /// `rustdoc-` prefix. diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 7a2449cbe9ac..1b445b8981e1 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -349,10 +349,10 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( let mut br_with_padding = String::with_capacity(6 * indent + 28); br_with_padding.push_str("\n"); - let padding_amout = + let padding_amount = if ending == Ending::Newline { indent + 4 } else { indent + "fn where ".len() }; - for _ in 0..padding_amout { + for _ in 0..padding_amount { br_with_padding.push_str(" "); } let where_preds = where_preds.to_string().replace('\n', &br_with_padding); diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 6bce57340040..9a968e48b272 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1796,10 +1796,11 @@ fn render_struct( } match ty { None => { - let where_diplayed = g.map(|g| print_where_clause_and_check(w, g, cx)).unwrap_or(false); + let where_displayed = + g.map(|g| print_where_clause_and_check(w, g, cx)).unwrap_or(false); // If there wasn't a `where` clause, we add a whitespace. - if !where_diplayed { + if !where_displayed { w.write_str(" {"); } else { w.write_str("{"); From f470c299366c4598fe2477d3e7a846e220abb75e Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Mon, 10 Apr 2023 21:02:49 +0200 Subject: [PATCH 165/272] Fix remaining typos --- config.example.toml | 2 +- src/bootstrap/channel.rs | 2 +- src/doc/style-guide/src/expressions.md | 2 +- .../compiler-flags/dump-mono-stats-format.md | 2 +- src/etc/installer/msi/rust.wxs | 2 +- src/rustdoc-json-types/lib.rs | 2 +- .../collect-license-metadata/src/path_tree.rs | 88 +++++++++---------- src/tools/generate-copyright/src/main.rs | 14 +-- src/tools/jsondocck/src/main.rs | 2 +- src/tools/jsondoclint/src/item_kind.rs | 4 +- src/tools/jsondoclint/src/main.rs | 6 +- src/tools/publish_toolstate.py | 6 +- triagebot.toml | 4 +- 13 files changed, 68 insertions(+), 68 deletions(-) diff --git a/config.example.toml b/config.example.toml index b27a34e61c54..081b3638383d 100644 --- a/config.example.toml +++ b/config.example.toml @@ -257,7 +257,7 @@ changelog-seen = 2 #python = "python" # The path to the REUSE executable to use. Note that REUSE is not required in -# most cases, as our tooling relies on a cached (and shrinked) copy of the +# most cases, as our tooling relies on a cached (and shrunk) copy of the # REUSE output present in the git repository and in our source tarballs. # # REUSE is only needed if your changes caused the overall licensing of the diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 390047f6fdce..c3e3fa009a67 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -139,7 +139,7 @@ pub fn read_commit_info_file(root: &Path) -> Option { sha: sha.to_owned(), short_sha: short_sha.to_owned(), }, - _ => panic!("the `git-comit-info` file is malformed"), + _ => panic!("the `git-commit-info` file is malformed"), }; Some(info) } else { diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index c7d0446dded1..96f66c89c259 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -643,7 +643,7 @@ Examples: ```rust match foo { foo => bar, - a_very_long_patten | another_pattern if an_expression() => { + a_very_long_pattern | another_pattern if an_expression() => { no_room_for_this_expression() } foo => { diff --git a/src/doc/unstable-book/src/compiler-flags/dump-mono-stats-format.md b/src/doc/unstable-book/src/compiler-flags/dump-mono-stats-format.md index a497a75261fe..05ffdcf201c8 100644 --- a/src/doc/unstable-book/src/compiler-flags/dump-mono-stats-format.md +++ b/src/doc/unstable-book/src/compiler-flags/dump-mono-stats-format.md @@ -3,4 +3,4 @@ -------------------- The `-Z dump-mono-stats-format` compiler flag controls what file format to use for `-Z dump-mono-stats`. -The default is markdown; currently JSON is also supported. JSON can be useful for programatically manipulating the results (e.g. to find the item that took the longest to compile). +The default is markdown; currently JSON is also supported. JSON can be useful for programmatically manipulating the results (e.g. to find the item that took the longest to compile). diff --git a/src/etc/installer/msi/rust.wxs b/src/etc/installer/msi/rust.wxs index 9f4e4fd0611d..f29e1e4d27a2 100644 --- a/src/etc/installer/msi/rust.wxs +++ b/src/etc/installer/msi/rust.wxs @@ -119,7 +119,7 @@ NOT ALLUSERS - + NOT ALLUSERS diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 4c210291b113..3cf8ceed6203 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -550,7 +550,7 @@ pub enum Type { DynTrait(DynTrait), /// Parameterized types Generic(String), - /// Built in numberic (i*, u*, f*) types, bool, and char + /// Built in numeric (i*, u*, f*) types, bool, and char Primitive(String), /// `extern "ABI" fn` FunctionPointer(Box), diff --git a/src/tools/collect-license-metadata/src/path_tree.rs b/src/tools/collect-license-metadata/src/path_tree.rs index 7a2a440636d9..68b6cef64327 100644 --- a/src/tools/collect-license-metadata/src/path_tree.rs +++ b/src/tools/collect-license-metadata/src/path_tree.rs @@ -10,8 +10,8 @@ use std::path::{Path, PathBuf}; #[derive(serde::Serialize)] #[serde(rename_all = "kebab-case", tag = "type")] pub(crate) enum Node { - Root { childs: Vec> }, - Directory { name: PathBuf, childs: Vec>, license: Option }, + Root { children: Vec> }, + Directory { name: PathBuf, children: Vec>, license: Option }, File { name: PathBuf, license: L }, Group { files: Vec, directories: Vec, license: L }, Empty, @@ -48,14 +48,14 @@ impl Node { /// ``` fn merge_directories(&mut self) { match self { - Node::Root { childs } | Node::Directory { childs, license: None, .. } => { + Node::Root { children } | Node::Directory { children, license: None, .. } => { let mut directories = BTreeMap::new(); let mut files = Vec::new(); - for child in childs.drain(..) { + for child in children.drain(..) { match child { - Node::Directory { name, mut childs, license: None } => { - directories.entry(name).or_insert_with(Vec::new).append(&mut childs); + Node::Directory { name, mut children, license: None } => { + directories.entry(name).or_insert_with(Vec::new).append(&mut children); } file @ Node::File { .. } => { files.push(file); @@ -73,14 +73,14 @@ impl Node { } } - childs.extend(directories.into_iter().map(|(name, childs)| Node::Directory { + children.extend(directories.into_iter().map(|(name, children)| Node::Directory { name, - childs, + children, license: None, })); - childs.append(&mut files); + children.append(&mut files); - for child in &mut *childs { + for child in &mut *children { child.merge_directories(); } } @@ -105,13 +105,13 @@ impl Node { /// our inclusion of LLVM. fn collapse_in_licensed_directories(&mut self) { match self { - Node::Directory { childs, license, .. } => { - for child in &mut *childs { + Node::Directory { children, license, .. } => { + for child in &mut *children { child.collapse_in_licensed_directories(); } let mut licenses_count = BTreeMap::new(); - for child in &*childs { + for child in &*children { let Some(license) = child.license() else { continue }; *licenses_count.entry(license).or_insert(0) += 1; } @@ -122,12 +122,12 @@ impl Node { .map(|(license, _)| license); if let Some(most_popular_license) = most_popular_license { - childs.retain(|child| child.license() != Some(most_popular_license)); + children.retain(|child| child.license() != Some(most_popular_license)); *license = Some(most_popular_license); } } - Node::Root { childs } => { - for child in &mut *childs { + Node::Root { children } => { + for child in &mut *children { child.collapse_in_licensed_directories(); } } @@ -138,29 +138,29 @@ impl Node { } /// Reduce the depth of the tree by merging subdirectories with the same license as their - /// parent directory into their parent, and adjusting the paths of the childs accordingly. + /// parent directory into their parent, and adjusting the paths of the children accordingly. fn merge_directory_licenses(&mut self) { match self { - Node::Root { childs } => { - for child in &mut *childs { + Node::Root { children } => { + for child in &mut *children { child.merge_directory_licenses(); } } - Node::Directory { childs, license, .. } => { + Node::Directory { children, license, .. } => { let mut to_add = Vec::new(); - for child in &mut *childs { + for child in &mut *children { child.merge_directory_licenses(); let Node::Directory { name: child_name, - childs: child_childs, + children: child_children, license: child_license, } = child else { continue }; if child_license != license { continue; } - for mut child_child in child_childs.drain(..) { + for mut child_child in child_children.drain(..) { match &mut child_child { Node::Root { .. } => { panic!("can't have a root inside another element"); @@ -181,7 +181,7 @@ impl Node { *child = Node::Empty; } - childs.append(&mut to_add); + children.append(&mut to_add); } Node::Empty => {} Node::File { .. } => {} @@ -203,14 +203,14 @@ impl Node { directories: Vec, } match self { - Node::Root { childs } | Node::Directory { childs, .. } => { + Node::Root { children } | Node::Directory { children, .. } => { let mut grouped: BTreeMap = BTreeMap::new(); - for child in &mut *childs { + for child in &mut *children { child.merge_groups(); match child { - Node::Directory { name, childs, license: Some(license) } => { - if childs.is_empty() { + Node::Directory { name, children, license: Some(license) } => { + if children.is_empty() { grouped .entry(*license) .or_insert_with(Grouped::default) @@ -234,16 +234,16 @@ impl Node { for (license, mut grouped) in grouped.into_iter() { if grouped.files.len() + grouped.directories.len() <= 1 { if let Some(name) = grouped.files.pop() { - childs.push(Node::File { license, name }); + children.push(Node::File { license, name }); } else if let Some(name) = grouped.directories.pop() { - childs.push(Node::Directory { + children.push(Node::Directory { name, - childs: Vec::new(), + children: Vec::new(), license: Some(license), }); } } else { - childs.push(Node::Group { + children.push(Node::Group { license, files: grouped.files, directories: grouped.directories, @@ -261,11 +261,11 @@ impl Node { /// sure to remove them from the tree. fn remove_empty(&mut self) { match self { - Node::Root { childs } | Node::Directory { childs, .. } => { - for child in &mut *childs { + Node::Root { children } | Node::Directory { children, .. } => { + for child in &mut *children { child.remove_empty(); } - childs.retain(|child| !matches!(child, Node::Empty)); + children.retain(|child| !matches!(child, Node::Empty)); } Node::Group { .. } => {} Node::File { .. } => {} @@ -275,7 +275,7 @@ impl Node { fn license(&self) -> Option { match self { - Node::Directory { childs, license: Some(license), .. } if childs.is_empty() => { + Node::Directory { children, license: Some(license), .. } if children.is_empty() => { Some(*license) } Node::File { license, .. } => Some(*license), @@ -285,7 +285,7 @@ impl Node { } pub(crate) fn build(mut input: Vec<(PathBuf, LicenseId)>) -> Node { - let mut childs = Vec::new(); + let mut children = Vec::new(); // Ensure reproducibility of all future steps. input.sort(); @@ -295,15 +295,15 @@ pub(crate) fn build(mut input: Vec<(PathBuf, LicenseId)>) -> Node { for component in path.parent().unwrap_or_else(|| Path::new(".")).components().rev() { node = Node::Directory { name: component.as_os_str().into(), - childs: vec![node], + children: vec![node], license: None, }; } - childs.push(node); + children.push(node); } - Node::Root { childs } + Node::Root { children } } /// Convert a `Node` into a `Node<&License>`, expanding all interned license IDs with a @@ -313,14 +313,14 @@ pub(crate) fn expand_interned_licenses( interner: &LicensesInterner, ) -> Node<&License> { match node { - Node::Root { childs } => Node::Root { - childs: childs + Node::Root { children } => Node::Root { + children: children .into_iter() .map(|child| expand_interned_licenses(child, interner)) .collect(), }, - Node::Directory { name, childs, license } => Node::Directory { - childs: childs + Node::Directory { name, children, license } => Node::Directory { + children: children .into_iter() .map(|child| expand_interned_licenses(child, interner)) .collect(), diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs index 4d116c7da653..60c77167613d 100644 --- a/src/tools/generate-copyright/src/main.rs +++ b/src/tools/generate-copyright/src/main.rs @@ -20,17 +20,17 @@ fn render_recursive(node: &Node, buffer: &mut Vec, depth: usize) -> Result<( let prefix = std::iter::repeat("> ").take(depth + 1).collect::(); match node { - Node::Root { childs } => { - for child in childs { + Node::Root { children } => { + for child in children { render_recursive(child, buffer, depth)?; } } - Node::Directory { name, childs, license } => { + Node::Directory { name, children, license } => { render_license(&prefix, std::iter::once(name), license, buffer)?; - if !childs.is_empty() { + if !children.is_empty() { writeln!(buffer, "{prefix}")?; writeln!(buffer, "{prefix}*Exceptions:*")?; - for child in childs { + for child in children { writeln!(buffer, "{prefix}")?; render_recursive(child, buffer, depth + 1)?; } @@ -73,8 +73,8 @@ struct Metadata { #[derive(serde::Deserialize)] #[serde(rename_all = "kebab-case", tag = "type")] pub(crate) enum Node { - Root { childs: Vec }, - Directory { name: String, childs: Vec, license: License }, + Root { children: Vec }, + Directory { name: String, children: Vec, license: License }, File { name: String, license: License }, Group { files: Vec, directories: Vec, license: License }, } diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 76770fe36a70..e3d05ec83159 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -237,7 +237,7 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { // Serde json doesn't implement Ord or Hash for Value, so we must // use a Vec here. While in theory that makes setwize equality - // O(n^2), in practice n will never be large enought to matter. + // O(n^2), in practice n will never be large enough to matter. let expected_values = values.iter().map(|v| string_to_value(v, cache)).collect::>(); if expected_values.len() != got_values.len() { diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs index b395c6e7d2d6..45a9c93ee0b5 100644 --- a/src/tools/jsondoclint/src/item_kind.rs +++ b/src/tools/jsondoclint/src/item_kind.rs @@ -1,6 +1,6 @@ use rustdoc_json_types::{Item, ItemEnum, ItemKind, ItemSummary}; -/// A univeral way to represent an [`ItemEnum`] or [`ItemKind`] +/// A universal way to represent an [`ItemEnum`] or [`ItemKind`] #[derive(Debug, Clone, Copy)] pub(crate) enum Kind { Module, @@ -53,7 +53,7 @@ impl Kind { Primitive => true, ForeignType => true, - // FIXME(adotinthevoid): I'm not sure if these are corrent + // FIXME(adotinthevoid): I'm not sure if these are correct Keyword => false, OpaqueTy => false, ProcAttribute => false, diff --git a/src/tools/jsondoclint/src/main.rs b/src/tools/jsondoclint/src/main.rs index 05e938f4f7df..ee163ddfdd9a 100644 --- a/src/tools/jsondoclint/src/main.rs +++ b/src/tools/jsondoclint/src/main.rs @@ -72,7 +72,7 @@ fn main() -> Result<()> { ) } [sel] => eprintln!( - "{} not in index or paths, but refered to at '{}'", + "{} not in index or paths, but referred to at '{}'", err.id.0, json_find::to_jsonpath(&sel) ), @@ -85,12 +85,12 @@ fn main() -> Result<()> { .collect::>() .join(", "); eprintln!( - "{} not in index or paths, but refered to at {sels}", + "{} not in index or paths, but referred to at {sels}", err.id.0 ); } else { eprintln!( - "{} not in index or paths, but refered to at '{}' and {} more", + "{} not in index or paths, but referred to at '{}' and {} more", err.id.0, json_find::to_jsonpath(&sel), sels.len() - 1, diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 395bcc745f8d..bad86701daed 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -86,7 +86,7 @@ def gh_url(): return os.environ['TOOLSTATE_ISSUES_API_URL'] -def maybe_delink(message): +def maybe_unlink(message): # type: (str) -> str if os.environ.get('TOOLSTATE_SKIP_MENTIONS') is not None: return message.replace("@", "") @@ -109,7 +109,7 @@ def issue( else: status_description = 'no longer builds' request = json.dumps({ - 'body': maybe_delink(textwrap.dedent('''\ + 'body': maybe_unlink(textwrap.dedent('''\ Hello, this is your friendly neighborhood mergebot. After merging PR {}, I observed that the tool {} {}. A follow-up PR to the repository {} is needed to fix the fallout. @@ -285,7 +285,7 @@ try: issue_url = gh_url() + '/{}/comments'.format(number) response = urllib2.urlopen(urllib2.Request( issue_url, - json.dumps({'body': maybe_delink(message)}).encode(), + json.dumps({'body': maybe_unlink(message)}).encode(), { 'Authorization': 'token ' + github_token, 'Content-Type': 'application/json', diff --git a/triagebot.toml b/triagebot.toml index 5f4de0562f89..58f51959e1f8 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -344,11 +344,11 @@ message = "Some changes occurred in `const_evaluatable.rs`" cc = ["@BoxyUwU"] [mentions."compiler/rustc_middle/src/ty/abstract_const.rs"] -message = "Some changes occured in `abstract_const.rs`" +message = "Some changes occurred in `abstract_const.rs`" cc = ["@BoxyUwU"] [mentions."compiler/rustc_ty_utils/src/consts.rs"] -message = "Some changes occured in `rustc_ty_utils::consts.rs`" +message = "Some changes occurred in `rustc_ty_utils::consts.rs`" cc = ["@BoxyUwU"] [mentions."compiler/rustc_trait_selection/src/solve/"] From 65c9c79d3f9da41951f7e181b6163ead0f67b6fd Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Mon, 10 Apr 2023 21:57:45 +0200 Subject: [PATCH 166/272] remove obsolete test --- library/core/tests/num/dec2flt/mod.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/library/core/tests/num/dec2flt/mod.rs b/library/core/tests/num/dec2flt/mod.rs index a2b9bb551e67..874e0ec7093c 100644 --- a/library/core/tests/num/dec2flt/mod.rs +++ b/library/core/tests/num/dec2flt/mod.rs @@ -127,14 +127,3 @@ fn massive_exponent() { assert_eq!(format!("1e-{max}000").parse(), Ok(0.0)); assert_eq!(format!("1e{max}000").parse(), Ok(f64::INFINITY)); } - -#[test] -fn borderline_overflow() { - let mut s = "0.".to_string(); - for _ in 0..375 { - s.push('3'); - } - // At the time of this writing, this returns Err(..), but this is a bug that should be fixed. - // It makes no sense to enshrine that in a test, the important part is that it doesn't panic. - let _ = s.parse::(); -} From 677357d32bd402ff1096803cb00b52124204af08 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Mon, 10 Apr 2023 22:02:52 +0200 Subject: [PATCH 167/272] Fix typos in compiler --- compiler/rustc_ast/src/format.rs | 2 +- compiler/rustc_ast_lowering/src/errors.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 6 ++-- .../rustc_borrowck/src/constraints/graph.rs | 32 ++++++++++--------- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- compiler/rustc_builtin_macros/src/format.rs | 2 +- compiler/rustc_codegen_ssa/messages.ftl | 2 +- compiler/rustc_codegen_ssa/src/back/link.rs | 2 +- compiler/rustc_codegen_ssa/src/errors.rs | 4 +-- .../src/const_eval/eval_queries.rs | 2 +- compiler/rustc_expand/messages.ftl | 2 +- compiler/rustc_feature/src/active.rs | 2 +- compiler/rustc_hir_analysis/src/bounds.rs | 2 +- compiler/rustc_hir_typeck/src/demand.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 12 +++---- .../src/fn_ctxt/adjust_fulfillment_errors.rs | 4 +-- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- compiler/rustc_hir_typeck/src/lib.rs | 2 +- .../rustc_hir_typeck/src/method/suggest.rs | 2 +- compiler/rustc_hir_typeck/src/op.rs | 6 ++-- compiler/rustc_infer/messages.ftl | 2 +- compiler/rustc_infer/src/errors/mod.rs | 6 ++-- .../src/infer/error_reporting/mod.rs | 2 +- .../infer/error_reporting/need_type_info.rs | 6 ++-- .../src/infer/error_reporting/note.rs | 4 +-- compiler/rustc_lint/messages.ftl | 4 +-- compiler/rustc_lint/src/internal.rs | 6 ++-- compiler/rustc_lint/src/let_underscore.rs | 2 +- compiler/rustc_lint/src/levels.rs | 4 +-- compiler/rustc_lint/src/lints.rs | 14 ++++---- compiler/rustc_lint/src/non_ascii_idents.rs | 6 ++-- compiler/rustc_lint_defs/src/lib.rs | 2 +- compiler/rustc_middle/src/infer/unify_key.rs | 2 +- compiler/rustc_middle/src/macros.rs | 2 +- .../src/mir/interpret/allocation/init_mask.rs | 2 +- .../interpret/allocation/provenance_map.rs | 2 +- compiler/rustc_middle/src/query/erase.rs | 2 +- compiler/rustc_middle/src/query/keys.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- compiler/rustc_mir_build/src/errors.rs | 8 ++--- .../src/thir/pattern/check_match.rs | 16 +++++----- .../src/framework/graphviz.rs | 16 +++++----- compiler/rustc_mir_transform/src/dest_prop.rs | 2 +- .../src/unreachable_prop.rs | 2 +- .../src/partitioning/mod.rs | 2 +- compiler/rustc_parse/src/lexer/diagnostics.rs | 6 ++-- compiler/rustc_parse/src/lexer/tokentrees.rs | 4 +-- compiler/rustc_parse/src/parser/expr.rs | 2 +- compiler/rustc_parse_format/src/lib.rs | 2 +- compiler/rustc_resolve/messages.ftl | 2 +- compiler/rustc_resolve/src/late.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 2 +- compiler/rustc_span/src/edit_distance.rs | 2 +- compiler/rustc_span/src/hygiene.rs | 2 +- compiler/rustc_target/src/abi/call/mod.rs | 2 +- compiler/rustc_target/src/spec/mod.rs | 2 +- .../src/solve/canonicalize.rs | 4 +-- .../src/solve/eval_ctxt/canonical.rs | 4 +-- .../src/solve/search_graph/mod.rs | 2 +- .../src/solve/search_graph/overflow.rs | 2 +- .../src/traits/select/candidate_assembly.rs | 4 +-- compiler/rustc_ty_utils/messages.ftl | 4 +-- compiler/rustc_ty_utils/src/errors.rs | 2 +- compiler/rustc_ty_utils/src/layout.rs | 2 +- compiler/rustc_type_ir/src/lib.rs | 2 +- ...ethod-not-found-generic-arg-elision.stderr | 2 ++ tests/ui/proc-macro/derive-bad.rs | 2 +- tests/ui/proc-macro/derive-bad.stderr | 2 +- tests/ui/proc-macro/issue-91800.rs | 2 +- tests/ui/proc-macro/issue-91800.stderr | 2 +- 71 files changed, 140 insertions(+), 136 deletions(-) diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs index 356b9bb6371e..699946f307b5 100644 --- a/compiler/rustc_ast/src/format.rs +++ b/compiler/rustc_ast/src/format.rs @@ -94,7 +94,7 @@ impl FormatArguments { } if !matches!(arg.kind, FormatArgumentKind::Captured(..)) { // This is an explicit argument. - // Make sure that all arguments so far are explcit. + // Make sure that all arguments so far are explicit. assert_eq!( self.num_explicit_args, self.arguments.len(), diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index f4e55619ebb1..59fdeacc7bfa 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -137,7 +137,7 @@ pub struct AsyncNonMoveClosureNotSupported { #[derive(Diagnostic, Clone, Copy)] #[diag(ast_lowering_functional_record_update_destructuring_assignment)] -pub struct FunctionalRecordUpdateDestructuringAssignemnt { +pub struct FunctionalRecordUpdateDestructuringAssignment { #[primary_span] #[suggestion(code = "", applicability = "machine-applicable")] pub span: Span, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 3247802345b0..1b1c4765bc07 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,6 +1,6 @@ use super::errors::{ AsyncGeneratorsNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks, - BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignemnt, + BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignment, GeneratorTooManyParameters, InclusiveRangeWithNoEnd, NotSupportedForLifetimeBinderAsyncClosure, UnderscoreExprLhsAssign, }; @@ -434,7 +434,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // `if let pat = val` or `if foo && let pat = val`, as we _do_ want `val` to live beyond the // condition in this case. // - // In order to mantain the drop behavior for the non `let` parts of the condition, + // In order to maintain the drop behavior for the non `let` parts of the condition, // we still wrap them in terminating scopes, e.g. `if foo && let pat = val` essentially // gets transformed into `if { let _t = foo; _t } && let pat = val` match &cond.kind { @@ -1232,7 +1232,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); let fields_omitted = match &se.rest { StructRest::Base(e) => { - self.tcx.sess.emit_err(FunctionalRecordUpdateDestructuringAssignemnt { + self.tcx.sess.emit_err(FunctionalRecordUpdateDestructuringAssignment { span: e.span, }); true diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs index c780d047992c..f5a34cb0561b 100644 --- a/compiler/rustc_borrowck/src/constraints/graph.rs +++ b/compiler/rustc_borrowck/src/constraints/graph.rs @@ -13,7 +13,7 @@ use crate::{ /// The construct graph organizes the constraints by their end-points. /// It can be used to view a `R1: R2` constraint as either an edge `R1 /// -> R2` or `R2 -> R1` depending on the direction type `D`. -pub(crate) struct ConstraintGraph { +pub(crate) struct ConstraintGraph { _direction: D, first_constraints: IndexVec>, next_constraints: IndexVec>, @@ -25,7 +25,7 @@ pub(crate) type ReverseConstraintGraph = ConstraintGraph; /// Marker trait that controls whether a `R1: R2` constraint /// represents an edge `R1 -> R2` or `R2 -> R1`. -pub(crate) trait ConstraintGraphDirecton: Copy + 'static { +pub(crate) trait ConstraintGraphDirection: Copy + 'static { fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid; fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid; fn is_normal() -> bool; @@ -38,7 +38,7 @@ pub(crate) trait ConstraintGraphDirecton: Copy + 'static { #[derive(Copy, Clone, Debug)] pub(crate) struct Normal; -impl ConstraintGraphDirecton for Normal { +impl ConstraintGraphDirection for Normal { fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid { c.sup } @@ -59,7 +59,7 @@ impl ConstraintGraphDirecton for Normal { #[derive(Copy, Clone, Debug)] pub(crate) struct Reverse; -impl ConstraintGraphDirecton for Reverse { +impl ConstraintGraphDirection for Reverse { fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid { c.sub } @@ -73,7 +73,7 @@ impl ConstraintGraphDirecton for Reverse { } } -impl ConstraintGraph { +impl ConstraintGraph { /// Creates a "dependency graph" where each region constraint `R1: /// R2` is treated as an edge `R1 -> R2`. We use this graph to /// construct SCCs for region inference but also for error @@ -133,7 +133,7 @@ impl ConstraintGraph { } } -pub(crate) struct Edges<'s, 'tcx, D: ConstraintGraphDirecton> { +pub(crate) struct Edges<'s, 'tcx, D: ConstraintGraphDirection> { graph: &'s ConstraintGraph, constraints: &'s OutlivesConstraintSet<'tcx>, pointer: Option, @@ -141,7 +141,7 @@ pub(crate) struct Edges<'s, 'tcx, D: ConstraintGraphDirecton> { static_region: RegionVid, } -impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Edges<'s, 'tcx, D> { +impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Edges<'s, 'tcx, D> { type Item = OutlivesConstraint<'tcx>; fn next(&mut self) -> Option { @@ -174,13 +174,13 @@ impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Edges<'s, 'tcx, D> { /// This struct brings together a constraint set and a (normal, not /// reverse) constraint graph. It implements the graph traits and is /// usd for doing the SCC computation. -pub(crate) struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirecton> { +pub(crate) struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirection> { set: &'s OutlivesConstraintSet<'tcx>, constraint_graph: &'s ConstraintGraph, static_region: RegionVid, } -impl<'s, 'tcx, D: ConstraintGraphDirecton> RegionGraph<'s, 'tcx, D> { +impl<'s, 'tcx, D: ConstraintGraphDirection> RegionGraph<'s, 'tcx, D> { /// Creates a "dependency graph" where each region constraint `R1: /// R2` is treated as an edge `R1 -> R2`. We use this graph to /// construct SCCs for region inference but also for error @@ -202,11 +202,11 @@ impl<'s, 'tcx, D: ConstraintGraphDirecton> RegionGraph<'s, 'tcx, D> { } } -pub(crate) struct Successors<'s, 'tcx, D: ConstraintGraphDirecton> { +pub(crate) struct Successors<'s, 'tcx, D: ConstraintGraphDirection> { edges: Edges<'s, 'tcx, D>, } -impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Successors<'s, 'tcx, D> { +impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'s, 'tcx, D> { type Item = RegionVid; fn next(&mut self) -> Option { @@ -214,23 +214,25 @@ impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Successors<'s, 'tcx, D> } } -impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> { +impl<'s, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> { type Node = RegionVid; } -impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::WithNumNodes for RegionGraph<'s, 'tcx, D> { +impl<'s, 'tcx, D: ConstraintGraphDirection> graph::WithNumNodes for RegionGraph<'s, 'tcx, D> { fn num_nodes(&self) -> usize { self.constraint_graph.first_constraints.len() } } -impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::WithSuccessors for RegionGraph<'s, 'tcx, D> { +impl<'s, 'tcx, D: ConstraintGraphDirection> graph::WithSuccessors for RegionGraph<'s, 'tcx, D> { fn successors(&self, node: Self::Node) -> >::Iter { self.outgoing_regions(node) } } -impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::GraphSuccessors<'_> for RegionGraph<'s, 'tcx, D> { +impl<'s, 'tcx, D: ConstraintGraphDirection> graph::GraphSuccessors<'_> + for RegionGraph<'s, 'tcx, D> +{ type Item = RegionVid; type Iter = Successors<'s, 'tcx, D>; } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 624a4a00c319..5658b956ec09 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2600,7 +2600,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.implicit_region_bound, self.param_env, location.to_locations(), - DUMMY_SP, // irrelevant; will be overrided. + DUMMY_SP, // irrelevant; will be overridden. ConstraintCategory::Boring, // same as above. &mut self.borrowck_context.constraints, ) diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index db2ef7fba4b8..03d2d60de744 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -40,7 +40,7 @@ struct MacroInput { fmtstr: P, args: FormatArguments, /// Whether the first argument was a string literal or a result from eager macro expansion. - /// If it's not a string literal, we disallow implicit arugment capturing. + /// If it's not a string literal, we disallow implicit argument capturing. /// /// This does not correspond to whether we can treat spans to the literal normally, as the whole /// invocation might be the result of another macro expansion, in which case this flag may still be true. diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 8fe5f8d50abe..243be0e1f70e 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -141,7 +141,7 @@ codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but 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_unsufficient_vs_code_product = VS Code is a different product, and is not sufficient. +codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient. codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status} .note = {$output} diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 7a5fa5a370cb..02e21e74fadc 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -923,7 +923,7 @@ fn link_natively<'a>( if sess.target.is_like_msvc && linker_not_found { sess.emit_note(errors::MsvcMissingLinker); sess.emit_note(errors::CheckInstalledVisualStudio); - sess.emit_note(errors::UnsufficientVSCodeProduct); + sess.emit_note(errors::InsufficientVSCodeProduct); } sess.abort_if_errors(); } diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 6dea7496fc3e..66e7e314f79d 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -405,8 +405,8 @@ pub struct MsvcMissingLinker; pub struct CheckInstalledVisualStudio; #[derive(Diagnostic)] -#[diag(codegen_ssa_unsufficient_vs_code_product)] -pub struct UnsufficientVSCodeProduct; +#[diag(codegen_ssa_insufficient_vs_code_product)] +pub struct InsufficientVSCodeProduct; #[derive(Diagnostic)] #[diag(codegen_ssa_processing_dymutil_failed)] diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 7564ba17b404..4bd6fe19931e 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -205,7 +205,7 @@ pub(crate) fn turn_into_const_value<'tcx>( let cid = key.value; let def_id = cid.instance.def.def_id(); let is_static = tcx.is_static(def_id); - // This is just accessing an already computed constant, so no need to check alginment here. + // This is just accessing an already computed constant, so no need to check alignment here. let ecx = mk_eval_cx( tcx, tcx.def_span(key.value.instance.def_id()), diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index cfae781bdee5..5d999d0db5db 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -135,4 +135,4 @@ expand_proc_macro_panicked = .help = message: {$message} expand_proc_macro_derive_tokens = - proc-macro derive produced unparseable tokens + proc-macro derive produced unparsable tokens diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 426c6727adca..2aa9101bff0a 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -309,7 +309,7 @@ declare_features! ( (active, associated_type_defaults, "1.2.0", Some(29661), None), /// Allows `async || body` closures. (active, async_closure, "1.37.0", Some(62290), None), - /// Alows async functions to be declared, implemented, and used in traits. + /// Allows async functions to be declared, implemented, and used in traits. (incomplete, async_fn_in_trait, "1.66.0", Some(91611), None), /// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries. (active, c_unwind, "1.52.0", Some(74990), None), diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 0880c8c15f2e..284b099e7bc7 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -58,7 +58,7 @@ impl<'tcx> Bounds<'tcx> { pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) { let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span)); let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(sized_def_id, [ty])); - // Preferrable to put this obligation first, since we report better errors for sized ambiguity. + // Preferable to put this obligation first, since we report better errors for sized ambiguity. self.predicates.insert(0, (trait_ref.without_const().to_predicate(tcx), span)); } diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 30d307948a6c..a4c3be1d1774 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -308,7 +308,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let rcvr_ty = self.node_ty(rcvr.hir_id); // Get the evaluated type *after* calling the method call, so that the influence // of the arguments can be reflected in the receiver type. The receiver - // expression has the type *before* theis analysis is done. + // expression has the type *before* this analysis is done. let ty = match self.lookup_probe_for_diagnostic( segment.ident, rcvr_ty, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 68e096e3bd02..6ffa0134f3d5 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -120,7 +120,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } - pub(super) fn check_expr_coercable_to_type( + pub(super) fn check_expr_coercible_to_type( &self, expr: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>, @@ -1128,7 +1128,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - // This is (basically) inlined `check_expr_coercable_to_type`, but we want + // This is (basically) inlined `check_expr_coercible_to_type`, but we want // to suggest an additional fixup here in `suggest_deref_binop`. let rhs_ty = self.check_expr_with_hint(&rhs, lhs_ty); if let (_, Some(mut diag)) = @@ -1401,7 +1401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (element_ty, t) = match uty { Some(uty) => { - self.check_expr_coercable_to_type(&element, uty, None); + self.check_expr_coercible_to_type(&element, uty, None); (uty, uty) } None => { @@ -1478,7 +1478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| match flds { Some(fs) if i < fs.len() => { let ety = fs[i]; - self.check_expr_coercable_to_type(&e, ety, None); + self.check_expr_coercible_to_type(&e, ety, None); ety } _ => self.check_expr_with_expectation(&e, NoExpectation), @@ -2869,7 +2869,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { match self.resume_yield_tys { Some((resume_ty, yield_ty)) => { - self.check_expr_coercable_to_type(&value, yield_ty, None); + self.check_expr_coercible_to_type(&value, yield_ty, None); resume_ty } @@ -2878,7 +2878,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // information. Hence, we check the source of the yield expression here and check its // value's type against `()` (this check should always hold). None if src.is_await() => { - self.check_expr_coercable_to_type(&value, self.tcx.mk_unit(), None); + self.check_expr_coercible_to_type(&value, self.tcx.mk_unit(), None); self.tcx.mk_unit() } _ => { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index 3e0c2bf2a553..e887ab2fa142 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -466,7 +466,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// obligation. Hence we refine the `expr` "outwards-in" and bail at the first kind of expression/impl we don't recognize. /// /// This function returns a `Result<&Expr, &Expr>` - either way, it returns the `Expr` whose span should be - /// reported as an error. If it is `Ok`, then it means it refined successfull. If it is `Err`, then it may be + /// reported as an error. If it is `Ok`, then it means it refined successful. If it is `Err`, then it may be /// only a partial success - but it cannot be refined even further. fn blame_specific_expr_if_possible_for_derived_predicate_obligation( &self, @@ -534,7 +534,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// - in_ty: `(Option, bool)` /// we would drill until we arrive at `vec![1, 2, 3]`. /// - /// If successful, we return `Ok(refined_expr)`. If unsuccesful, we return `Err(partially_refined_expr`), + /// If successful, we return `Ok(refined_expr)`. If unsuccessful, we return `Err(partially_refined_expr`), /// which will go as far as possible. For example, given `(foo(), false)` instead, we would drill to /// `foo()` and then return `Err("foo()")`. /// diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index b02eae19fce1..5473b2bae2da 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1413,7 +1413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.demand_eqtype(init.span, local_ty, init_ty); init_ty } else { - self.check_expr_coercable_to_type(init, local_ty, None) + self.check_expr_coercible_to_type(init, local_ty, None) } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 6af095cb4d43..45890abad92e 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -280,7 +280,7 @@ fn typeck_with_fallback<'tcx>( // Gather locals in statics (because of block expressions). GatherLocalsVisitor::new(&fcx).visit_body(body); - fcx.check_expr_coercable_to_type(&body.value, expected_type, None); + fcx.check_expr_coercible_to_type(&body.value, expected_type, None); fcx.write_ty(id, expected_type); }; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 5c50619f4c3c..7702a8b7004f 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -300,7 +300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // We could pass the file for long types into these two, but it isn't strictly necessary - // given how targetted they are. + // given how targeted they are. if self.suggest_wrapping_range_with_parens( tcx, rcvr_ty, diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 8a83bb58573d..0ab6af127c09 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -103,9 +103,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match BinOpCategory::from(op) { BinOpCategory::Shortcircuit => { // && and || are a simple case. - self.check_expr_coercable_to_type(lhs_expr, tcx.types.bool, None); + self.check_expr_coercible_to_type(lhs_expr, tcx.types.bool, None); let lhs_diverges = self.diverges.get(); - self.check_expr_coercable_to_type(rhs_expr, tcx.types.bool, None); + self.check_expr_coercible_to_type(rhs_expr, tcx.types.bool, None); // Depending on the LHS' value, the RHS can never execute. self.diverges.set(lhs_diverges); @@ -255,7 +255,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); // see `NB` above - let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var, Some(lhs_expr)); + let rhs_ty = self.check_expr_coercible_to_type(rhs_expr, rhs_ty_var, Some(lhs_expr)); let rhs_ty = self.resolve_vars_with_obligations(rhs_ty); let return_ty = match result { diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index 1e43644be89a..c90519bdf8f2 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -174,7 +174,7 @@ infer_region_explanation = {$pref_kind -> infer_outlives_content = lifetime of reference outlives lifetime of borrowed content... infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type -infer_fullfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime +infer_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime infer_lf_bound_not_satisfied = lifetime bound not satisfied infer_borrowed_too_long = a value of type `{$ty}` is borrowed for too long infer_ref_longer_than_data = in type `{$ty}`, reference has a longer lifetime than the data it references diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 6bbd3fd3e6e7..53d0d37a314f 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -53,7 +53,7 @@ pub struct AnnotationRequired<'a> { // Copy of `AnnotationRequired` for E0283 #[derive(Diagnostic)] #[diag(infer_type_annotations_needed, code = "E0283")] -pub struct AmbigousImpl<'a> { +pub struct AmbiguousImpl<'a> { #[primary_span] pub span: Span, pub source_kind: &'static str, @@ -954,8 +954,8 @@ pub struct OutlivesBound<'a> { } #[derive(Diagnostic)] -#[diag(infer_fullfill_req_lifetime, code = "E0477")] -pub struct FullfillReqLifetime<'a> { +#[diag(infer_fulfill_req_lifetime, code = "E0477")] +pub struct FulfillReqLifetime<'a> { #[primary_span] pub span: Span, pub ty: Ty<'a>, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 86fca9797d02..96aaff2457c2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1808,7 +1808,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // will try to hide in some case such as `async fn`, so // to make an error more use friendly we will // avoid to suggest a mismatch type with a - // type that the user usually are not usign + // type that the user usually are not using // directly such as `impl Future`. if !self.tcx.ty_is_opaque_future(found_ty) { diag.note_expected_found_extra( diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index d7b900ca02d3..75cc4e257bd8 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -1,5 +1,5 @@ use crate::errors::{ - AmbigousImpl, AmbigousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator, + AmbigousReturn, AmbiguousImpl, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator, SourceKindMultiSuggestion, SourceKindSubdiag, }; use crate::infer::error_reporting::TypeErrCtxt; @@ -358,7 +358,7 @@ impl<'tcx> InferCtxt<'tcx> { bad_label, } .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), - TypeAnnotationNeeded::E0283 => AmbigousImpl { + TypeAnnotationNeeded::E0283 => AmbiguousImpl { span, source_kind, source_name, @@ -563,7 +563,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { bad_label: None, } .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), - TypeAnnotationNeeded::E0283 => AmbigousImpl { + TypeAnnotationNeeded::E0283 => AmbiguousImpl { span, source_kind, source_name: &name, diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index e720af73c39f..07a9eff2dbef 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -1,5 +1,5 @@ use crate::errors::{ - note_and_explain, FullfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, + note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, RefLongerThanData, RegionOriginNote, WhereClauseSuggestions, }; use crate::fluent_generated as fluent; @@ -176,7 +176,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let note = note_and_explain::RegionExplanation::new( self.tcx, sub, opt_span, prefix, suffix, ); - FullfillReqLifetime { span, ty: self.resolve_vars_if_possible(ty), note } + FulfillReqLifetime { span, ty: self.resolve_vars_if_possible(ty), note } .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) } infer::RelateRegionParamBound(span) => { diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index d9c8142226d2..db15b176df00 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -91,7 +91,7 @@ lint_ty_qualified = usage of qualified `ty::{$ty}` lint_lintpass_by_hand = implementing `LintPass` by hand .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead -lint_non_existant_doc_keyword = found non-existing keyword `{$keyword}` used in `#[doc(keyword = "...")]` +lint_non_existent_doc_keyword = found non-existing keyword `{$keyword}` used in `#[doc(keyword = "...")]` .help = only existing keywords are allowed in core/std lint_diag_out_of_impl = @@ -107,7 +107,7 @@ lint_cstring_ptr = getting the inner pointer of a temporary `CString` .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned .help = for more information, see https://doc.rust-lang.org/reference/destructors.html -lint_multple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits +lint_multiple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits lint_identifier_non_ascii_char = identifier contains non-ASCII characters diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 9c7feadaf874..4ac589c2e10f 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -2,7 +2,7 @@ //! Clippy. use crate::lints::{ - BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistantDocKeyword, + BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword, QueryInstability, TyQualified, TykindDiag, TykindKind, UntranslatableDiag, }; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; @@ -334,7 +334,7 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword { cx.emit_spanned_lint( EXISTING_DOC_KEYWORD, attr.span, - NonExistantDocKeyword { keyword }, + NonExistentDocKeyword { keyword }, ); } } @@ -424,7 +424,7 @@ impl LateLintPass<'_> for Diagnostics { } declare_tool_lint! { - /// The `bad_opt_access` lint detects accessing options by field instad of + /// The `bad_opt_access` lint detects accessing options by field instead of /// the wrapper function. pub rustc::BAD_OPT_ACCESS, Deny, diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index b83a9665fc0c..3eefd1b0e083 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -25,7 +25,7 @@ declare_lint! { /// /// fn main() { /// #[warn(let_underscore_drop)] - /// // SomeStuct is dropped immediately instead of at end of scope, + /// // SomeStruct is dropped immediately instead of at end of scope, /// // so "Dropping SomeStruct" is printed before "end of main". /// // The order of prints would be reversed if SomeStruct was bound to /// // a name (such as "_foo"). diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index a2a7c93a7ca9..bb863f095168 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -3,7 +3,7 @@ use crate::{ fluent_generated as fluent, late::unerased_lint_store, lints::{ - DeprecatedLintName, IgnoredUnlessCrateSpecified, OverruledAtributeLint, + DeprecatedLintName, IgnoredUnlessCrateSpecified, OverruledAttributeLint, RenamedOrRemovedLint, RenamedOrRemovedLintSuggestion, UnknownLint, UnknownLintSuggestion, }, }; @@ -612,7 +612,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { self.emit_spanned_lint( FORBIDDEN_LINT_GROUPS, src.span().into(), - OverruledAtributeLint { + OverruledAttributeLint { overruled: src.span(), lint_level: level.as_str(), lint_source: src.name(), diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 8ec4c2b3d463..1d5e02369f52 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -806,9 +806,9 @@ pub struct TyQualified { pub struct LintPassByHand; #[derive(LintDiagnostic)] -#[diag(lint_non_existant_doc_keyword)] +#[diag(lint_non_existent_doc_keyword)] #[help] -pub struct NonExistantDocKeyword { +pub struct NonExistentDocKeyword { pub keyword: Symbol, } @@ -875,7 +875,7 @@ impl AddToDiagnostic for NonBindingLetSub { // levels.rs #[derive(LintDiagnostic)] #[diag(lint_overruled_attribute)] -pub struct OverruledAtributeLint<'a> { +pub struct OverruledAttributeLint<'a> { #[label] pub overruled: Span, pub lint_level: &'a str, @@ -947,7 +947,7 @@ pub struct CStringPtr { // multiple_supertrait_upcastable.rs #[derive(LintDiagnostic)] -#[diag(lint_multple_supertrait_upcastable)] +#[diag(lint_multiple_supertrait_upcastable)] pub struct MultipleSupertraitUpcastable { pub ident: Ident, } @@ -1422,7 +1422,7 @@ pub struct UnusedResult<'a> { pub ty: Ty<'a>, } -// FIXME(davidtwco): this isn't properly translatable becauses of the +// FIXME(davidtwco): this isn't properly translatable because of the // pre/post strings #[derive(LintDiagnostic)] #[diag(lint_unused_closure)] @@ -1433,7 +1433,7 @@ pub struct UnusedClosure<'a> { pub post: &'a str, } -// FIXME(davidtwco): this isn't properly translatable becauses of the +// FIXME(davidtwco): this isn't properly translatable because of the // pre/post strings #[derive(LintDiagnostic)] #[diag(lint_unused_generator)] @@ -1444,7 +1444,7 @@ pub struct UnusedGenerator<'a> { pub post: &'a str, } -// FIXME(davidtwco): this isn't properly translatable becauses of the pre/post +// FIXME(davidtwco): this isn't properly translatable because of the pre/post // strings pub struct UnusedDef<'a, 'b> { pub pre: &'a str, diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index f130a98185d6..4af879b4e912 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -250,7 +250,7 @@ impl EarlyLintPass for NonAsciiIdents { let latin_augmented_script_set = AugmentedScriptSet::for_char('A'); script_states.insert(latin_augmented_script_set, ScriptSetUsage::Verified); - let mut has_suspicous = false; + let mut has_suspicious = false; for (symbol, &sp) in symbols.iter() { let symbol_str = symbol.as_str(); for ch in symbol_str.chars() { @@ -278,14 +278,14 @@ impl EarlyLintPass for NonAsciiIdents { if !is_potential_mixed_script_confusable_char(ch) { ScriptSetUsage::Verified } else { - has_suspicous = true; + has_suspicious = true; ScriptSetUsage::Suspicious(vec![ch], sp) } }); } } - if has_suspicous { + if has_suspicious { let verified_augmented_script_sets = script_states .iter() .flat_map(|(k, v)| match v { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 69a8b691ab21..7ea472ed504a 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -532,7 +532,7 @@ pub enum BuiltinLintDiagnostics { AmbiguousGlobReexports { /// The name for which collision(s) have occurred. name: String, - /// The name space for whihc the collision(s) occurred in. + /// The name space for which the collision(s) occurred in. namespace: String, /// Span where the name is first re-exported. first_reexport_span: Span, diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index d83a587a86ae..a873854f0686 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -58,7 +58,7 @@ impl<'tcx> UnifyValue for UnifiedRegion<'tcx> { fn unify_values(value1: &Self, value2: &Self) -> Result { // We pick the value of the least universe because it is compatible with more variables. - // This is *not* neccessary for soundness, but it allows more region variables to be + // This is *not* necessary for soundness, but it allows more region variables to be // resolved to the said value. #[cold] fn min_universe<'tcx>(r1: Region<'tcx>, r2: Region<'tcx>) -> Region<'tcx> { diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index a8d71ce030c2..89014f62d4d6 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -1,6 +1,6 @@ /// A macro for triggering an ICE. /// Calling `bug` instead of panicking will result in a nicer error message and should -/// therefore be prefered over `panic`/`unreachable` or others. +/// therefore be preferred over `panic`/`unreachable` or others. /// /// If you have a span available, you should use [`span_bug`] instead. /// diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs index 9a02bc0cc15f..dcb56a1755e4 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs @@ -63,7 +63,7 @@ impl InitMask { } /// Sets a specified range to a value. If the range is out-of-bounds, the mask will grow to - /// accomodate it entirely. + /// accommodate it entirely. pub fn set_range(&mut self, range: AllocRange, new_state: bool) { let start = range.start; let end = range.end(); diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index ddd3f394358a..318f93e12b58 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -14,7 +14,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; #[derive(HashStable)] pub struct ProvenanceMap { /// Provenance in this map applies from the given offset for an entire pointer-size worth of - /// bytes. Two entires in this map are always at least a pointer size apart. + /// bytes. Two entries in this map are always at least a pointer size apart. ptrs: SortedMap, /// Provenance in this map only applies to the given single byte. /// This map is disjoint from the previous. It will always be empty when diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 24d98665a7b4..7d9aea022898 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -37,7 +37,7 @@ pub fn erase(src: T) -> Erase { #[inline(always)] pub fn restore(value: Erase) -> T { let value: Erased<::Result> = value; - // SAFETY: Due to the use of impl Trait in `Erase` the only way to safetly create an instance + // SAFETY: Due to the use of impl Trait in `Erase` the only way to safely create an instance // of `Erase` is to call `erase`, so we know that `value.data` is a valid instance of `T` of // the right size. unsafe { transmute_copy(&value.data) } diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 4a096a2c0e84..c767558f7385 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -26,7 +26,7 @@ pub trait Key: Sized { // // ...But r-a doesn't support them yet and using a default here causes r-a to not infer // return types of queries which is very annoying. Thus, until r-a support associated - // type defaults, plese restrain from using them here <3 + // type defaults, please restrain from using them here <3 // // r-a issue: type CacheSelector; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index a0fce4b47ca3..686703e72223 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -97,7 +97,7 @@ rustc_queries! { /// Gives access to the HIR ID for the given `LocalDefId` owner `key` if any. /// - /// Definitions that were generated with no HIR, would be feeded to return `None`. + /// Definitions that were generated with no HIR, would be fed to return `None`. query opt_local_def_id_to_hir_id(key: LocalDefId) -> Option{ desc { |tcx| "getting HIR ID of `{}`", tcx.def_path_str(key.to_def_id()) } feedable diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index bc0ccc1ebc3a..72caadaf6619 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1347,7 +1347,7 @@ pub trait PrettyPrinter<'tcx>: p!(write("{}::{}", self.tcx().crate_name(def.did.krate), self.tcx().def_path(def.did).to_string_no_crate_verbose())) } } - defkind => bug!("`{:?}` has unexpcted defkind {:?}", ct, defkind), + defkind => bug!("`{:?}` has unexpected defkind {:?}", ct, defkind), } } ty::ConstKind::Infer(infer_ct) => { diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 431c3255ab2a..43e787db41a8 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -593,7 +593,7 @@ pub struct MultipleMutBorrows { #[primary_span] pub span: Span, #[subdiagnostic] - pub occurences: Vec, + pub occurrences: Vec, } #[derive(Diagnostic)] @@ -602,7 +602,7 @@ pub struct AlreadyBorrowed { #[primary_span] pub span: Span, #[subdiagnostic] - pub occurences: Vec, + pub occurrences: Vec, } #[derive(Diagnostic)] @@ -611,7 +611,7 @@ pub struct AlreadyMutBorrowed { #[primary_span] pub span: Span, #[subdiagnostic] - pub occurences: Vec, + pub occurrences: Vec, } #[derive(Diagnostic)] @@ -620,7 +620,7 @@ pub struct MovedWhileBorrowed { #[primary_span] pub span: Span, #[subdiagnostic] - pub occurences: Vec, + pub occurrences: Vec, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 0882b473f108..bac46db2b1e6 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -966,30 +966,30 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, '_, 'tcx>, let report_mut_ref = !conflicts_mut_ref.is_empty(); let report_move_conflict = !conflicts_move.is_empty(); - let mut occurences = match mut_outer { + let mut occurrences = match mut_outer { Mutability::Mut => vec![Conflict::Mut { span: pat.span, name }], Mutability::Not => vec![Conflict::Ref { span: pat.span, name }], }; - occurences.extend(conflicts_mut_mut); - occurences.extend(conflicts_mut_ref); - occurences.extend(conflicts_move); + occurrences.extend(conflicts_mut_mut); + occurrences.extend(conflicts_mut_ref); + occurrences.extend(conflicts_move); // Report errors if any. if report_mut_mut { // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`. - sess.emit_err(MultipleMutBorrows { span: pat.span, occurences }); + sess.emit_err(MultipleMutBorrows { span: pat.span, occurrences }); } else if report_mut_ref { // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse. match mut_outer { Mutability::Mut => { - sess.emit_err(AlreadyMutBorrowed { span: pat.span, occurences }); + sess.emit_err(AlreadyMutBorrowed { span: pat.span, occurrences }); } Mutability::Not => { - sess.emit_err(AlreadyBorrowed { span: pat.span, occurences }); + sess.emit_err(AlreadyBorrowed { span: pat.span, occurrences }); } }; } else if report_move_conflict { // Report by-ref and by-move conflicts, e.g. `ref x @ y`. - sess.emit_err(MovedWhileBorrowed { span: pat.span, occurences }); + sess.emit_err(MovedWhileBorrowed { span: pat.span, occurrences }); } } diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index c188105eae89..707729f8f21b 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -394,8 +394,8 @@ where ) -> io::Result<()> { let diffs = StateDiffCollector::run(body, block, self.results.results(), self.style); - let mut befores = diffs.before.map(|v| v.into_iter()); - let mut afters = diffs.after.into_iter(); + let mut diffs_before = diffs.before.map(|v| v.into_iter()); + let mut diffs_after = diffs.after.into_iter(); let next_in_dataflow_order = |it: &mut std::vec::IntoIter<_>| { if A::Direction::IS_FORWARD { it.next().unwrap() } else { it.next_back().unwrap() } @@ -405,8 +405,8 @@ where let statement_str = format!("{statement:?}"); let index_str = format!("{i}"); - let after = next_in_dataflow_order(&mut afters); - let before = befores.as_mut().map(next_in_dataflow_order); + let after = next_in_dataflow_order(&mut diffs_after); + let before = diffs_before.as_mut().map(next_in_dataflow_order); self.write_row(w, &index_str, &statement_str, |_this, w, fmt| { if let Some(before) = before { @@ -417,11 +417,11 @@ where })?; } - let after = next_in_dataflow_order(&mut afters); - let before = befores.as_mut().map(next_in_dataflow_order); + let after = next_in_dataflow_order(&mut diffs_after); + let before = diffs_before.as_mut().map(next_in_dataflow_order); - assert!(afters.is_empty()); - assert!(befores.as_ref().map_or(true, ExactSizeIterator::is_empty)); + assert!(diffs_after.is_empty()); + assert!(diffs_before.as_ref().map_or(true, ExactSizeIterator::is_empty)); let terminator = body[block].terminator(); let mut terminator_str = String::new(); diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 811935aa9908..391649177708 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -83,7 +83,7 @@ //! that ever have their address taken. Of course that requires actually having alias analysis //! (and a model to build it on), so this might be a bit of a ways off. //! -//! * Various perf improvents. There are a bunch of comments in here marked `PERF` with ideas for +//! * Various perf improvements. There are a bunch of comments in here marked `PERF` with ideas for //! how to do things more efficiently. However, the complexity of the pass as a whole should be //! kept in mind. //! diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs index d4b1cfe43372..bd1724bf8424 100644 --- a/compiler/rustc_mir_transform/src/unreachable_prop.rs +++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs @@ -99,7 +99,7 @@ where // // This generates a `switchInt() -> [0: 0, 1: 1, otherwise: unreachable]`, which allows us or LLVM to // turn it into just `x` later. Without the unreachable, such a transformation would be illegal. - // If the otherwise branch is unreachable, we can delete all other unreacahble targets, as they will + // If the otherwise branch is unreachable, we can delete all other unreachable targets, as they will // still point to the unreachable and therefore not lose reachability information. let reachable_iter = targets.iter().filter(|(_, bb)| !is_unreachable(*bb)); diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index 7ac1c9e057e8..18aa0742c099 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -474,7 +474,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co (tcx.arena.alloc(mono_items), codegen_units) } -/// Outputs stats about instantation counts and estimated size, per `MonoItem`'s +/// Outputs stats about instantiation counts and estimated size, per `MonoItem`'s /// def, to a file in the given output directory. fn dump_mono_items_stats<'tcx>( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs index c4b9fdc81c5e..9e6d27bf036f 100644 --- a/compiler/rustc_parse/src/lexer/diagnostics.rs +++ b/compiler/rustc_parse/src/lexer/diagnostics.rs @@ -21,7 +21,7 @@ pub struct TokenTreeDiagInfo { pub matching_block_spans: Vec<(Span, Span)>, } -pub fn same_identation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> bool { +pub fn same_indentation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> bool { match (sm.span_to_margin(open_sp), sm.span_to_margin(close_sp)) { (Some(open_padding), Some(close_padding)) => open_padding == close_padding, _ => false, @@ -67,13 +67,13 @@ pub fn report_suspicious_mismatch_block( let mut matched_spans: Vec<(Span, bool)> = diag_info .matching_block_spans .iter() - .map(|&(open, close)| (open.with_hi(close.lo()), same_identation_level(sm, open, close))) + .map(|&(open, close)| (open.with_hi(close.lo()), same_indentation_level(sm, open, close))) .collect(); // sort by `lo`, so the large block spans in the front matched_spans.sort_by_key(|(span, _)| span.lo()); - // We use larger block whose identation is well to cover those inner mismatched blocks + // We use larger block whose indentation is well to cover those inner mismatched blocks // O(N^2) here, but we are on error reporting path, so it is fine for i in 0..matched_spans.len() { let (block_span, same_ident) = matched_spans[i]; diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index 36fd1e37d651..7c2c0895193e 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -1,5 +1,5 @@ use super::diagnostics::report_suspicious_mismatch_block; -use super::diagnostics::same_identation_level; +use super::diagnostics::same_indentation_level; use super::diagnostics::TokenTreeDiagInfo; use super::{StringReader, UnmatchedDelim}; use rustc_ast::token::{self, Delimiter, Token}; @@ -153,7 +153,7 @@ impl<'a> TokenTreesReader<'a> { unclosed_delimiter = Some(sp); }; for (brace, brace_span) in &self.diag_info.open_braces { - if same_identation_level(&sm, self.token.span, *brace_span) + if same_indentation_level(&sm, self.token.span, *brace_span) && brace == &close_delim { // high likelihood of these two corresponding diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index c4605e63cf39..03c82fbd329f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2767,7 +2767,7 @@ impl<'a> Parser<'a> { (token::DotDotEq, token::Gt) ) { // `error_inclusive_range_match_arrow` handles cases like `0..=> {}`, - // so we supress the error here + // so we suppress the error here err.delay_as_bug(); this.bump(); } else { diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 1c5410c5658c..7de84db211ed 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -909,7 +909,7 @@ fn find_width_map_from_snippet( // Strip quotes. let snippet = &snippet[1..snippet.len() - 1]; - // Macros like `println` add a newline at the end. That technically doens't make them "literals" anymore, but it's fine + // Macros like `println` add a newline at the end. That technically doesn't make them "literals" anymore, but it's fine // since we will never need to point our spans there, so we lie about it here by ignoring it. // Since there might actually be newlines in the source code, we need to normalize away all trailing newlines. // If we only trimmed it off the input, `format!("\n")` would cause a mismatch as here we they actually match up. diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 2199ceee5326..9a5ecddb74ab 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -42,7 +42,7 @@ resolve_try_adding_local_generic_param_on_method = try adding a local generic parameter in this method instead resolve_help_try_using_local_generic_param = - try using a local generic paramter instead + try using a local generic parameter instead resolve_name_is_already_used_as_generic_parameter = the name `{$name}` is already used for a generic parameter in this item's generic parameters diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 31ac3f1c151e..47d688e48fe9 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -598,7 +598,7 @@ struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { /// The current set of local scopes for types and values. ribs: PerNS>>, - /// Previous poped `rib`, only used for diagnostic. + /// Previous popped `rib`, only used for diagnostic. last_block_rib: Option>, /// The current set of local scopes, for labels. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 99fad22d4a12..274155b19aac 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1652,7 +1652,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { misc2: AmbiguityErrorMisc::None, }; if !self.matches_previous_ambiguity_error(&ambiguity_error) { - // avoid dumplicated span information to be emitt out + // avoid duplicated span information to be emitt out self.ambiguity_errors.push(ambiguity_error); } } diff --git a/compiler/rustc_span/src/edit_distance.rs b/compiler/rustc_span/src/edit_distance.rs index 9fe9e3a7a5fd..259f42386548 100644 --- a/compiler/rustc_span/src/edit_distance.rs +++ b/compiler/rustc_span/src/edit_distance.rs @@ -219,7 +219,7 @@ fn find_best_match_for_name_impl( } // We have a tie among several candidates, try to select the best among them ignoring substrings. - // For example, the candidates list `force_capture`, `capture`, and user inputed `forced_capture`, + // For example, the candidates list `force_capture`, `capture`, and user inputted `forced_capture`, // we select `force_capture` with a extra round of edit distance calculation. if next_candidates.len() > 1 { debug_assert!(use_substring_score); diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 0bb42a3a71fd..08c4414034a0 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1207,7 +1207,7 @@ impl HygieneEncodeContext { // a `SyntaxContext` that we haven't seen before while !self.latest_ctxts.lock().is_empty() || !self.latest_expns.lock().is_empty() { debug!( - "encode_hygiene: Serializing a round of {:?} SyntaxContextDatas: {:?}", + "encode_hygiene: Serializing a round of {:?} SyntaxContextData: {:?}", self.latest_ctxts.lock().len(), self.latest_ctxts ); diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index a0730fbb650d..57011aa8a147 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -755,7 +755,7 @@ impl FromStr for Conv { "AmdGpuKernel" => Ok(Conv::AmdGpuKernel), "AvrInterrupt" => Ok(Conv::AvrInterrupt), "AvrNonBlockingInterrupt" => Ok(Conv::AvrNonBlockingInterrupt), - _ => Err(format!("'{s}' is not a valid value for entry function call convetion.")), + _ => Err(format!("'{s}' is not a valid value for entry function call convention.")), } } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 62c58c204e09..67c22555c5ea 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -123,7 +123,7 @@ pub enum Lld { /// target properties, in accordance with the first design goal. /// /// The first component of the flavor is tightly coupled with the compilation target, -/// while the `Cc` and `Lld` flags can vary withing the same target. +/// while the `Cc` and `Lld` flags can vary within the same target. #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum LinkerFlavor { /// Unix-like linker with GNU extensions (both naked and compiler-wrapped forms). diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs index 55025e2e72b9..25e7439ece79 100644 --- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs +++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{TypeFoldable, TypeFolder, TypeSuperFoldable}; -/// Whether we're canonicalizing a query input or the query reponse. +/// Whether we're canonicalizing a query input or the query response. /// /// When canonicalizing an input we're in the context of the caller /// while canonicalizing the response happens in the context of the @@ -21,7 +21,7 @@ use rustc_middle::ty::{TypeFoldable, TypeFolder, TypeSuperFoldable}; #[derive(Debug, Clone, Copy)] pub enum CanonicalizeMode { Input, - /// FIXME: We currently return region constraints refering to + /// FIXME: We currently return region constraints referring to /// placeholders and inference variables from a binder instantiated /// inside of the query. /// diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 861fa0a305ac..ada868705c7c 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -42,7 +42,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// /// - `var_values`: a map from bound variables in the canonical goal to /// the values inferred while solving the instantiated goal. - /// - `external_constraints`: additional constraints which aren't expressable + /// - `external_constraints`: additional constraints which aren't expressible /// using simple unification of inference variables. #[instrument(level = "debug", skip(self))] pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response( @@ -113,7 +113,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } /// This returns the substitutions to instantiate the bound variables of - /// the canonical reponse. This depends on the `original_values` for the + /// the canonical response. This depends on the `original_values` for the /// bound variables. fn compute_query_response_substitution( &self, diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index 42c28686f5c1..050269fa973e 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -153,7 +153,7 @@ impl<'tcx> SearchGraph<'tcx> { /// coinductive cycles. /// /// When we encounter a coinductive cycle, we have to prove the final result of that cycle - /// while we are still computing that result. Because of this we continously recompute the + /// while we are still computing that result. Because of this we continuously recompute the /// cycle until the result of the previous iteration is equal to the final result, at which /// point we are done. /// diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs b/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs index 574f3e9a5772..e0a2e0c5cc29 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs @@ -45,7 +45,7 @@ impl OverflowData { /// Updating the current limit when hitting overflow. fn deal_with_overflow(&mut self) { // When first hitting overflow we reduce the overflow limit - // for all future goals to prevent hangs if there's an exponental + // for all future goals to prevent hangs if there's an exponential // blowup. self.current_limit.0 = self.default_limit.0 / 8; } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index a794d20d683f..1f5bbc178f7d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -294,7 +294,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } - // Keep this funtion in sync with extract_tupled_inputs_and_output_from_callable + // Keep this function in sync with extract_tupled_inputs_and_output_from_callable // until the old solver (and thus this function) is removed. // Okay to skip binder because what we are inspecting doesn't involve bound regions. @@ -406,7 +406,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } match obligation.self_ty().skip_binder().kind() { - // Fast path to avoid evaluating an obligation that trivally holds. + // Fast path to avoid evaluating an obligation that trivially holds. // There may be more bounds, but these are checked by the regular path. ty::FnPtr(..) => return false, // These may potentially implement `FnPtr` diff --git a/compiler/rustc_ty_utils/messages.ftl b/compiler/rustc_ty_utils/messages.ftl index a1e97bb95bc6..abb0dca17426 100644 --- a/compiler/rustc_ty_utils/messages.ftl +++ b/compiler/rustc_ty_utils/messages.ftl @@ -12,7 +12,7 @@ ty_utils_array_not_supported = array construction is not supported in generic co ty_utils_block_not_supported = blocks are not supported in generic constants -ty_utils_never_to_any_not_supported = converting nevers to any is not supported in generic constants +ty_utils_never_to_any_not_supported = converting never to any is not supported in generic constants ty_utils_tuple_not_supported = tuple construction is not supported in generic constants @@ -54,4 +54,4 @@ ty_utils_multiple_array_fields_simd_type = monomorphising SIMD type `{$ty}` with ty_utils_oversized_simd_type = monomorphising SIMD type `{$ty}` of length greater than {$max_lanes} -ty_utils_non_primative_simd_type = monomorphising SIMD type `{$ty}` with a non-primitive-scalar (integer/float/pointer) element type `{$e_ty}` +ty_utils_non_primitive_simd_type = monomorphising SIMD type `{$ty}` with a non-primitive-scalar (integer/float/pointer) element type `{$e_ty}` diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs index 3db3c98e9e28..3d3fc50e6e59 100644 --- a/compiler/rustc_ty_utils/src/errors.rs +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -95,7 +95,7 @@ pub struct OversizedSimdType<'tcx> { } #[derive(Diagnostic)] -#[diag(ty_utils_non_primative_simd_type)] +#[diag(ty_utils_non_primitive_simd_type)] pub struct NonPrimitiveSimdType<'tcx> { pub ty: Ty<'tcx>, pub e_ty: Ty<'tcx>, diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 63eb34f7d552..63ef1c72417f 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -322,7 +322,7 @@ fn layout_of_uncached<'tcx>( if fi.ty(tcx, substs) != f0_ty { tcx.sess.delay_span_bug( DUMMY_SP, - "#[repr(simd)] was applied to an ADT with hetrogeneous field type", + "#[repr(simd)] was applied to an ADT with heterogeneous field type", ); return Err(LayoutError::Unknown(ty)); } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 8b23fbc75833..a3c98ae007ed 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -83,7 +83,7 @@ pub trait CollectAndApply: Sized { /// Produce a result of type `Self::Output` from `iter`. The result will /// typically be produced by applying `f` on the elements produced by /// `iter`, though this may not happen in some impls, e.g. if an error - /// occured during iteration. + /// occurred during iteration. fn collect_and_apply(iter: I, f: F) -> Self::Output where I: Iterator, diff --git a/tests/ui/methods/method-not-found-generic-arg-elision.stderr b/tests/ui/methods/method-not-found-generic-arg-elision.stderr index f3db56d1d539..ddbaece96d9f 100644 --- a/tests/ui/methods/method-not-found-generic-arg-elision.stderr +++ b/tests/ui/methods/method-not-found-generic-arg-elision.stderr @@ -24,6 +24,8 @@ error[E0599]: no method named `extend` found for struct `Map` in the current sco | LL | v.iter().map(|x| x * x).extend(std::iter::once(100)); | ^^^^^^ method not found in `Map, [closure@method-not-found-generic-arg-elision.rs:87:18]>` + | + = note: the full type name has been written to '$TEST_BUILD_DIR/methods/method-not-found-generic-arg-elision/method-not-found-generic-arg-elision.long-type-15656389337579798043.txt' error[E0599]: no method named `method` found for struct `Wrapper` in the current scope --> $DIR/method-not-found-generic-arg-elision.rs:90:13 diff --git a/tests/ui/proc-macro/derive-bad.rs b/tests/ui/proc-macro/derive-bad.rs index cb5188b5fb43..92d35f5371ab 100644 --- a/tests/ui/proc-macro/derive-bad.rs +++ b/tests/ui/proc-macro/derive-bad.rs @@ -4,7 +4,7 @@ extern crate derive_bad; #[derive(A)] -//~^ ERROR proc-macro derive produced unparseable tokens +//~^ ERROR proc-macro derive produced unparsable tokens //~| ERROR expected `:`, found `}` struct A; //~ ERROR the name `A` is defined multiple times diff --git a/tests/ui/proc-macro/derive-bad.stderr b/tests/ui/proc-macro/derive-bad.stderr index 241f99b28c24..43e97f40ba88 100644 --- a/tests/ui/proc-macro/derive-bad.stderr +++ b/tests/ui/proc-macro/derive-bad.stderr @@ -9,7 +9,7 @@ LL | #[derive(A)] | = note: this error originates in the derive macro `A` (in Nightly builds, run with -Z macro-backtrace for more info) -error: proc-macro derive produced unparseable tokens +error: proc-macro derive produced unparsable tokens --> $DIR/derive-bad.rs:6:10 | LL | #[derive(A)] diff --git a/tests/ui/proc-macro/issue-91800.rs b/tests/ui/proc-macro/issue-91800.rs index 0c1281de4f8c..f48c8bf72d72 100644 --- a/tests/ui/proc-macro/issue-91800.rs +++ b/tests/ui/proc-macro/issue-91800.rs @@ -5,7 +5,7 @@ extern crate issue_91800_macro; #[derive(MyTrait)] //~^ ERROR macros that expand to items must be delimited with braces or followed by a semicolon -//~| ERROR proc-macro derive produced unparseable tokens +//~| ERROR proc-macro derive produced unparsable tokens #[attribute_macro] //~^ ERROR macros that expand to items must be delimited with braces or followed by a semicolon struct MyStruct; diff --git a/tests/ui/proc-macro/issue-91800.stderr b/tests/ui/proc-macro/issue-91800.stderr index 9c356263a36b..d831d62e919d 100644 --- a/tests/ui/proc-macro/issue-91800.stderr +++ b/tests/ui/proc-macro/issue-91800.stderr @@ -6,7 +6,7 @@ LL | #[derive(MyTrait)] | = note: this error originates in the derive macro `MyTrait` (in Nightly builds, run with -Z macro-backtrace for more info) -error: proc-macro derive produced unparseable tokens +error: proc-macro derive produced unparsable tokens --> $DIR/issue-91800.rs:6:10 | LL | #[derive(MyTrait)] From f06640de08c0e66de6bd3ea275ec52b96c3211a3 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Mon, 10 Apr 2023 22:03:08 +0200 Subject: [PATCH 168/272] Update ty_utils_never_to_any_not_supported diagnostic message --- compiler/rustc_ty_utils/messages.ftl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_ty_utils/messages.ftl b/compiler/rustc_ty_utils/messages.ftl index abb0dca17426..15a14112f4a2 100644 --- a/compiler/rustc_ty_utils/messages.ftl +++ b/compiler/rustc_ty_utils/messages.ftl @@ -12,7 +12,7 @@ ty_utils_array_not_supported = array construction is not supported in generic co ty_utils_block_not_supported = blocks are not supported in generic constants -ty_utils_never_to_any_not_supported = converting never to any is not supported in generic constants +ty_utils_never_to_any_not_supported = coercing the `never` type is not supported in generic constants ty_utils_tuple_not_supported = tuple construction is not supported in generic constants From 64f75977764439f500f58ed6f2ac6db4873b250a Mon Sep 17 00:00:00 2001 From: clubby789 Date: Sat, 8 Apr 2023 20:37:41 +0100 Subject: [PATCH 169/272] Migrate most of `rustc_builtin_macros` to diagnostic impls Co-authored-by: Joe ST Co-authored-by: Michael Goulet --- compiler/rustc_builtin_macros/messages.ftl | 146 +++++ .../src/alloc_error_handler.rs | 3 +- compiler/rustc_builtin_macros/src/assert.rs | 28 +- compiler/rustc_builtin_macros/src/cfg.rs | 21 +- .../src/cfg_accessible.rs | 18 +- .../rustc_builtin_macros/src/compile_error.rs | 5 + compiler/rustc_builtin_macros/src/concat.rs | 10 +- .../rustc_builtin_macros/src/concat_bytes.rs | 77 +-- .../rustc_builtin_macros/src/concat_idents.rs | 8 +- compiler/rustc_builtin_macros/src/derive.rs | 40 +- .../src/deriving/default.rs | 124 ++-- .../src/deriving/generic/mod.rs | 6 +- compiler/rustc_builtin_macros/src/env.rs | 30 +- compiler/rustc_builtin_macros/src/errors.rs | 553 ++++++++++++++++++ compiler/rustc_builtin_macros/src/format.rs | 175 +++--- compiler/rustc_builtin_macros/src/lib.rs | 2 + compiler/rustc_errors/src/diagnostic.rs | 1 + compiler/rustc_errors/src/diagnostic_impls.rs | 26 +- compiler/rustc_errors/src/lib.rs | 4 +- .../src/diagnostics/diagnostic_builder.rs | 6 +- .../session-diagnostic/diagnostic-derive.rs | 2 +- .../diagnostic-derive.stderr | 2 +- tests/ui/extenv/extenv-no-args.rs | 2 +- tests/ui/extenv/extenv-no-args.stderr | 2 +- tests/ui/extenv/extenv-too-many-args.rs | 2 +- tests/ui/extenv/extenv-too-many-args.stderr | 2 +- tests/ui/extenv/issue-55897.stderr | 2 +- tests/ui/issues/issue-50403.rs | 2 +- tests/ui/issues/issue-50403.stderr | 2 +- tests/ui/macros/concat-bytes-error.stderr | 8 +- tests/ui/macros/macros-nonfatal-errors.stderr | 18 +- 31 files changed, 978 insertions(+), 349 deletions(-) create mode 100644 compiler/rustc_builtin_macros/src/errors.rs diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 4d088e27b364..83dc1ac50e55 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -3,3 +3,149 @@ builtin_macros_requires_cfg_pattern = .label = cfg-pattern required builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern + +builtin_macros_alloc_error_must_be_fn = alloc_error_handler must be a function + +builtin_macros_assert_requires_boolean = macro requires a boolean expression as an argument + .label = boolean expression required + +builtin_macros_assert_requires_expression = macro requires an expression as an argument + .suggestion = try removing semicolon + +builtin_macros_assert_missing_comma = unexpected string literal + .suggestion = try adding a comma + +builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not specified +builtin_macros_cfg_accessible_multiple_paths = multiple `cfg_accessible` paths are specified +builtin_macros_cfg_accessible_literal_path = `cfg_accessible` path cannot be a literal +builtin_macros_cfg_accessible_has_args = `cfg_accessible` path cannot accept arguments + +builtin_macros_cfg_accessible_indeterminate = cannot determine whether the path is accessible or not + +builtin_macros_concat_bytestr = cannot concatenate a byte string literal + +builtin_macros_concat_missing_literal = expected a literal + .note = only literals (like `"foo"`, `-42` and `3.14`) can be passed to `concat!()` + +builtin_macros_concat_bytes_missing_literal = expected a byte literal + .note = only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` + +builtin_macros_concat_bytes_invalid = cannot concatenate {$lit_kind} literals + .byte_char = try using a byte character + .byte_str = try using a byte string + .number_array = try wrapping the number in an array + +builtin_macros_concat_bytes_oob = numeric literal is out of bounds + +builtin_macros_concat_bytes_non_u8 = numeric literal is not a `u8` + +builtin_macros_concat_bytes_array = cannot concatenate doubly nested array + .note = byte strings are treated as arrays of bytes + .help = try flattening the array + +builtin_macros_concat_bytes_bad_repeat = repeat count is not a positive number + +builtin_macros_concat_idents_missing_args = `concat_idents!()` takes 1 or more arguments +builtin_macros_concat_idents_missing_comma = `concat_idents!()` expecting comma +builtin_macros_concat_idents_ident_args = `concat_idents!()` requires ident args + +builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `enum`s and `union`s + .label = not applicable here + .label2 = not a `struct`, `enum` or `union` + +builtin_macros_unexpected_lit = expected path to a trait, found literal + .label = not a trait + .str_lit = try using `#[derive({$sym})]` + .other = for example, write `#[derive(Debug)]` for `Debug` + +builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept arguments + .suggestion = remove the arguments + +builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values + .suggestion = remove the value + +builtin_macros_derive_macro_call = `derive` cannot be used on items with type macros + +builtin_macros_cannot_derive_union = this trait cannot be derived for unions + +builtin_macros_no_default_variant = no default declared + .help = make a unit variant default by placing `#[default]` above it + .suggestion = make `{$ident}` default + +builtin_macros_multiple_defaults = multiple declared defaults + .label = first default + .additional = additional default + .note = only one variant can be default + .suggestion = make `{$ident}` default + +builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants + .help = consider a manual implementation of `Default` + +builtin_macros_non_exhaustive_default = default variant must be exhaustive + .label = declared `#[non_exhaustive]` here + .help = consider a manual implementation of `Default` + +builtin_macros_multiple_default_attrs = multiple `#[default]` attributes + .note = only one `#[default]` attribute is needed + .label = `#[default]` used here + .label_again = `#[default]` used again here + .help = try removing {$only_one -> + [true] this + *[false] these + } + +builtin_macros_default_arg = `#[default]` attribute does not accept a value + .suggestion = try using `#[default]` + +builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments + +builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time + .cargo = Cargo sets build script variables at run time. Use `std::env::var("{$var}")` instead + .other = use `std::env::var("{$var}")` to read the variable at run time + +builtin_macros_format_requires_string = requires at least a format string argument + +builtin_macros_format_duplicate_arg = duplicate argument named `{$ident}` + .label1 = previously here + .label2 = duplicate argument + +builtin_macros_format_positional_after_named = positional arguments cannot follow named arguments + .label = positional arguments must be before named arguments + .named_args = named argument + +builtin_macros_format_string_invalid = invalid format string: {$desc} + .label = {$label1} in format string + .note = {$note} + .second_label = {$label} + +builtin_macros_sugg = consider using a positional formatting argument instead + +builtin_macros_format_no_arg_named = there is no argument named `{$name}` + .note = did you intend to capture a variable `{$name}` from the surrounding scope? + .note2 = to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro + +builtin_macros_format_unknown_trait = unknown format trait `{$ty}` + .note = the only appropriate formatting traits are: + - ``, which uses the `Display` trait + - `?`, which uses the `Debug` trait + - `e`, which uses the `LowerExp` trait + - `E`, which uses the `UpperExp` trait + - `o`, which uses the `Octal` trait + - `p`, which uses the `Pointer` trait + - `b`, which uses the `Binary` trait + - `x`, which uses the `LowerHex` trait + - `X`, which uses the `UpperHex` trait + .suggestion = use the `{$trait_name}` trait + +builtin_macros_format_unused_arg = {$named -> + [true] named argument + *[false] argument + } never used + +builtin_macros_format_unused_args = multiple unused formatting arguments + .label = multiple missing formatting specifiers + +builtin_macros_format_pos_mismatch = {$n} positional {$n -> + [one] argument + *[more] arguments + } in format string, but {$desc} diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index ac6697232cb8..82bae9157e79 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -1,3 +1,4 @@ +use crate::errors; use crate::util::check_builtin_macro_attribute; use rustc_ast::ptr::P; @@ -31,7 +32,7 @@ pub fn expand( { (item, true, ecx.with_def_site_ctxt(fn_kind.sig.span)) } else { - ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "alloc_error_handler must be a function"); + ecx.sess.parse_sess.span_diagnostic.emit_err(errors::AllocErrorMustBeFn {span: item.span() }); return vec![orig_item]; }; diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 75af5e2b1fad..0de424be2f16 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -1,12 +1,13 @@ mod context; use crate::edition_panic::use_panic_2021; +use crate::errors; use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, MacDelimiter, Path, PathSegment, UnOp}; use rustc_ast_pretty::pprust; -use rustc_errors::{Applicability, PResult}; +use rustc_errors::PResult; use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult}; use rustc_parse::parser::Parser; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -114,9 +115,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes let mut parser = cx.new_parser_from_tts(stream); if parser.token == token::Eof { - let mut err = cx.struct_span_err(sp, "macro requires a boolean expression as an argument"); - err.span_label(sp, "boolean expression required"); - return Err(err); + return Err(cx.create_err(errors::AssertRequiresBoolean { span: sp })); } let cond_expr = parser.parse_expr()?; @@ -129,15 +128,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes // // Emit an error about semicolon and suggest removing it. if parser.token == token::Semi { - let mut err = cx.struct_span_err(sp, "macro requires an expression as an argument"); - err.span_suggestion( - parser.token.span, - "try removing semicolon", - "", - Applicability::MaybeIncorrect, - ); - err.emit(); - + cx.emit_err(errors::AssertRequiresExpression { span: sp, token: parser.token.span }); parser.bump(); } @@ -149,15 +140,8 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes // Emit an error and suggest inserting a comma. let custom_message = if let token::Literal(token::Lit { kind: token::Str, .. }) = parser.token.kind { - let mut err = cx.struct_span_err(parser.token.span, "unexpected string literal"); - let comma_span = parser.prev_token.span.shrink_to_hi(); - err.span_suggestion_short( - comma_span, - "try adding a comma", - ", ", - Applicability::MaybeIncorrect, - ); - err.emit(); + let comma = parser.prev_token.span.shrink_to_hi(); + cx.emit_err(errors::AssertMissingComma { span: parser.token.span, comma }); parse_custom_message(&mut parser) } else if parser.eat(&token::Comma) { diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 5638c2f6180c..1397cee7af83 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -2,13 +2,13 @@ //! a literal `true` or `false` based on whether the given cfg matches the //! current compilation environment. +use crate::errors; use rustc_ast as ast; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_attr as attr; use rustc_errors::PResult; use rustc_expand::base::{self, *}; -use rustc_macros::Diagnostic; use rustc_span::Span; pub fn expand_cfg( @@ -35,26 +35,11 @@ pub fn expand_cfg( } } -#[derive(Diagnostic)] -#[diag(builtin_macros_requires_cfg_pattern)] -struct RequiresCfgPattern { - #[primary_span] - #[label] - span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_expected_one_cfg_pattern)] -struct OneCfgPattern { - #[primary_span] - span: Span, -} - fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> { let mut p = cx.new_parser_from_tts(tts); if p.token == token::Eof { - return Err(cx.create_err(RequiresCfgPattern { span })); + return Err(cx.create_err(errors::RequiresCfgPattern { span })); } let cfg = p.parse_meta_item()?; @@ -62,7 +47,7 @@ fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult< let _ = p.eat(&token::Comma); if !p.eat(&token::Eof) { - return Err(cx.create_err(OneCfgPattern { span })); + return Err(cx.create_err(errors::OneCfgPattern { span })); } Ok(cfg) diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs index 4e4cafc71823..37ac09ccdff4 100644 --- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs +++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs @@ -1,5 +1,6 @@ //! Implementation of the `#[cfg_accessible(path)]` attribute macro. +use crate::errors; use rustc_ast as ast; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; use rustc_feature::AttributeTemplate; @@ -10,15 +11,22 @@ use rustc_span::Span; pub(crate) struct Expander; fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> { + use errors::CfgAccessibleInvalid::*; match mi.meta_item_list() { None => {} - Some([]) => ecx.span_err(mi.span, "`cfg_accessible` path is not specified"), - Some([_, .., l]) => ecx.span_err(l.span(), "multiple `cfg_accessible` paths are specified"), + Some([]) => { + ecx.emit_err(UnspecifiedPath(mi.span)); + } + Some([_, .., l]) => { + ecx.emit_err(MultiplePaths(l.span())); + } Some([nmi]) => match nmi.meta_item() { - None => ecx.span_err(nmi.span(), "`cfg_accessible` path cannot be a literal"), + None => { + ecx.emit_err(LiteralPath(nmi.span())); + } Some(mi) => { if !mi.is_word() { - ecx.span_err(mi.span, "`cfg_accessible` path cannot accept arguments"); + ecx.emit_err(HasArguments(mi.span)); } return Some(&mi.path); } @@ -53,7 +61,7 @@ impl MultiItemModifier for Expander { Ok(true) => ExpandResult::Ready(vec![item]), Ok(false) => ExpandResult::Ready(Vec::new()), Err(Indeterminate) if ecx.force_mode => { - ecx.span_err(span, "cannot determine whether the path is accessible or not"); + ecx.emit_err(errors::CfgAccessibleIndeterminate { span }); ExpandResult::Ready(vec![item]) } Err(Indeterminate) => ExpandResult::Retry(item), diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs index 72397aa2500f..aeb3bb80045b 100644 --- a/compiler/rustc_builtin_macros/src/compile_error.rs +++ b/compiler/rustc_builtin_macros/src/compile_error.rs @@ -13,6 +13,11 @@ pub fn expand_compile_error<'cx>( return DummyResult::any(sp); }; + #[expect( + rustc::diagnostic_outside_of_impl, + reason = "diagnostic message is specified by user" + )] + #[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")] cx.span_err(sp, var.as_str()); DummyResult::any(sp) diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index 36682bbe0708..b92964d03e9f 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -4,6 +4,8 @@ use rustc_expand::base::{self, DummyResult}; use rustc_session::errors::report_lit_error; use rustc_span::symbol::Symbol; +use crate::errors; + pub fn expand_concat( cx: &mut base::ExtCtxt<'_>, sp: rustc_span::Span, @@ -31,7 +33,7 @@ pub fn expand_concat( accumulator.push_str(&b.to_string()); } Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => { - cx.span_err(e.span, "cannot concatenate a byte string literal"); + cx.emit_err(errors::ConcatBytestr { span: e.span }); has_errors = true; } Ok(ast::LitKind::Err) => { @@ -55,7 +57,7 @@ pub fn expand_concat( } } ast::ExprKind::IncludedBytes(..) => { - cx.span_err(e.span, "cannot concatenate a byte string literal") + cx.emit_err(errors::ConcatBytestr { span: e.span }); } ast::ExprKind::Err => { has_errors = true; @@ -67,9 +69,7 @@ pub fn expand_concat( } if !missing_literal.is_empty() { - let mut err = cx.struct_span_err(missing_literal, "expected a literal"); - err.note("only literals (like `\"foo\"`, `-42` and `3.14`) can be passed to `concat!()`"); - err.emit(); + cx.emit_err(errors::ConcatMissingLiteral { spans: missing_literal }); return DummyResult::any(sp); } else if has_errors { return DummyResult::any(sp); diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 4f1a7d709ff8..ba639c0a9fe3 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -1,10 +1,11 @@ use rustc_ast as ast; use rustc_ast::{ptr::P, tokenstream::TokenStream}; -use rustc_errors::Applicability; use rustc_expand::base::{self, DummyResult}; use rustc_session::errors::report_lit_error; use rustc_span::Span; +use crate::errors; + /// Emits errors for literal expressions that are invalid inside and outside of an array. fn invalid_type_err( cx: &mut base::ExtCtxt<'_>, @@ -12,62 +13,46 @@ fn invalid_type_err( span: Span, is_nested: bool, ) { + use errors::{ + ConcatBytesInvalid, ConcatBytesInvalidSuggestion, ConcatBytesNonU8, ConcatBytesOob, + }; + let snippet = cx.sess.source_map().span_to_snippet(span).ok(); match ast::LitKind::from_token_lit(token_lit) { Ok(ast::LitKind::Char(_)) => { - let mut err = cx.struct_span_err(span, "cannot concatenate character literals"); - if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) { - err.span_suggestion( - span, - "try using a byte character", - format!("b{}", snippet), - Applicability::MachineApplicable, - ) - .emit(); - } + let sugg = + snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet }); + cx.sess.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg }); } Ok(ast::LitKind::Str(_, _)) => { - let mut err = cx.struct_span_err(span, "cannot concatenate string literals"); // suggestion would be invalid if we are nested - if !is_nested { - if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) { - err.span_suggestion( - span, - "try using a byte string", - format!("b{}", snippet), - Applicability::MachineApplicable, - ); - } - } - err.emit(); + let sugg = if !is_nested { + snippet.map(|snippet| ConcatBytesInvalidSuggestion::StrLit { span, snippet }) + } else { + None + }; + cx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg }); } Ok(ast::LitKind::Float(_, _)) => { - cx.span_err(span, "cannot concatenate float literals"); + cx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None }); } Ok(ast::LitKind::Bool(_)) => { - cx.span_err(span, "cannot concatenate boolean literals"); + cx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None }); } Ok(ast::LitKind::Err) => {} Ok(ast::LitKind::Int(_, _)) if !is_nested => { - let mut err = cx.struct_span_err(span, "cannot concatenate numeric literals"); - if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) { - err.span_suggestion( - span, - "try wrapping the number in an array", - format!("[{}]", snippet), - Applicability::MachineApplicable, - ); - } - err.emit(); + let sugg = + snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span: span, snippet }); + cx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg }); } Ok(ast::LitKind::Int( val, ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), )) => { assert!(val > u8::MAX.into()); // must be an error - cx.span_err(span, "numeric literal is out of bounds"); + cx.emit_err(ConcatBytesOob { span }); } Ok(ast::LitKind::Int(_, _)) => { - cx.span_err(span, "numeric literal is not a `u8`"); + cx.emit_err(ConcatBytesNonU8 { span }); } Ok(ast::LitKind::ByteStr(..) | ast::LitKind::Byte(_)) => unreachable!(), Err(err) => { @@ -85,7 +70,7 @@ fn handle_array_element( match expr.kind { ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => { if !*has_errors { - cx.span_err(expr.span, "cannot concatenate doubly nested array"); + cx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }); } *has_errors = true; None @@ -99,10 +84,7 @@ fn handle_array_element( Ok(ast::LitKind::Byte(val)) => Some(val), Ok(ast::LitKind::ByteStr(..)) => { if !*has_errors { - cx.struct_span_err(expr.span, "cannot concatenate doubly nested array") - .note("byte strings are treated as arrays of bytes") - .help("try flattening the array") - .emit(); + cx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true }); } *has_errors = true; None @@ -117,10 +99,7 @@ fn handle_array_element( }, ast::ExprKind::IncludedBytes(..) => { if !*has_errors { - cx.struct_span_err(expr.span, "cannot concatenate doubly nested array") - .note("byte strings are treated as arrays of bytes") - .help("try flattening the array") - .emit(); + cx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }); } *has_errors = true; None @@ -167,7 +146,7 @@ pub fn expand_concat_bytes( } } } else { - cx.span_err(count.value.span, "repeat count is not a positive number"); + cx.emit_err(errors::ConcatBytesBadRepeat {span: count.value.span }); } } &ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { @@ -196,9 +175,7 @@ pub fn expand_concat_bytes( } } if !missing_literals.is_empty() { - let mut err = cx.struct_span_err(missing_literals, "expected a byte literal"); - err.note("only byte literals (like `b\"foo\"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`"); - err.emit(); + cx.emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals }); return base::MacEager::expr(DummyResult::raw_expr(sp, true)); } else if has_errors { return base::MacEager::expr(DummyResult::raw_expr(sp, true)); diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs index 297c604e0204..8c737f043237 100644 --- a/compiler/rustc_builtin_macros/src/concat_idents.rs +++ b/compiler/rustc_builtin_macros/src/concat_idents.rs @@ -6,13 +6,15 @@ use rustc_expand::base::{self, *}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; +use crate::errors; + pub fn expand_concat_idents<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, ) -> Box { if tts.is_empty() { - cx.span_err(sp, "concat_idents! takes 1 or more arguments"); + cx.emit_err(errors::ConcatIdentsMissingArgs { span: sp }); return DummyResult::any(sp); } @@ -22,7 +24,7 @@ pub fn expand_concat_idents<'cx>( match e { TokenTree::Token(Token { kind: token::Comma, .. }, _) => {} _ => { - cx.span_err(sp, "concat_idents! expecting comma"); + cx.emit_err(errors::ConcatIdentsMissingComma { span: sp }); return DummyResult::any(sp); } } @@ -34,7 +36,7 @@ pub fn expand_concat_idents<'cx>( } } - cx.span_err(sp, "concat_idents! requires ident args"); + cx.emit_err(errors::ConcatIdentsIdentArgs { span: sp }); return DummyResult::any(sp); } } diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 2a8dc02849ea..fe4483104eeb 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -1,8 +1,8 @@ use crate::cfg_eval::cfg_eval; +use crate::errors; use rustc_ast as ast; use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; -use rustc_errors::{struct_span_err, Applicability}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; use rustc_feature::AttributeTemplate; use rustc_parse::validate_attr; @@ -116,49 +116,33 @@ fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool { let bad_target = !matches!(item_kind, Some(ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..))); if bad_target { - struct_span_err!( - sess, - span, - E0774, - "`derive` may only be applied to `struct`s, `enum`s and `union`s", - ) - .span_label(span, "not applicable here") - .span_label(item.span(), "not a `struct`, `enum` or `union`") - .emit(); + sess.emit_err(errors::BadDeriveTarget { span, item: item.span() }); } bad_target } fn report_unexpected_meta_item_lit(sess: &Session, lit: &ast::MetaItemLit) { - let help_msg = match lit.kind { + let help = match lit.kind { ast::LitKind::Str(_, ast::StrStyle::Cooked) if rustc_lexer::is_ident(lit.symbol.as_str()) => { - format!("try using `#[derive({})]`", lit.symbol) + errors::BadDeriveLitHelp::StrLit { sym: lit.symbol } } - _ => "for example, write `#[derive(Debug)]` for `Debug`".to_string(), + _ => errors::BadDeriveLitHelp::Other, }; - struct_span_err!(sess, lit.span, E0777, "expected path to a trait, found literal",) - .span_label(lit.span, "not a trait") - .help(&help_msg) - .emit(); + sess.emit_err(errors::BadDeriveLit { span: lit.span, help }); } fn report_path_args(sess: &Session, meta: &ast::MetaItem) { - let report_error = |title, action| { - let span = meta.span.with_lo(meta.path.span.hi()); - sess.struct_span_err(span, title) - .span_suggestion(span, action, "", Applicability::MachineApplicable) - .emit(); - }; + let span = meta.span.with_lo(meta.path.span.hi()); + match meta.kind { MetaItemKind::Word => {} - MetaItemKind::List(..) => report_error( - "traits in `#[derive(...)]` don't accept arguments", - "remove the arguments", - ), + MetaItemKind::List(..) => { + sess.emit_err(errors::DerivePathArgsList { span }); + } MetaItemKind::NameValue(..) => { - report_error("traits in `#[derive(...)]` don't accept values", "remove the value") + sess.emit_err(errors::DerivePathArgsValue { span }); } } } diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index cc32739d083c..33fe98b40e15 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -1,8 +1,8 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; +use crate::errors; use rustc_ast as ast; use rustc_ast::{attr, walk_list, EnumDef, VariantData}; -use rustc_errors::Applicability; use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; use rustc_span::symbol::Ident; use rustc_span::symbol::{kw, sym}; @@ -118,67 +118,50 @@ fn extract_default_variant<'a>( .filter(|variant| matches!(variant.data, VariantData::Unit(..))) .filter(|variant| !attr::contains_name(&variant.attrs, sym::non_exhaustive)); - let mut diag = cx.struct_span_err(trait_span, "no default declared"); - diag.help("make a unit variant default by placing `#[default]` above it"); - for variant in possible_defaults { - // Suggest making each unit variant default. - diag.tool_only_span_suggestion( - variant.span, - &format!("make `{}` default", variant.ident), - format!("#[default] {}", variant.ident), - Applicability::MaybeIncorrect, - ); - } - diag.emit(); + let suggs = possible_defaults + .map(|v| errors::NoDefaultVariantSugg { span: v.span, ident: v.ident }) + .collect(); + cx.emit_err(errors::NoDefaultVariant { span: trait_span, suggs }); return Err(()); } [first, rest @ ..] => { - let mut diag = cx.struct_span_err(trait_span, "multiple declared defaults"); - diag.span_label(first.span, "first default"); - diag.span_labels(rest.iter().map(|variant| variant.span), "additional default"); - diag.note("only one variant can be default"); - for variant in &default_variants { - // Suggest making each variant already tagged default. - let suggestion = default_variants - .iter() - .filter_map(|v| { - if v.span == variant.span { - None - } else { - Some((attr::find_by_name(&v.attrs, kw::Default)?.span, String::new())) - } - }) - .collect(); - - diag.tool_only_multipart_suggestion( - &format!("make `{}` default", variant.ident), - suggestion, - Applicability::MaybeIncorrect, - ); - } - diag.emit(); - + let suggs = default_variants + .iter() + .map(|variant| { + let spans = default_variants + .iter() + .filter_map(|v| { + if v.span == variant.span { + None + } else { + Some(attr::find_by_name(&v.attrs, kw::Default)?.span) + } + }) + .collect(); + errors::MultipleDefaultsSugg { spans, ident: variant.ident } + }) + .collect(); + cx.emit_err(errors::MultipleDefaults { + span: trait_span, + first: first.span, + additional: rest.iter().map(|v| v.span).collect(), + suggs, + }); return Err(()); } }; if !matches!(variant.data, VariantData::Unit(..)) { - cx.struct_span_err( - variant.ident.span, - "the `#[default]` attribute may only be used on unit enum variants", - ) - .help("consider a manual implementation of `Default`") - .emit(); - + cx.emit_err(errors::NonUnitDefault { span: variant.ident.span }); return Err(()); } if let Some(non_exhaustive_attr) = attr::find_by_name(&variant.attrs, sym::non_exhaustive) { - cx.struct_span_err(variant.ident.span, "default variant must be exhaustive") - .span_label(non_exhaustive_attr.span, "declared `#[non_exhaustive]` here") - .help("consider a manual implementation of `Default`") - .emit(); + cx.emit_err(errors::NonExhaustiveDefault { + span: variant.ident.span, + non_exhaustive: non_exhaustive_attr.span, + }); return Err(()); } @@ -199,35 +182,23 @@ fn validate_default_attribute( "this method must only be called with a variant that has a `#[default]` attribute", ), [first, rest @ ..] => { - let suggestion_text = - if rest.len() == 1 { "try removing this" } else { "try removing these" }; - - cx.struct_span_err(default_variant.ident.span, "multiple `#[default]` attributes") - .note("only one `#[default]` attribute is needed") - .span_label(first.span, "`#[default]` used here") - .span_label(rest[0].span, "`#[default]` used again here") - .span_help(rest.iter().map(|attr| attr.span).collect::>(), suggestion_text) - // This would otherwise display the empty replacement, hence the otherwise - // repetitive `.span_help` call above. - .tool_only_multipart_suggestion( - suggestion_text, - rest.iter().map(|attr| (attr.span, String::new())).collect(), - Applicability::MachineApplicable, - ) - .emit(); + let sugg = errors::MultipleDefaultAttrsSugg { + spans: rest.iter().map(|attr| attr.span).collect(), + }; + cx.emit_err(errors::MultipleDefaultAttrs { + span: default_variant.ident.span, + first: first.span, + first_rest: rest[0].span, + rest: rest.iter().map(|attr| attr.span).collect::>().into(), + only_one: rest.len() == 1, + sugg, + }); return Err(()); } }; if !attr.is_word() { - cx.struct_span_err(attr.span, "`#[default]` attribute does not accept a value") - .span_suggestion_hidden( - attr.span, - "try using `#[default]`", - "#[default]", - Applicability::MaybeIncorrect, - ) - .emit(); + cx.emit_err(errors::DefaultHasArg { span: attr.span }); return Err(()); } @@ -241,12 +212,7 @@ struct DetectNonVariantDefaultAttr<'a, 'b> { impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, 'b> { fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) { if attr.has_name(kw::Default) { - self.cx - .struct_span_err( - attr.span, - "the `#[default]` attribute may only be used on unit enum variants", - ) - .emit(); + self.cx.emit_err(errors::NonUnitDefault { span: attr.span }); } rustc_ast::visit::walk_attribute(self, attr); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 6b3053fdfac7..e5a003315884 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -162,7 +162,7 @@ pub use StaticFields::*; pub use SubstructureFields::*; -use crate::deriving; +use crate::{deriving, errors}; use rustc_ast::ptr::P; use rustc_ast::{ self as ast, BindingAnnotation, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics, @@ -415,7 +415,7 @@ fn find_type_parameters( } fn visit_mac_call(&mut self, mac: &ast::MacCall) { - self.cx.span_err(mac.span(), "`derive` cannot be used on items with type macros"); + self.cx.emit_err(errors::DeriveMacroCall { span: mac.span() }); } } @@ -488,7 +488,7 @@ impl<'a> TraitDef<'a> { is_packed, ) } else { - cx.span_err(mitem.span, "this trait cannot be derived for unions"); + cx.emit_err(errors::DeriveUnion { span: mitem.span }); return; } } diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index f011cb754cb4..58c972738c49 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -11,6 +11,8 @@ use rustc_span::Span; use std::env; use thin_vec::thin_vec; +use crate::errors; + pub fn expand_option_env<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, @@ -54,7 +56,7 @@ pub fn expand_env<'cx>( ) -> Box { let mut exprs = match get_exprs_from_tts(cx, tts) { Some(exprs) if exprs.is_empty() || exprs.len() > 2 => { - cx.span_err(sp, "env! takes 1 or 2 arguments"); + cx.emit_err(errors::EnvTakesArgs { span: sp }); return DummyResult::any(sp); } None => return DummyResult::any(sp), @@ -78,18 +80,12 @@ pub fn expand_env<'cx>( cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value)); let e = match value { None => { - let (msg, help) = match custom_msg { - None => ( - format!("environment variable `{var}` not defined at compile time"), - Some(help_for_missing_env_var(var.as_str())), - ), - Some(s) => (s.to_string(), None), - }; - let mut diag = cx.struct_span_err(sp, &msg); - if let Some(help) = help { - diag.help(help); - } - diag.emit(); + cx.emit_err(errors::EnvNotDefined { + span: sp, + msg: custom_msg, + var, + help: custom_msg.is_none().then(|| help_for_missing_env_var(var.as_str())), + }); return DummyResult::any(sp); } Some(value) => cx.expr_str(sp, value), @@ -97,15 +93,13 @@ pub fn expand_env<'cx>( MacEager::expr(e) } -fn help_for_missing_env_var(var: &str) -> String { +fn help_for_missing_env_var(var: &str) -> errors::EnvNotDefinedHelp { if var.starts_with("CARGO_") || var.starts_with("DEP_") || matches!(var, "OUT_DIR" | "OPT_LEVEL" | "PROFILE" | "HOST" | "TARGET") { - format!( - "Cargo sets build script variables at run time. Use `std::env::var(\"{var}\")` instead" - ) + errors::EnvNotDefinedHelp::CargoVar } else { - format!("Use `std::env::var(\"{var}\")` to read the variable at run time") + errors::EnvNotDefinedHelp::Other } } diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs new file mode 100644 index 000000000000..630f9b87bc3e --- /dev/null +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -0,0 +1,553 @@ +use rustc_errors::{ + AddToDiagnostic, EmissionGuarantee, IntoDiagnostic, MultiSpan, SingleLabelManySpans, +}; +use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_span::{symbol::Ident, Span, Symbol}; + +#[derive(Diagnostic)] +#[diag(builtin_macros_requires_cfg_pattern)] +pub(crate) struct RequiresCfgPattern { + #[primary_span] + #[label] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_expected_one_cfg_pattern)] +pub(crate) struct OneCfgPattern { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_alloc_error_must_be_fn)] +pub(crate) struct AllocErrorMustBeFn { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_assert_requires_boolean)] +pub(crate) struct AssertRequiresBoolean { + #[primary_span] + #[label] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_assert_requires_expression)] +pub(crate) struct AssertRequiresExpression { + #[primary_span] + pub(crate) span: Span, + #[suggestion(code = "", applicability = "maybe-incorrect")] + pub(crate) token: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_assert_missing_comma)] +pub(crate) struct AssertMissingComma { + #[primary_span] + pub(crate) span: Span, + #[suggestion(code = ", ", applicability = "maybe-incorrect", style = "short")] + pub(crate) comma: Span, +} + +#[derive(Diagnostic)] +pub(crate) enum CfgAccessibleInvalid { + #[diag(builtin_macros_cfg_accessible_unspecified_path)] + UnspecifiedPath(#[primary_span] Span), + #[diag(builtin_macros_cfg_accessible_multiple_paths)] + MultiplePaths(#[primary_span] Span), + #[diag(builtin_macros_cfg_accessible_literal_path)] + LiteralPath(#[primary_span] Span), + #[diag(builtin_macros_cfg_accessible_has_args)] + HasArguments(#[primary_span] Span), +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_cfg_accessible_indeterminate)] +pub(crate) struct CfgAccessibleIndeterminate { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_missing_literal)] +#[note] +pub(crate) struct ConcatMissingLiteral { + #[primary_span] + pub(crate) spans: Vec, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_bytestr)] +pub(crate) struct ConcatBytestr { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_bytes_invalid)] +pub(crate) struct ConcatBytesInvalid { + #[primary_span] + pub(crate) span: Span, + pub(crate) lit_kind: &'static str, + #[subdiagnostic] + pub(crate) sugg: Option, +} + +#[derive(Subdiagnostic)] +pub(crate) enum ConcatBytesInvalidSuggestion { + #[suggestion( + builtin_macros_byte_char, + code = "b{snippet}", + applicability = "machine-applicable" + )] + CharLit { + #[primary_span] + span: Span, + snippet: String, + }, + #[suggestion( + builtin_macros_byte_str, + code = "b{snippet}", + applicability = "machine-applicable" + )] + StrLit { + #[primary_span] + span: Span, + snippet: String, + }, + #[suggestion( + builtin_macros_number_array, + code = "[{snippet}]", + applicability = "machine-applicable" + )] + IntLit { + #[primary_span] + span: Span, + snippet: String, + }, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_bytes_oob)] +pub(crate) struct ConcatBytesOob { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_bytes_non_u8)] +pub(crate) struct ConcatBytesNonU8 { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_bytes_missing_literal)] +#[note] +pub(crate) struct ConcatBytesMissingLiteral { + #[primary_span] + pub(crate) spans: Vec, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_bytes_array)] +pub(crate) struct ConcatBytesArray { + #[primary_span] + pub(crate) span: Span, + #[note] + #[help] + pub(crate) bytestr: bool, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_bytes_bad_repeat)] +pub(crate) struct ConcatBytesBadRepeat { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_idents_missing_args)] +pub(crate) struct ConcatIdentsMissingArgs { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_idents_missing_comma)] +pub(crate) struct ConcatIdentsMissingComma { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_idents_ident_args)] +pub(crate) struct ConcatIdentsIdentArgs { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_bad_derive_target, code = "E0774")] +pub(crate) struct BadDeriveTarget { + #[primary_span] + #[label] + pub(crate) span: Span, + #[label(builtin_macros_label2)] + pub(crate) item: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_unexpected_lit, code = "E0777")] +pub(crate) struct BadDeriveLit { + #[primary_span] + #[label] + pub(crate) span: Span, + #[subdiagnostic] + pub help: BadDeriveLitHelp, +} + +#[derive(Subdiagnostic)] +pub(crate) enum BadDeriveLitHelp { + #[help(builtin_macros_str_lit)] + StrLit { sym: Symbol }, + #[help(builtin_macros_other)] + Other, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_derive_path_args_list)] +pub(crate) struct DerivePathArgsList { + #[suggestion(code = "", applicability = "machine-applicable")] + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_derive_path_args_value)] +pub(crate) struct DerivePathArgsValue { + #[suggestion(code = "", applicability = "machine-applicable")] + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_no_default_variant)] +#[help] +pub(crate) struct NoDefaultVariant { + #[primary_span] + pub(crate) span: Span, + #[subdiagnostic] + pub(crate) suggs: Vec, +} + +#[derive(Subdiagnostic)] +#[suggestion( + builtin_macros_suggestion, + code = "#[default] {ident}", + applicability = "maybe-incorrect", + style = "tool-only" +)] +pub(crate) struct NoDefaultVariantSugg { + #[primary_span] + pub(crate) span: Span, + pub(crate) ident: Ident, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_multiple_defaults)] +#[note] +pub(crate) struct MultipleDefaults { + #[primary_span] + pub(crate) span: Span, + #[label] + pub(crate) first: Span, + #[label(builtin_macros_additional)] + pub additional: Vec, + #[subdiagnostic] + pub suggs: Vec, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + builtin_macros_suggestion, + applicability = "maybe-incorrect", + style = "tool-only" +)] +pub(crate) struct MultipleDefaultsSugg { + #[suggestion_part(code = "")] + pub(crate) spans: Vec, + pub(crate) ident: Ident, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_non_unit_default)] +#[help] +pub(crate) struct NonUnitDefault { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_non_exhaustive_default)] +#[help] +pub(crate) struct NonExhaustiveDefault { + #[primary_span] + pub(crate) span: Span, + #[label] + pub(crate) non_exhaustive: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_multiple_default_attrs)] +#[note] +pub(crate) struct MultipleDefaultAttrs { + #[primary_span] + pub(crate) span: Span, + #[label] + pub(crate) first: Span, + #[label(builtin_macros_label_again)] + pub(crate) first_rest: Span, + #[help] + pub(crate) rest: MultiSpan, + pub(crate) only_one: bool, + #[subdiagnostic] + pub(crate) sugg: MultipleDefaultAttrsSugg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + builtin_macros_help, + applicability = "machine-applicable", + style = "tool-only" +)] +pub(crate) struct MultipleDefaultAttrsSugg { + #[suggestion_part(code = "")] + pub(crate) spans: Vec, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_default_arg)] +pub(crate) struct DefaultHasArg { + #[primary_span] + #[suggestion(code = "#[default]", style = "hidden", applicability = "maybe-incorrect")] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_derive_macro_call)] +pub(crate) struct DeriveMacroCall { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_cannot_derive_union)] +pub(crate) struct DeriveUnion { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_env_takes_args)] +pub(crate) struct EnvTakesArgs { + #[primary_span] + pub(crate) span: Span, +} + +//#[derive(Diagnostic)] +//#[diag(builtin_macros_env_not_defined)] +pub(crate) struct EnvNotDefined { + pub(crate) span: Span, + pub(crate) msg: Option, + pub(crate) var: Symbol, + pub(crate) help: Option, +} + +// Hand-written implementation to support custom user messages +impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefined { + #[track_caller] + fn into_diagnostic( + self, + handler: &'a rustc_errors::Handler, + ) -> rustc_errors::DiagnosticBuilder<'a, G> { + let mut diag = if let Some(msg) = self.msg { + handler.struct_diagnostic(msg.as_str()) + } else { + handler.struct_diagnostic(crate::fluent_generated::builtin_macros_env_not_defined) + }; + diag.set_arg("var", self.var); + diag.set_span(self.span); + if let Some(help) = self.help { + diag.subdiagnostic(help); + } + diag + } +} + +#[derive(Subdiagnostic)] +pub(crate) enum EnvNotDefinedHelp { + #[help(builtin_macros_cargo)] + CargoVar, + #[help(builtin_macros_other)] + Other, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_format_requires_string)] +pub(crate) struct FormatRequiresString { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_format_duplicate_arg)] +pub(crate) struct FormatDuplicateArg { + #[primary_span] + pub(crate) span: Span, + #[label(builtin_macros_label1)] + pub(crate) prev: Span, + #[label(builtin_macros_label2)] + pub(crate) duplicate: Span, + pub(crate) ident: Ident, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_format_positional_after_named)] +pub(crate) struct PositionalAfterNamed { + #[primary_span] + #[label] + pub(crate) span: Span, + #[label(builtin_macros_named_args)] + pub(crate) args: Vec, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_format_string_invalid)] +pub(crate) struct InvalidFormatString { + #[primary_span] + #[label] + pub(crate) span: Span, + pub(crate) desc: String, + pub(crate) label1: String, + #[subdiagnostic] + pub(crate) note_: Option, + #[subdiagnostic] + pub(crate) label_: Option, + #[subdiagnostic] + pub(crate) sugg_: Option, +} + +#[derive(Subdiagnostic)] +#[note(builtin_macros_note)] +pub(crate) struct InvalidFormatStringNote { + pub(crate) note: String, +} + +#[derive(Subdiagnostic)] +#[label(builtin_macros_second_label)] +pub(crate) struct InvalidFormatStringLabel { + #[primary_span] + pub(crate) span: Span, + pub(crate) label: String, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + builtin_macros_sugg, + style = "verbose", + applicability = "machine-applicable" +)] +pub(crate) struct InvalidFormatStringSuggestion { + #[suggestion_part(code = "{len}")] + pub(crate) captured: Span, + pub(crate) len: String, + #[suggestion_part(code = ", {arg}")] + pub(crate) span: Span, + pub(crate) arg: String, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_format_no_arg_named)] +#[note] +#[note(builtin_macros_note2)] +pub(crate) struct FormatNoArgNamed { + #[primary_span] + pub(crate) span: Span, + pub(crate) name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_format_unknown_trait)] +#[note] +pub(crate) struct FormatUnknownTrait<'a> { + #[primary_span] + pub(crate) span: Span, + pub(crate) ty: &'a str, + #[subdiagnostic] + pub(crate) suggs: Vec, +} + +#[derive(Subdiagnostic)] +#[suggestion( + builtin_macros_suggestion, + code = "{fmt}", + style = "tool-only", + applicability = "maybe-incorrect" +)] +pub struct FormatUnknownTraitSugg { + #[primary_span] + pub span: Span, + pub fmt: &'static str, + pub trait_name: &'static str, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_format_unused_arg)] +pub(crate) struct FormatUnusedArg { + #[primary_span] + #[label(builtin_macros_format_unused_arg)] + pub(crate) span: Span, + pub(crate) named: bool, +} + +// Allow the singular form to be a subdiagnostic of the multiple-unused +// form of diagnostic. +impl AddToDiagnostic for FormatUnusedArg { + fn add_to_diagnostic_with(self, diag: &mut rustc_errors::Diagnostic, f: F) + where + F: Fn( + &mut rustc_errors::Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + diag.set_arg("named", self.named); + let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into()); + diag.span_label(self.span, msg); + } +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_format_unused_args)] +pub(crate) struct FormatUnusedArgs { + #[primary_span] + pub(crate) unused: Vec, + #[label] + pub(crate) fmt: Span, + #[subdiagnostic] + pub(crate) unused_labels: Vec, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_format_pos_mismatch)] +pub(crate) struct FormatPositionalMismatch { + #[primary_span] + pub(crate) span: MultiSpan, + pub(crate) n: usize, + pub(crate) desc: String, + #[subdiagnostic] + pub(crate) highlight: SingleLabelManySpans, +} diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index db2ef7fba4b8..435a07d8ce7a 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -7,7 +7,7 @@ use rustc_ast::{ FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait, }; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{pluralize, Applicability, MultiSpan, PResult}; +use rustc_errors::{Applicability, MultiSpan, PResult, SingleLabelManySpans}; use rustc_expand::base::{self, *}; use rustc_parse_format as parse; use rustc_span::symbol::{Ident, Symbol}; @@ -36,6 +36,8 @@ enum PositionUsedAs { } use PositionUsedAs::*; +use crate::errors; + struct MacroInput { fmtstr: P, args: FormatArguments, @@ -66,7 +68,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult< let mut p = ecx.new_parser_from_tts(tts); if p.token == token::Eof { - return Err(ecx.struct_span_err(sp, "requires at least a format string argument")); + return Err(ecx.create_err(errors::FormatRequiresString { span: sp })); } let first_token = &p.token; @@ -121,13 +123,12 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult< p.expect(&token::Eq)?; let expr = p.parse_expr()?; if let Some((_, prev)) = args.by_name(ident.name) { - ecx.struct_span_err( - ident.span, - &format!("duplicate argument named `{}`", ident), - ) - .span_label(prev.kind.ident().unwrap().span, "previously here") - .span_label(ident.span, "duplicate argument") - .emit(); + ecx.emit_err(errors::FormatDuplicateArg { + span: ident.span, + prev: prev.kind.ident().unwrap().span, + duplicate: ident.span, + ident, + }); continue; } args.add(FormatArgument { kind: FormatArgumentKind::Named(ident), expr }); @@ -135,20 +136,21 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult< _ => { let expr = p.parse_expr()?; if !args.named_args().is_empty() { - let mut err = ecx.struct_span_err( - expr.span, - "positional arguments cannot follow named arguments", - ); - err.span_label( - expr.span, - "positional arguments must be before named arguments", - ); - for arg in args.named_args() { - if let Some(name) = arg.kind.ident() { - err.span_label(name.span.to(arg.expr.span), "named argument"); - } - } - err.emit(); + ecx.emit_err(errors::PositionalAfterNamed { + span: expr.span, + args: args + .named_args() + .iter() + .filter_map(|a| { + if let Some(ident) = a.kind.ident() { + Some((a, ident)) + } else { + None + } + }) + .map(|(arg, n)| n.span.to(arg.expr.span)) + .collect(), + }); } args.add(FormatArgument { kind: FormatArgumentKind::Normal, expr }); } @@ -234,13 +236,19 @@ fn make_format_args( // argument span here. fmt_span }; - let mut e = ecx.struct_span_err(sp, &format!("invalid format string: {}", err.description)); - e.span_label(sp, err.label + " in format string"); + let mut e = errors::InvalidFormatString { + span: sp, + note_: None, + label_: None, + sugg_: None, + desc: err.description, + label1: err.label, + }; if let Some(note) = err.note { - e.note(¬e); + e.note_ = Some(errors::InvalidFormatStringNote { note }); } if let Some((label, span)) = err.secondary_label && is_source_literal { - e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label); + e.label_ = Some(errors::InvalidFormatStringLabel { span: fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label } ); } if err.should_be_replaced_with_positional_argument { let captured_arg_span = @@ -250,17 +258,15 @@ fn make_format_args( Some(arg) => arg.expr.span, None => fmt_span, }; - e.multipart_suggestion_verbose( - "consider using a positional formatting argument instead", - vec![ - (captured_arg_span, args.unnamed_args().len().to_string()), - (span.shrink_to_hi(), format!(", {}", arg)), - ], - Applicability::MachineApplicable, - ); + e.sugg_ = Some(errors::InvalidFormatStringSuggestion { + captured: captured_arg_span, + len: args.unnamed_args().len().to_string(), + span: span.shrink_to_hi(), + arg, + }); } } - e.emit(); + ecx.emit_err(e); return Err(()); } @@ -318,10 +324,7 @@ fn make_format_args( } else { // For the moment capturing variables from format strings expanded from macros is // disabled (see RFC #2795) - ecx.struct_span_err(span, &format!("there is no argument named `{name}`")) - .note(format!("did you intend to capture a variable `{name}` from the surrounding scope?")) - .note("to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro") - .emit(); + ecx.emit_err(errors::FormatNoArgNamed { span, name }); DummyResult::raw_expr(span, true) }; Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr })) @@ -475,12 +478,8 @@ fn make_format_args( .enumerate() .filter(|&(_, used)| !used) .map(|(i, _)| { - let msg = if let FormatArgumentKind::Named(_) = args.explicit_args()[i].kind { - "named argument never used" - } else { - "argument never used" - }; - (args.explicit_args()[i].expr.span, msg) + let named = matches!(args.explicit_args()[i].kind, FormatArgumentKind::Named(_)); + (args.explicit_args()[i].expr.span, named) }) .collect::>(); @@ -531,22 +530,8 @@ fn invalid_placeholder_type_error( fmt_span: Span, ) { let sp = ty_span.map(|sp| fmt_span.from_inner(InnerSpan::new(sp.start, sp.end))); - let mut err = - ecx.struct_span_err(sp.unwrap_or(fmt_span), &format!("unknown format trait `{}`", ty)); - err.note( - "the only appropriate formatting traits are:\n\ - - ``, which uses the `Display` trait\n\ - - `?`, which uses the `Debug` trait\n\ - - `e`, which uses the `LowerExp` trait\n\ - - `E`, which uses the `UpperExp` trait\n\ - - `o`, which uses the `Octal` trait\n\ - - `p`, which uses the `Pointer` trait\n\ - - `b`, which uses the `Binary` trait\n\ - - `x`, which uses the `LowerHex` trait\n\ - - `X`, which uses the `UpperHex` trait", - ); - if let Some(sp) = sp { - for (fmt, name) in &[ + let suggs = if let Some(sp) = sp { + [ ("", "Display"), ("?", "Debug"), ("e", "LowerExp"), @@ -556,40 +541,38 @@ fn invalid_placeholder_type_error( ("b", "Binary"), ("x", "LowerHex"), ("X", "UpperHex"), - ] { - err.tool_only_span_suggestion( - sp, - &format!("use the `{}` trait", name), - *fmt, - Applicability::MaybeIncorrect, - ); - } - } - err.emit(); + ] + .into_iter() + .map(|(fmt, trait_name)| errors::FormatUnknownTraitSugg { span: sp, fmt, trait_name }) + .collect() + } else { + vec![] + }; + ecx.emit_err(errors::FormatUnknownTrait { span: sp.unwrap_or(fmt_span), ty, suggs }); } fn report_missing_placeholders( ecx: &mut ExtCtxt<'_>, - unused: Vec<(Span, &str)>, + unused: Vec<(Span, bool)>, detect_foreign_fmt: bool, str_style: Option, fmt_str: &str, fmt_span: Span, ) { - let mut diag = if let &[(span, msg)] = &unused[..] { - let mut diag = ecx.struct_span_err(span, msg); - diag.span_label(span, msg); - diag + let mut diag = if let &[(span, named)] = &unused[..] { + //let mut diag = ecx.struct_span_err(span, msg); + //diag.span_label(span, msg); + //diag + ecx.create_err(errors::FormatUnusedArg { span, named }) } else { - let mut diag = ecx.struct_span_err( - unused.iter().map(|&(sp, _)| sp).collect::>(), - "multiple unused formatting arguments", - ); - diag.span_label(fmt_span, "multiple missing formatting specifiers"); - for &(span, msg) in &unused { - diag.span_label(span, msg); - } - diag + let unused_labels = + unused.iter().map(|&(span, named)| errors::FormatUnusedArg { span, named }).collect(); + let unused_spans = unused.iter().map(|&(span, _)| span).collect(); + ecx.create_err(errors::FormatUnusedArgs { + fmt: fmt_span, + unused: unused_spans, + unused_labels, + }) }; // Used to ensure we only report translations for *one* kind of foreign format. @@ -768,18 +751,16 @@ fn report_invalid_references( } else { MultiSpan::from_spans(spans) }; - e = ecx.struct_span_err( + e = ecx.create_err(errors::FormatPositionalMismatch { span, - &format!( - "{} positional argument{} in format string, but {}", - num_placeholders, - pluralize!(num_placeholders), - num_args_desc, - ), - ); - for arg in args.explicit_args() { - e.span_label(arg.expr.span, ""); - } + n: num_placeholders, + desc: num_args_desc, + highlight: SingleLabelManySpans { + spans: args.explicit_args().iter().map(|arg| arg.expr.span).collect(), + label: "", + kind: rustc_errors::LabelKind::Label, + }, + }); // Point out `{:.*}` placeholders: those take an extra argument. let mut has_precision_star = false; for piece in template { diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 7697b592e33a..37fbd03a6a21 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -9,6 +9,7 @@ #![feature(if_let_guard)] #![feature(is_sorted)] #![feature(let_chains)] +#![feature(lint_reasons)] #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] #![recursion_limit = "256"] @@ -39,6 +40,7 @@ mod derive; mod deriving; mod edition_panic; mod env; +mod errors; mod format; mod format_foreign; mod global_allocator; diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 9ed8ab67431c..cd0049b45586 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -880,6 +880,7 @@ impl Diagnostic { /// /// This is intended to be used for suggestions that are *very* obvious in what the changes /// need to be from the message, but we still want other tools to be able to apply them. + #[rustc_lint_diagnostics] pub fn tool_only_span_suggestion( &mut self, sp: Span, diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index e82bad67b21e..65f8a61a30a9 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -1,4 +1,4 @@ -use crate::fluent_generated as fluent; +use crate::{fluent_generated as fluent, AddToDiagnostic}; use crate::{DiagnosticArgValue, DiagnosticBuilder, Handler, IntoDiagnostic, IntoDiagnosticArg}; use rustc_ast as ast; use rustc_ast_pretty::pprust; @@ -6,6 +6,7 @@ use rustc_hir as hir; use rustc_lint_defs::Level; use rustc_span::edition::Edition; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol}; +use rustc_span::Span; use rustc_target::abi::TargetDataLayoutErrors; use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple}; use rustc_type_ir as type_ir; @@ -276,3 +277,26 @@ impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> { } } } + +/// Utility struct used to apply a single label while highlighting multiple spans +pub struct SingleLabelManySpans { + pub spans: Vec, + pub label: &'static str, + pub kind: LabelKind, +} +impl AddToDiagnostic for SingleLabelManySpans { + fn add_to_diagnostic_with(self, diag: &mut crate::Diagnostic, _: F) { + match self.kind { + LabelKind::Note => diag.span_note(self.spans, self.label), + LabelKind::Label => diag.span_labels(self.spans, self.label), + LabelKind::Help => diag.span_help(self.spans, self.label), + }; + } +} + +/// The kind of label to attach when using [`SingleLabelManySpans`] +pub enum LabelKind { + Note, + Label, + Help, +} diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 9866a9bffe0e..5b0d80962073 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -383,7 +383,9 @@ pub use diagnostic::{ DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, }; pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted}; -pub use diagnostic_impls::{DiagnosticArgFromDisplay, DiagnosticSymbolList}; +pub use diagnostic_impls::{ + DiagnosticArgFromDisplay, DiagnosticSymbolList, LabelKind, SingleLabelManySpans, +}; use std::backtrace::Backtrace; /// A handler deals with errors and other compiler output. diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 9b91627883a8..181e65d89531 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -392,14 +392,16 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { } SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => { let inner = info.ty.inner_type(); - if type_matches_path(inner, &["rustc_span", "Span"]) { + if type_matches_path(inner, &["rustc_span", "Span"]) + || type_matches_path(inner, &["rustc_span", "MultiSpan"]) + { Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug)) } else if type_is_unit(inner) || (matches!(info.ty, FieldInnerTy::Plain(_)) && type_is_bool(inner)) { Ok(self.add_subdiagnostic(&fn_ident, slug)) } else { - report_type_error(attr, "`Span`, `bool` or `()`")? + report_type_error(attr, "`Span`, `MultiSpan`, `bool` or `()`")? } } SubdiagnosticKind::Suggestion { diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs index 61724c11745c..6cc7bab37266 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs @@ -518,7 +518,7 @@ struct BoolField { #[help] foo: bool, #[help(no_crate_help)] - //~^ ERROR the `#[help(...)]` attribute can only be applied to fields of type `Span`, `bool` or `()` + //~^ ERROR the `#[help(...)]` attribute can only be applied to fields of type // only allow plain 'bool' fields bar: Option, } diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index cd14c7496b37..a2f3bb5277b5 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -323,7 +323,7 @@ error: invalid applicability LL | #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")] | ^^^^^^^^ -error: the `#[help(...)]` attribute can only be applied to fields of type `Span`, `bool` or `()` +error: the `#[help(...)]` attribute can only be applied to fields of type `Span`, `MultiSpan`, `bool` or `()` --> $DIR/diagnostic-derive.rs:520:5 | LL | #[help(no_crate_help)] diff --git a/tests/ui/extenv/extenv-no-args.rs b/tests/ui/extenv/extenv-no-args.rs index 9f221ed10d74..2ff6d242b27c 100644 --- a/tests/ui/extenv/extenv-no-args.rs +++ b/tests/ui/extenv/extenv-no-args.rs @@ -1 +1 @@ -fn main() { env!(); } //~ ERROR: env! takes 1 or 2 arguments +fn main() { env!(); } //~ ERROR: `env!()` takes 1 or 2 arguments diff --git a/tests/ui/extenv/extenv-no-args.stderr b/tests/ui/extenv/extenv-no-args.stderr index 318ed635be02..70b85932c233 100644 --- a/tests/ui/extenv/extenv-no-args.stderr +++ b/tests/ui/extenv/extenv-no-args.stderr @@ -1,4 +1,4 @@ -error: env! takes 1 or 2 arguments +error: `env!()` takes 1 or 2 arguments --> $DIR/extenv-no-args.rs:1:13 | LL | fn main() { env!(); } diff --git a/tests/ui/extenv/extenv-too-many-args.rs b/tests/ui/extenv/extenv-too-many-args.rs index 1adbee583dbe..ffad1c51303f 100644 --- a/tests/ui/extenv/extenv-too-many-args.rs +++ b/tests/ui/extenv/extenv-too-many-args.rs @@ -1 +1 @@ -fn main() { env!("one", "two", "three"); } //~ ERROR: env! takes 1 or 2 arguments +fn main() { env!("one", "two", "three"); } //~ ERROR: `env!()` takes 1 or 2 arguments diff --git a/tests/ui/extenv/extenv-too-many-args.stderr b/tests/ui/extenv/extenv-too-many-args.stderr index 54150a3328f9..47cf810b70d7 100644 --- a/tests/ui/extenv/extenv-too-many-args.stderr +++ b/tests/ui/extenv/extenv-too-many-args.stderr @@ -1,4 +1,4 @@ -error: env! takes 1 or 2 arguments +error: `env!()` takes 1 or 2 arguments --> $DIR/extenv-too-many-args.rs:1:13 | LL | fn main() { env!("one", "two", "three"); } diff --git a/tests/ui/extenv/issue-55897.stderr b/tests/ui/extenv/issue-55897.stderr index 5752a965e351..401db827813a 100644 --- a/tests/ui/extenv/issue-55897.stderr +++ b/tests/ui/extenv/issue-55897.stderr @@ -4,7 +4,7 @@ error: environment variable `NON_EXISTENT` not defined at compile time LL | include!(concat!(env!("NON_EXISTENT"), "/data.rs")); | ^^^^^^^^^^^^^^^^^^^^ | - = help: Use `std::env::var("NON_EXISTENT")` to read the variable at run time + = help: use `std::env::var("NON_EXISTENT")` to read the variable at run time = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) error: suffixes on string literals are invalid diff --git a/tests/ui/issues/issue-50403.rs b/tests/ui/issues/issue-50403.rs index 012057fc2809..ab22aff26d99 100644 --- a/tests/ui/issues/issue-50403.rs +++ b/tests/ui/issues/issue-50403.rs @@ -1,5 +1,5 @@ #![feature(concat_idents)] fn main() { - let x = concat_idents!(); //~ ERROR concat_idents! takes 1 or more arguments + let x = concat_idents!(); //~ ERROR `concat_idents!()` takes 1 or more arguments } diff --git a/tests/ui/issues/issue-50403.stderr b/tests/ui/issues/issue-50403.stderr index a3a2ed044db3..d50befa5e326 100644 --- a/tests/ui/issues/issue-50403.stderr +++ b/tests/ui/issues/issue-50403.stderr @@ -1,4 +1,4 @@ -error: concat_idents! takes 1 or more arguments +error: `concat_idents!()` takes 1 or more arguments --> $DIR/issue-50403.rs:4:13 | LL | let x = concat_idents!(); diff --git a/tests/ui/macros/concat-bytes-error.stderr b/tests/ui/macros/concat-bytes-error.stderr index d6cd1a3d178b..3f2c64922e34 100644 --- a/tests/ui/macros/concat-bytes-error.stderr +++ b/tests/ui/macros/concat-bytes-error.stderr @@ -4,7 +4,7 @@ error: expected a byte literal LL | concat_bytes!(pie); | ^^^ | - = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()` + = note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` error: expected a byte literal --> $DIR/concat-bytes-error.rs:5:19 @@ -12,7 +12,7 @@ error: expected a byte literal LL | concat_bytes!(pie, pie); | ^^^ ^^^ | - = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()` + = note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` error: cannot concatenate string literals --> $DIR/concat-bytes-error.rs:6:19 @@ -98,7 +98,7 @@ error: expected a byte literal LL | -33, | ^^^ | - = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()` + = note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` error: cannot concatenate doubly nested array --> $DIR/concat-bytes-error.rs:35:9 @@ -151,7 +151,7 @@ error: expected a byte literal LL | concat_bytes!([pie; 2]); | ^^^ | - = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()` + = note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` error: cannot concatenate float literals --> $DIR/concat-bytes-error.rs:46:20 diff --git a/tests/ui/macros/macros-nonfatal-errors.stderr b/tests/ui/macros/macros-nonfatal-errors.stderr index 93fbc9c8a447..ca373ea6cd9e 100644 --- a/tests/ui/macros/macros-nonfatal-errors.stderr +++ b/tests/ui/macros/macros-nonfatal-errors.stderr @@ -3,36 +3,48 @@ error: the `#[default]` attribute may only be used on unit enum variants | LL | #[default] | ^^^^^^^^^^ + | + = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants --> $DIR/macros-nonfatal-errors.rs:18:36 | LL | struct DefaultInnerAttrTupleStruct(#[default] ()); | ^^^^^^^^^^ + | + = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants --> $DIR/macros-nonfatal-errors.rs:22:1 | LL | #[default] | ^^^^^^^^^^ + | + = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants --> $DIR/macros-nonfatal-errors.rs:26:1 | LL | #[default] | ^^^^^^^^^^ + | + = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants --> $DIR/macros-nonfatal-errors.rs:36:11 | LL | Foo = #[default] 0, | ^^^^^^^^^^ + | + = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants --> $DIR/macros-nonfatal-errors.rs:37:14 | LL | Bar([u8; #[default] 1]), | ^^^^^^^^^^ + | + = help: consider a manual implementation of `Default` error: no default declared --> $DIR/macros-nonfatal-errors.rs:42:10 @@ -132,7 +144,7 @@ error: asm template must be a string literal LL | asm!(invalid); | ^^^^^^^ -error: concat_idents! requires ident args +error: `concat_idents!()` requires ident args --> $DIR/macros-nonfatal-errors.rs:101:5 | LL | concat_idents!("not", "idents"); @@ -150,7 +162,7 @@ error: expected string literal LL | env!(invalid); | ^^^^^^^ -error: env! takes 1 or 2 arguments +error: `env!()` takes 1 or 2 arguments --> $DIR/macros-nonfatal-errors.rs:105:5 | LL | env!(foo, abr, baz); @@ -162,7 +174,7 @@ error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined at co LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: Use `std::env::var("RUST_HOPEFULLY_THIS_DOESNT_EXIST")` to read the variable at run time + = help: use `std::env::var("RUST_HOPEFULLY_THIS_DOESNT_EXIST")` to read the variable at run time = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) error: format argument must be a string literal From 40f12c68ea9fe0d80456c27bb0ab8cbbc87b021c Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Mon, 10 Apr 2023 22:29:10 +0200 Subject: [PATCH 170/272] Revert method-not-found-generic-arg-elision test bless --- tests/ui/methods/method-not-found-generic-arg-elision.stderr | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/ui/methods/method-not-found-generic-arg-elision.stderr b/tests/ui/methods/method-not-found-generic-arg-elision.stderr index ddbaece96d9f..f3db56d1d539 100644 --- a/tests/ui/methods/method-not-found-generic-arg-elision.stderr +++ b/tests/ui/methods/method-not-found-generic-arg-elision.stderr @@ -24,8 +24,6 @@ error[E0599]: no method named `extend` found for struct `Map` in the current sco | LL | v.iter().map(|x| x * x).extend(std::iter::once(100)); | ^^^^^^ method not found in `Map, [closure@method-not-found-generic-arg-elision.rs:87:18]>` - | - = note: the full type name has been written to '$TEST_BUILD_DIR/methods/method-not-found-generic-arg-elision/method-not-found-generic-arg-elision.long-type-15656389337579798043.txt' error[E0599]: no method named `method` found for struct `Wrapper` in the current scope --> $DIR/method-not-found-generic-arg-elision.rs:90:13 From dd28cfbc85160c08c57390adb50d03e755c8b425 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 10 Apr 2023 15:13:49 -0700 Subject: [PATCH 171/272] rustdoc: remove redundant expandSection code from main.js This functionality is already tested in `hash-item-expansion.goml`, and was implemented twice: * First, in code that ran at load time and at hash change: 917cdd295d2eed213c135d6f984c650f016ee3d6 * Later, the hash change event handler was itself run at load time, and the code handling both cases diverged in implementation, though their behavior still matches pretty well: f66a331335f3ac931afabca6f927a9d7dc17db3e --- src/librustdoc/html/static/js/main.js | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 56ee4c1510e8..a6655663b82f 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -331,10 +331,6 @@ function preLoadCss(cssUrl) { }, }; - function getPageId() { - return window.location.hash.replace(/^#/, ""); - } - const toggleAllDocsId = "toggle-all-docs"; let savedHash = ""; @@ -355,12 +351,12 @@ function preLoadCss(cssUrl) { } } // This part is used in case an element is not visible. - if (savedHash !== window.location.hash) { - savedHash = window.location.hash; - if (savedHash.length === 0) { - return; + const pageId = window.location.hash.replace(/^#/, ""); + if (savedHash !== pageId) { + savedHash = pageId; + if (pageId !== "") { + expandSection(pageId); } - expandSection(savedHash.slice(1)); // we remove the '#' } } @@ -699,11 +695,6 @@ function preLoadCss(cssUrl) { } }); - - const pageId = getPageId(); - if (pageId !== "") { - expandSection(pageId); - } }()); window.rustdoc_add_line_numbers_to_examples = () => { From 24cbf81b8546beb8193217316acf4ded4117b4af Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 10 Apr 2023 22:16:17 +0000 Subject: [PATCH 172/272] Remove `..` from return type notation --- compiler/rustc_ast/src/ast.rs | 4 --- compiler/rustc_ast/src/mut_visit.rs | 1 - compiler/rustc_ast/src/visit.rs | 1 - compiler/rustc_ast_lowering/src/errors.rs | 8 +----- compiler/rustc_ast_lowering/src/lib.rs | 27 +++++++++++-------- compiler/rustc_ast_lowering/src/path.rs | 13 --------- .../rustc_ast_passes/src/ast_validation.rs | 2 -- compiler/rustc_ast_passes/src/feature_gate.rs | 19 +++++++------ compiler/rustc_ast_pretty/src/pprust/state.rs | 4 --- compiler/rustc_parse/messages.ftl | 4 +++ compiler/rustc_parse/src/errors.rs | 8 ++++++ compiler/rustc_parse/src/parser/path.rs | 25 ++++++++++------- compiler/rustc_passes/src/hir_stats.rs | 2 +- compiler/rustc_resolve/src/late.rs | 1 - compiler/rustc_resolve/src/lib.rs | 1 - .../bad-inputs-and-output.rs | 8 +++--- .../bad-inputs-and-output.stderr | 24 ++++++++--------- .../return-type-notation/basic.rs | 2 +- .../return-type-notation/equality.rs | 2 +- .../return-type-notation/equality.stderr | 4 +-- .../return-type-notation/missing.rs | 2 +- .../return-type-notation/missing.stderr | 4 +-- .../return-type-notation/non-rpitit.rs | 2 +- .../return-type-notation/non-rpitit.stderr | 4 +-- ...ature-gate-return_type_notation.cfg.stderr | 27 ++++++++++++++----- ...eature-gate-return_type_notation.no.stderr | 25 ++++++++--------- .../feature-gate-return_type_notation.rs | 11 ++++++-- 27 files changed, 126 insertions(+), 109 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index fb9d71b52a8a..df1a716755b4 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -167,9 +167,6 @@ pub enum GenericArgs { AngleBracketed(AngleBracketedArgs), /// The `(A, B)` and `C` in `Foo(A, B) -> C`. Parenthesized(ParenthesizedArgs), - /// Associated return type bounds, like `T: Trait` - /// which applies the `Send` bound to the return-type of `method`. - ReturnTypeNotation(Span), } impl GenericArgs { @@ -181,7 +178,6 @@ impl GenericArgs { match self { AngleBracketed(data) => data.span, Parenthesized(data) => data.span, - ReturnTypeNotation(span) => *span, } } } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 2424073ae53a..694d31d8f1fd 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -561,7 +561,6 @@ pub fn noop_visit_generic_args(generic_args: &mut GenericArgs, vi match generic_args { GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data), GenericArgs::Parenthesized(data) => vis.visit_parenthesized_parameter_data(data), - GenericArgs::ReturnTypeNotation(_span) => {} } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 3b08467fde2b..ac9b321b71c6 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -482,7 +482,6 @@ where walk_list!(visitor, visit_ty, &data.inputs); walk_fn_ret_ty(visitor, &data.output); } - GenericArgs::ReturnTypeNotation(_span) => {} } } diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index f4e55619ebb1..4eefd951b24a 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -353,13 +353,7 @@ pub enum BadReturnTypeNotation { #[diag(ast_lowering_bad_return_type_notation_inputs)] Inputs { #[primary_span] - #[suggestion(code = "(..)", applicability = "maybe-incorrect")] - span: Span, - }, - #[diag(ast_lowering_bad_return_type_notation_needs_dots)] - NeedsDots { - #[primary_span] - #[suggestion(code = "(..)", applicability = "maybe-incorrect")] + #[suggestion(code = "()", applicability = "maybe-incorrect")] span: Span, }, #[diag(ast_lowering_bad_return_type_notation_output)] diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ca659db4dbea..f7ae96b7c4a3 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -987,15 +987,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { GenericArgs::AngleBracketed(data) => { self.lower_angle_bracketed_parameter_data(data, ParamMode::Explicit, itctx).0 } - &GenericArgs::ReturnTypeNotation(span) => GenericArgsCtor { - args: Default::default(), - bindings: &[], - parenthesized: hir::GenericArgsParentheses::ReturnTypeNotation, - span, - }, GenericArgs::Parenthesized(data) => { - if let Some(start_char) = constraint.ident.as_str().chars().next() - && start_char.is_ascii_lowercase() + if data.inputs.is_empty() && matches!(data.output, FnRetTy::Default(..)) { + let parenthesized = if self.tcx.features().return_type_notation { + hir::GenericArgsParentheses::ReturnTypeNotation + } else { + self.emit_bad_parenthesized_trait_in_assoc_ty(data); + hir::GenericArgsParentheses::No + }; + GenericArgsCtor { + args: Default::default(), + bindings: &[], + parenthesized, + span: data.inputs_span, + } + } else if let Some(first_char) = constraint.ident.as_str().chars().next() + && first_char.is_ascii_lowercase() { let mut err = if !data.inputs.is_empty() { self.tcx.sess.create_err(errors::BadReturnTypeNotation::Inputs { @@ -1006,9 +1013,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: data.inputs_span.shrink_to_hi().to(ty.span), }) } else { - self.tcx.sess.create_err(errors::BadReturnTypeNotation::NeedsDots { - span: data.inputs_span, - }) + unreachable!("inputs are empty and return type is not provided") }; if !self.tcx.features().return_type_notation && self.tcx.sess.is_nightly_build() diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 1c47a969696d..8eb84c036a08 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -13,7 +13,6 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; -use thin_vec::ThinVec; impl<'a, 'hir> LoweringContext<'a, 'hir> { #[instrument(level = "trace", skip(self))] @@ -219,18 +218,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) } }, - &GenericArgs::ReturnTypeNotation(span) => { - self.tcx.sess.emit_err(GenericTypeWithParentheses { span, sub: None }); - ( - self.lower_angle_bracketed_parameter_data( - &AngleBracketedArgs { span, args: ThinVec::default() }, - param_mode, - itctx, - ) - .0, - false, - ) - } } } else { ( diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 1389acabfcbd..c243afdb8975 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1075,7 +1075,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.with_impl_trait(None, |this| this.visit_ty(ty)); } } - GenericArgs::ReturnTypeNotation(_span) => {} } } @@ -1386,7 +1385,6 @@ fn deny_equality_constraints( match &mut assoc_path.segments[len].args { Some(args) => match args.deref_mut() { GenericArgs::Parenthesized(_) => continue, - GenericArgs::ReturnTypeNotation(_span) => continue, GenericArgs::AngleBracketed(args) => { args.args.push(arg); } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 007d64f681f7..66d82a26c377 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -485,20 +485,23 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) { if let AssocConstraintKind::Bound { .. } = constraint.kind { - if let Some(args) = constraint.gen_args.as_ref() - && matches!( - args, - ast::GenericArgs::ReturnTypeNotation(..) - ) + if let Some(ast::GenericArgs::Parenthesized(args)) = constraint.gen_args.as_ref() + && args.inputs.is_empty() + && matches!(args.output, ast::FnRetTy::Default(..)) { - // RTN is gated below with a `gate_all`. + gate_feature_post!( + &self, + return_type_notation, + constraint.span, + "return type notation is experimental" + ); } else { gate_feature_post!( &self, associated_type_bounds, constraint.span, "associated type bounds are unstable" - ) + ); } } visit::walk_assoc_constraint(self, constraint) @@ -589,7 +592,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(yeet_expr, "`do yeet` expression is experimental"); gate_all!(dyn_star, "`dyn*` trait objects are experimental"); gate_all!(const_closures, "const closures are experimental"); - gate_all!(return_type_notation, "return type notation is experimental"); // All uses of `gate_all!` below this point were added in #65742, // and subsequently disabled (with the non-early gating readded). @@ -605,6 +607,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(trait_alias, "trait aliases are experimental"); gate_all!(associated_type_bounds, "associated type bounds are unstable"); + gate_all!(return_type_notation, "return type notation is experimental"); gate_all!(decl_macro, "`macro` is experimental"); gate_all!(box_patterns, "box pattern syntax is experimental"); gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental"); diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 1f6838a02784..849336c8669a 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -936,10 +936,6 @@ impl<'a> PrintState<'a> for State<'a> { self.word(")"); self.print_fn_ret_ty(&data.output); } - - ast::GenericArgs::ReturnTypeNotation(_span) => { - self.word("(..)"); - } } } } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index e21bbd0217bd..f11d0ed0f010 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -738,3 +738,7 @@ parse_box_syntax_removed = `box_syntax` has been removed parse_bad_return_type_notation_output = return type not allowed with return type notation .suggestion = remove the return type + +parse_bad_return_type_notation_dotdot = + return type notation uses `()` instead of `(..)` for elided arguments + .suggestion = remove the `..` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index aead216b61cd..069217165fab 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2324,3 +2324,11 @@ pub(crate) struct BadReturnTypeNotationOutput { #[suggestion(code = "", applicability = "maybe-incorrect")] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(parse_bad_return_type_notation_dotdot)] +pub(crate) struct BadReturnTypeNotationDotDot { + #[primary_span] + #[suggestion(code = "", applicability = "maybe-incorrect")] + pub span: Span, +} diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index f1c9f0109f82..c25c23d849f0 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -290,16 +290,17 @@ impl<'a> Parser<'a> { })?; let span = lo.to(self.prev_token.span); AngleBracketedArgs { args, span }.into() - } else if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) + } else if self.may_recover() + && self.token.kind == token::OpenDelim(Delimiter::Parenthesis) // FIXME(return_type_notation): Could also recover `...` here. && self.look_ahead(1, |tok| tok.kind == token::DotDot) { - let lo = self.token.span; self.bump(); + self.sess + .emit_err(errors::BadReturnTypeNotationDotDot { span: self.token.span }); self.bump(); self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; let span = lo.to(self.prev_token.span); - self.sess.gated_spans.gate(sym::return_type_notation, span); if self.eat_noexpect(&token::RArrow) { let lo = self.prev_token.span; @@ -308,7 +309,13 @@ impl<'a> Parser<'a> { .emit_err(errors::BadReturnTypeNotationOutput { span: lo.to(ty.span) }); } - P(GenericArgs::ReturnTypeNotation(span)) + ParenthesizedArgs { + span, + inputs: ThinVec::new(), + inputs_span: span, + output: ast::FnRetTy::Default(self.prev_token.span.shrink_to_hi()), + } + .into() } else { // `(T, U) -> R` let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?; @@ -566,13 +573,13 @@ impl<'a> Parser<'a> { }; let span = lo.to(self.prev_token.span); - // Gate associated type bounds, e.g., `Iterator`. if let AssocConstraintKind::Bound { .. } = kind { - if gen_args.as_ref().map_or(false, |args| { - matches!(args, GenericArgs::ReturnTypeNotation(..)) - }) { - // This is already gated in `parse_path_segment` + if let Some(ast::GenericArgs::Parenthesized(args)) = &gen_args + && args.inputs.is_empty() + && matches!(args.output, ast::FnRetTy::Default(..)) + { + self.sess.gated_spans.gate(sym::return_type_notation, span); } else { self.sess.gated_spans.gate(sym::associated_type_bounds, span); } diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index ce44f709f3b7..47e032758f23 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -666,7 +666,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { fn visit_generic_args(&mut self, g: &'v ast::GenericArgs) { record_variants!( (self, g, g, Id::None, ast, GenericArgs, GenericArgs), - [AngleBracketed, Parenthesized, ReturnTypeNotation] + [AngleBracketed, Parenthesized] ); ast_visit::walk_generic_args(self, g) } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 31ac3f1c151e..07b14eaf1b35 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1116,7 +1116,6 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, } } } - GenericArgs::ReturnTypeNotation(_span) => {} } } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 99fad22d4a12..0e84432a5b4b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -312,7 +312,6 @@ impl<'a> From<&'a ast::PathSegment> for Segment { (args.span, found_lifetimes) } GenericArgs::Parenthesized(args) => (args.span, true), - GenericArgs::ReturnTypeNotation(span) => (*span, false), } } else { (DUMMY_SP, false) diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs index 2f9a1d1c76e0..79cee55177ba 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs @@ -12,11 +12,11 @@ fn foo>() {} //~^ ERROR argument types not allowed with return type notation //~| ERROR associated type bounds are unstable -fn bar (): Send>>() {} +fn bar (): Send>>() {} //~^ ERROR return type not allowed with return type notation - -fn baz>() {} -//~^ ERROR return type notation arguments must be elided with `..` //~| ERROR associated type bounds are unstable +fn baz>() {} +//~^ ERROR return type notation uses `()` instead of `(..)` for elided arguments + fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr index b354a6805d6e..b23e0f791eae 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr @@ -1,8 +1,8 @@ -error: return type not allowed with return type notation - --> $DIR/bad-inputs-and-output.rs:15:28 +error: return type notation uses `()` instead of `(..)` for elided arguments + --> $DIR/bad-inputs-and-output.rs:19:24 | -LL | fn bar (): Send>>() {} - | ^^^^^ help: remove the return type +LL | fn baz>() {} + | ^^ help: remove the `..` error[E0658]: associated type bounds are unstable --> $DIR/bad-inputs-and-output.rs:11:17 @@ -14,10 +14,10 @@ LL | fn foo>() {} = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable error[E0658]: associated type bounds are unstable - --> $DIR/bad-inputs-and-output.rs:18:17 + --> $DIR/bad-inputs-and-output.rs:15:17 | -LL | fn baz>() {} - | ^^^^^^^^^^^^^^ +LL | fn bar (): Send>>() {} + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #52662 for more information = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable @@ -43,13 +43,13 @@ error: argument types not allowed with return type notation --> $DIR/bad-inputs-and-output.rs:11:23 | LL | fn foo>() {} - | ^^^^^ help: remove the input types: `(..)` + | ^^^^^ help: remove the input types: `()` -error: return type notation arguments must be elided with `..` - --> $DIR/bad-inputs-and-output.rs:18:23 +error: return type not allowed with return type notation + --> $DIR/bad-inputs-and-output.rs:15:25 | -LL | fn baz>() {} - | ^^ help: add `..`: `(..)` +LL | fn bar (): Send>>() {} + | ^^^^^^ help: remove the return type error: aborting due to 5 previous errors; 2 warnings emitted diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.rs b/tests/ui/associated-type-bounds/return-type-notation/basic.rs index 75d1dc745d1d..0b7530b65d75 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.rs @@ -18,7 +18,7 @@ async fn foo() -> Result<(), ()> { fn is_send(_: impl Send) {} fn test< - #[cfg(with)] T: Foo, + #[cfg(with)] T: Foo, #[cfg(without)] T: Foo, >() { is_send(foo::()); diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.rs b/tests/ui/associated-type-bounds/return-type-notation/equality.rs index c8fc980974ed..75f757e90259 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/equality.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.rs @@ -10,7 +10,7 @@ trait Trait { async fn method() {} } -fn test>>>() {} +fn test>>>() {} //~^ ERROR return type notation is not allowed to use type equality fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.stderr b/tests/ui/associated-type-bounds/return-type-notation/equality.stderr index cd50ff386946..c5b2e5710d4a 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/equality.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.stderr @@ -18,8 +18,8 @@ LL | #![feature(return_type_notation, async_fn_in_trait)] error: return type notation is not allowed to use type equality --> $DIR/equality.rs:13:18 | -LL | fn test>>>() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn test>>>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error; 2 warnings emitted diff --git a/tests/ui/associated-type-bounds/return-type-notation/missing.rs b/tests/ui/associated-type-bounds/return-type-notation/missing.rs index 1263cae44775..7b98a5cdafdd 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/missing.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/missing.rs @@ -8,7 +8,7 @@ trait Trait { async fn method() {} } -fn bar>() {} +fn bar>() {} //~^ ERROR cannot find associated function `methid` in trait `Trait` fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/missing.stderr b/tests/ui/associated-type-bounds/return-type-notation/missing.stderr index 93111b5c36b1..34f5bda884d4 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/missing.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/missing.stderr @@ -18,8 +18,8 @@ LL | #![feature(return_type_notation, async_fn_in_trait)] error: cannot find associated function `methid` in trait `Trait` --> $DIR/missing.rs:11:17 | -LL | fn bar>() {} - | ^^^^^^^^^^^^^^^^ +LL | fn bar>() {} + | ^^^^^^^^^^^^^^ error: aborting due to previous error; 2 warnings emitted diff --git a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs index d283c6eab370..db5f6fe389ea 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs @@ -5,7 +5,7 @@ trait Trait { fn method() {} } -fn test>() {} +fn test>() {} //~^ ERROR return type notation used on function that is not `async` and does not return `impl Trait` fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr index 38c498bc2fbf..31b793995f8a 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr @@ -13,8 +13,8 @@ error: return type notation used on function that is not `async` and does not re LL | fn method() {} | ----------- this function must be `async` or return `impl Trait` ... -LL | fn test>() {} - | ^^^^^^^^^^^^^^^^ +LL | fn test>() {} + | ^^^^^^^^^^^^^^ | = note: function returns `()`, which is not compatible with associated type return bounds diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr index 85728f8e1ad4..c3a371e25e89 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr @@ -1,14 +1,14 @@ error[E0658]: return type notation is experimental - --> $DIR/feature-gate-return_type_notation.rs:12:18 + --> $DIR/feature-gate-return_type_notation.rs:15:17 | -LL | fn foo>() {} - | ^^^^ +LL | fn foo>() {} + | ^^^^^^^^^ | = note: see issue #109417 for more information = help: add `#![feature(return_type_notation)]` to the crate attributes to enable warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/feature-gate-return_type_notation.rs:4:12 + --> $DIR/feature-gate-return_type_notation.rs:7:12 | LL | #![feature(async_fn_in_trait)] | ^^^^^^^^^^^^^^^^^ @@ -16,6 +16,21 @@ LL | #![feature(async_fn_in_trait)] = note: see issue #91611 for more information = note: `#[warn(incomplete_features)]` on by default -error: aborting due to previous error; 1 warning emitted +error: parenthesized generic arguments cannot be used in associated type constraints + --> $DIR/feature-gate-return_type_notation.rs:15:17 + | +LL | fn foo>() {} + | ^-- + | | + | help: remove these parentheses -For more information about this error, try `rustc --explain E0658`. +error[E0220]: associated type `m` not found for `Trait` + --> $DIR/feature-gate-return_type_notation.rs:15:17 + | +LL | fn foo>() {} + | ^ associated type `m` not found + +error: aborting due to 3 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0220, E0658. +For more information about an error, try `rustc --explain E0220`. diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr index 85728f8e1ad4..52c90c1565cf 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr @@ -1,14 +1,5 @@ -error[E0658]: return type notation is experimental - --> $DIR/feature-gate-return_type_notation.rs:12:18 - | -LL | fn foo>() {} - | ^^^^ - | - = note: see issue #109417 for more information - = help: add `#![feature(return_type_notation)]` to the crate attributes to enable - warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/feature-gate-return_type_notation.rs:4:12 + --> $DIR/feature-gate-return_type_notation.rs:7:12 | LL | #![feature(async_fn_in_trait)] | ^^^^^^^^^^^^^^^^^ @@ -16,6 +7,16 @@ LL | #![feature(async_fn_in_trait)] = note: see issue #91611 for more information = note: `#[warn(incomplete_features)]` on by default -error: aborting due to previous error; 1 warning emitted +warning: return type notation is experimental + --> $DIR/feature-gate-return_type_notation.rs:15:17 + | +LL | fn foo>() {} + | ^^^^^^^^^ + | + = note: see issue #109417 for more information + = help: add `#![feature(return_type_notation)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: 2 warnings emitted -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.rs b/tests/ui/feature-gates/feature-gate-return_type_notation.rs index b75feb130a63..5028b9ec9e3d 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.rs +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.rs @@ -1,6 +1,9 @@ // edition: 2021 // revisions: cfg no +//[no] check-pass +// Since we're not adding new syntax, `cfg`'d out RTN must pass. + #![feature(async_fn_in_trait)] //~^ WARN the feature `async_fn_in_trait` is incomplete @@ -9,7 +12,11 @@ trait Trait { } #[cfg(cfg)] -fn foo>() {} -//~^ ERROR return type notation is experimental +fn foo>() {} +//[cfg]~^ ERROR return type notation is experimental +//[cfg]~| ERROR parenthesized generic arguments cannot be used in associated type constraints +//[cfg]~| ERROR associated type `m` not found for `Trait` +//[no]~^^^^ WARN return type notation is experimental +//[no]~| WARN unstable syntax can change at any point in the future, causing a hard error! fn main() {} From a6292676eb412d8239b308cfd1660aa75623bf5b Mon Sep 17 00:00:00 2001 From: David Lattimore Date: Tue, 21 Mar 2023 21:48:03 +1100 Subject: [PATCH 173/272] Preserve argument indexes when inlining MIR We store argument indexes on VarDebugInfo. Unlike the previous method of relying on the variable index to know whether a variable is an argument, this survives MIR inlining. We also no longer check if var.source_info.scope is the outermost scope. When a function gets inlined, the arguments to the inner function will no longer be in the outermost scope. What we care about though is whether they were in the outermost scope prior to inlining, which we know by whether we assigned an argument index. --- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 10 +++----- compiler/rustc_middle/src/mir/mod.rs | 5 ++++ compiler/rustc_middle/src/mir/visit.rs | 1 + .../rustc_mir_build/src/build/matches/mod.rs | 2 ++ compiler/rustc_mir_build/src/build/mod.rs | 4 ++- compiler/rustc_mir_transform/src/generator.rs | 7 ++++++ .../inline-function-args-debug-info.rs | 20 +++++++++++++++ tests/ui/async-await/task-context-arg.rs | 25 +++++++++++++++++++ 8 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 tests/codegen/inline-function-args-debug-info.rs create mode 100644 tests/ui/async-await/task-context-arg.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 280f0207116f..d049bafb821b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -442,11 +442,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (var_ty, var_kind) = match var.value { mir::VarDebugInfoContents::Place(place) => { let var_ty = self.monomorphized_place_ty(place.as_ref()); - let var_kind = if self.mir.local_kind(place.local) == mir::LocalKind::Arg + let var_kind = if let Some(arg_index) = var.argument_index && place.projection.is_empty() - && var.source_info.scope == mir::OUTERMOST_SOURCE_SCOPE { - let arg_index = place.local.index() - 1; + let arg_index = arg_index as usize; if target_is_msvc { // ScalarPair parameters are spilled to the stack so they need to // be marked as a `LocalVariable` for MSVC debuggers to visualize @@ -455,13 +454,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if let Abi::ScalarPair(_, _) = var_ty_layout.abi { VariableKind::LocalVariable } else { - VariableKind::ArgumentVariable(arg_index + 1) + VariableKind::ArgumentVariable(arg_index) } } else { // FIXME(eddyb) shouldn't `ArgumentVariable` indices be // offset in closures to account for the hidden environment? - // Also, is this `+ 1` needed at all? - VariableKind::ArgumentVariable(arg_index + 1) + VariableKind::ArgumentVariable(arg_index) } } else { VariableKind::LocalVariable diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 0fad30973db7..ad69082a70ba 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1115,6 +1115,11 @@ pub struct VarDebugInfo<'tcx> { /// Where the data for this user variable is to be found. pub value: VarDebugInfoContents<'tcx>, + + /// When present, indicates what argument number this variable is in the function that it + /// originated from (starting from 1). Note, if MIR inlining is enabled, then this is the + /// argument number in the original function before it was inlined. + pub argument_index: Option, } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 6c4ea065abeb..0a9fcd898b93 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -832,6 +832,7 @@ macro_rules! make_mir_visitor { name: _, source_info, value, + argument_index: _, } = var_debug_info; self.visit_source_info(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 2d52102db2cc..4926ff85de38 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -2242,6 +2242,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { name, source_info: debug_source_info, value: VarDebugInfoContents::Place(for_arm_body.into()), + argument_index: None, }); let locals = if has_guard.0 { let ref_for_guard = self.local_decls.push(LocalDecl::<'tcx> { @@ -2260,6 +2261,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { name, source_info: debug_source_info, value: VarDebugInfoContents::Place(ref_for_guard.into()), + argument_index: None, }); LocalsForNode::ForGuard { ref_for_guard, for_arm_body } } else { diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 415f5b1b1e15..bc50bcbc3d07 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -811,6 +811,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { name, source_info: SourceInfo::outermost(captured_place.var_ident.span), value: VarDebugInfoContents::Place(use_place), + argument_index: None, }); let capture = Capture { captured_place, use_place, mutability }; @@ -827,7 +828,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr: &Expr<'tcx>, ) -> BlockAnd<()> { // Allocate locals for the function arguments - for param in arguments.iter() { + for (argument_index, param) in arguments.iter().enumerate() { let source_info = SourceInfo::outermost(param.pat.as_ref().map_or(self.fn_span, |pat| pat.span)); let arg_local = @@ -839,6 +840,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { name, source_info, value: VarDebugInfoContents::Place(arg_local.into()), + argument_index: Some(argument_index as u16 + 1), }); } } diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 159780319ba5..4c4423721fb8 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1556,6 +1556,13 @@ impl<'tcx> MirPass<'tcx> for StateTransform { body.arg_count = 2; // self, resume arg body.spread_arg = None; + // The original arguments to the function are no longer arguments, mark them as such. + // Otherwise they'll conflict with our new arguments, which although they don't have + // argument_index set, will get emitted as unnamed arguments. + for var in &mut body.var_debug_info { + var.argument_index = None; + } + body.generator.as_mut().unwrap().yield_ty = None; body.generator.as_mut().unwrap().generator_layout = Some(layout); diff --git a/tests/codegen/inline-function-args-debug-info.rs b/tests/codegen/inline-function-args-debug-info.rs new file mode 100644 index 000000000000..e3d8caa49d45 --- /dev/null +++ b/tests/codegen/inline-function-args-debug-info.rs @@ -0,0 +1,20 @@ +// This test checks that debug information includes function argument indexes even if the function +// gets inlined by MIR inlining. Without function argument indexes, `info args` in gdb won't show +// arguments and their values for the current function. + +// compile-flags: -Zinline-mir=yes -Cdebuginfo=2 --edition=2021 + +#![crate_type = "lib"] + +pub fn outer_function(x: usize, y: usize) -> usize { + inner_function(x, y) + 1 +} + +#[inline] +fn inner_function(aaaa: usize, bbbb: usize) -> usize { + // CHECK: !DILocalVariable(name: "aaaa", arg: 1 + // CHECK-SAME: line: 14 + // CHECK: !DILocalVariable(name: "bbbb", arg: 2 + // CHECK-SAME: line: 14 + aaaa + bbbb +} diff --git a/tests/ui/async-await/task-context-arg.rs b/tests/ui/async-await/task-context-arg.rs new file mode 100644 index 000000000000..937723ca743e --- /dev/null +++ b/tests/ui/async-await/task-context-arg.rs @@ -0,0 +1,25 @@ +// Checks that we don't get conflicting arguments in our debug info with a particular async function +// structure. + +// edition:2021 +// compile-flags: -Cdebuginfo=2 +// build-pass + +#![crate_type = "lib"] + +use std::future::Future; + +// The compiler produces a closure as part of this function. That closure initially takes an +// argument _task_context. Later, when the MIR for that closure is transformed into a generator +// state machine, _task_context is demoted to not be an argument, but just part of an unnamed +// argument. If we emit debug info saying that both _task_context and the unnamed argument are both +// argument number 2, then LLVM will fail with "conflicting debug info for argument". See +// https://github.com/rust-lang/rust/pull/109466#issuecomment-1500879195 for details. +async fn recv_unit() { + std::future::ready(()).await; +} + +pub fn poll_recv() { + // This box is necessary in order to reproduce the problem. + let _: Box> = Box::new(recv_unit()); +} From 63030acf4ff453da2beb7f43b13cca8fb6cf425a Mon Sep 17 00:00:00 2001 From: Michael Schubart Date: Sun, 12 Mar 2023 14:45:22 +0000 Subject: [PATCH 174/272] Refactor --- clippy_lints/src/collection_is_never_read.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index 15a5b7dd2748..a5feffa31065 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -101,9 +101,9 @@ fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Bloc return ControlFlow::Continue(()); } - // Method call on `id` in a statement ignores any return value, so it's not a read access: + // Look for method call with receiver `id`. It might be a non-read access: // - // id.foo(...); // Not reading `id`. + // id.foo(args) // // Only assuming this for "official" methods defined on the type. For methods defined in extension // traits (identified as local, based on the orphan rule), pessimistically assume that they might @@ -111,11 +111,15 @@ fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Bloc if let Some(Node::Expr(parent)) = get_parent_node(cx.tcx, expr.hir_id) && let ExprKind::MethodCall(_, receiver, _, _) = parent.kind && path_to_local_id(receiver, id) - && let Some(Node::Stmt(..)) = get_parent_node(cx.tcx, parent.hir_id) && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id) && !method_def_id.is_local() { - return ControlFlow::Continue(()); + // The method call is a statement, so the return value is not used. That's not a read access: + // + // id.foo(args); + if let Some(Node::Stmt(..)) = get_parent_node(cx.tcx, parent.hir_id) { + return ControlFlow::Continue(()); + } } // Any other access to `id` is a read access. Stop searching. From 008ba7326b315abd1d6ef693d773b88ccb044ba4 Mon Sep 17 00:00:00 2001 From: Michael Schubart Date: Sun, 12 Mar 2023 14:56:14 +0000 Subject: [PATCH 175/272] Ignore fake read access --- clippy_lints/src/collection_is_never_read.rs | 9 +++++++++ tests/ui/collection_is_never_read.rs | 3 +-- tests/ui/collection_is_never_read.stderr | 20 +++++++++++++------- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index a5feffa31065..5e2eb5789f62 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -120,6 +120,15 @@ fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Bloc if let Some(Node::Stmt(..)) = get_parent_node(cx.tcx, parent.hir_id) { return ControlFlow::Continue(()); } + + // The method call is not a statement, so its return value is used somehow but its type is the + // unit type, so this is not a real read access. Examples: + // + // let y = x.clear(); + // println!("{:?}", x.clear()); + if cx.typeck_results().expr_ty(parent).is_unit() { + return ControlFlow::Continue(()); + } } // Any other access to `id` is a read access. Stop searching. diff --git a/tests/ui/collection_is_never_read.rs b/tests/ui/collection_is_never_read.rs index ca20031bfbef..4f9431be72a7 100644 --- a/tests/ui/collection_is_never_read.rs +++ b/tests/ui/collection_is_never_read.rs @@ -85,9 +85,8 @@ fn shadowing_2() { #[allow(clippy::let_unit_value)] fn fake_read() { - let mut x = vec![1, 2, 3]; // Ok + let mut x = vec![1, 2, 3]; // WARNING x.reverse(); - // `collection_is_never_read` gets fooled, but other lints should catch this. let _: () = x.clear(); } diff --git a/tests/ui/collection_is_never_read.stderr b/tests/ui/collection_is_never_read.stderr index f5dea96116f8..cfb392983391 100644 --- a/tests/ui/collection_is_never_read.stderr +++ b/tests/ui/collection_is_never_read.stderr @@ -25,40 +25,46 @@ LL | let mut x = HashMap::new(); // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:95:5 + --> $DIR/collection_is_never_read.rs:88:5 | LL | let mut x = vec![1, 2, 3]; // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:102:5 + --> $DIR/collection_is_never_read.rs:94:5 | LL | let mut x = vec![1, 2, 3]; // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:119:5 + --> $DIR/collection_is_never_read.rs:101:5 + | +LL | let mut x = vec![1, 2, 3]; // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:118:5 | LL | let mut x = HashSet::new(); // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:133:5 + --> $DIR/collection_is_never_read.rs:132:5 | LL | let x = vec![1, 2, 3]; // WARNING | ^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:169:5 + --> $DIR/collection_is_never_read.rs:168:5 | LL | let mut s = String::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:182:5 + --> $DIR/collection_is_never_read.rs:181:5 | LL | let mut s = String::from("Hello, World!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors From 3d711455c21fca69cad5de32385da90a4902c67c Mon Sep 17 00:00:00 2001 From: Michael Schubart Date: Sun, 12 Mar 2023 14:59:10 +0000 Subject: [PATCH 176/272] Add test case from #10488 --- tests/ui/collection_is_never_read.rs | 8 +++++++- tests/ui/collection_is_never_read.stderr | 18 ++++++++++++------ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/tests/ui/collection_is_never_read.rs b/tests/ui/collection_is_never_read.rs index 4f9431be72a7..01259a983ab6 100644 --- a/tests/ui/collection_is_never_read.rs +++ b/tests/ui/collection_is_never_read.rs @@ -84,12 +84,18 @@ fn shadowing_2() { } #[allow(clippy::let_unit_value)] -fn fake_read() { +fn fake_read_1() { let mut x = vec![1, 2, 3]; // WARNING x.reverse(); let _: () = x.clear(); } +fn fake_read_2() { + let mut x = vec![1, 2, 3]; // WARNING + x.reverse(); + println!("{:?}", x.push(5)); +} + fn assignment() { let mut x = vec![1, 2, 3]; // WARNING let y = vec![4, 5, 6]; // Ok diff --git a/tests/ui/collection_is_never_read.stderr b/tests/ui/collection_is_never_read.stderr index cfb392983391..cf51a53686f2 100644 --- a/tests/ui/collection_is_never_read.stderr +++ b/tests/ui/collection_is_never_read.stderr @@ -37,34 +37,40 @@ LL | let mut x = vec![1, 2, 3]; // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:101:5 + --> $DIR/collection_is_never_read.rs:100:5 | LL | let mut x = vec![1, 2, 3]; // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:118:5 + --> $DIR/collection_is_never_read.rs:107:5 + | +LL | let mut x = vec![1, 2, 3]; // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:124:5 | LL | let mut x = HashSet::new(); // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:132:5 + --> $DIR/collection_is_never_read.rs:138:5 | LL | let x = vec![1, 2, 3]; // WARNING | ^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:168:5 + --> $DIR/collection_is_never_read.rs:174:5 | LL | let mut s = String::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:181:5 + --> $DIR/collection_is_never_read.rs:187:5 | LL | let mut s = String::from("Hello, World!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors From 7d269633b1e254ad21f23994bbf04a6a8296abf7 Mon Sep 17 00:00:00 2001 From: fleetingbytes <7075397+fleetingbytes@users.noreply.github.com> Date: Tue, 11 Apr 2023 04:13:35 +0200 Subject: [PATCH 177/272] Break up long first paragraph Further referring to `var_os` as a "function" (like in `var`), rather than "method". --- library/std/src/env.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 51e5c60ed294..74394694d43c 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -236,11 +236,12 @@ fn _var(key: &OsStr) -> Result { } /// Fetches the environment variable `key` from the current process, returning -/// [`None`] if the environment variable isn't set. It may return `None` also -/// if the environment variable's name contains +/// [`None`] if the variable isn't set or if there is another error. +/// +/// It may return `None` if the environment variable's name contains /// the equal sign character (`=`) or the NUL character. /// -/// Note that the method will not check if the environment variable +/// Note that this function will not check if the environment variable /// is valid Unicode. If you want to have an error on invalid UTF-8, /// use the [`var`] function instead. /// From 72bfd55d4b15053df3801eb920ce23032685cf1b Mon Sep 17 00:00:00 2001 From: Tomoaki Kawada Date: Tue, 11 Apr 2023 12:00:36 +0900 Subject: [PATCH 178/272] kmc-solid: Implement `Socket::read_buf` --- library/std/src/sys/solid/net.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/solid/net.rs b/library/std/src/sys/solid/net.rs index 1b98ef993b04..7d7bfae14329 100644 --- a/library/std/src/sys/solid/net.rs +++ b/library/std/src/sys/solid/net.rs @@ -2,7 +2,7 @@ use super::abi; use crate::{ cmp, ffi::CStr, - io::{self, ErrorKind, IoSlice, IoSliceMut}, + io::{self, BorrowedBuf, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}, mem, net::{Shutdown, SocketAddr}, ptr, str, @@ -294,19 +294,30 @@ impl Socket { self.0.duplicate().map(Socket) } - fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { + fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> { let ret = cvt(unsafe { - netc::recv(self.0.raw(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags) + netc::recv(self.0.raw(), buf.as_mut().as_mut_ptr().cast(), buf.capacity(), flags) })?; - Ok(ret as usize) + unsafe { + buf.advance(ret as usize); + } + Ok(()) } pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.recv_with_flags(buf, 0) + let mut buf = BorrowedBuf::from(buf); + self.recv_with_flags(buf.unfilled(), 0)?; + Ok(buf.len()) } pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.recv_with_flags(buf, MSG_PEEK) + let mut buf = BorrowedBuf::from(buf); + self.recv_with_flags(buf.unfilled(), MSG_PEEK)?; + Ok(buf.len()) + } + + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.recv_with_flags(buf, 0) } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { From 47ff60dc09299b15102b4ebe0efd6a0446fe5a05 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 9 Apr 2023 12:31:04 -0500 Subject: [PATCH 179/272] Fix `x test ui --target foo` when download-rustc is enabled Previously, we would never build the target std, only the host std. --- src/bootstrap/compile.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index e3581943f2ca..85d1c12cc6a0 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -83,11 +83,11 @@ impl Step for Std { let target = self.target; let compiler = self.compiler; - // These artifacts were already copied (in `impl Step for Sysroot`). - // Don't recompile them. + // When using `download-rustc`, we already have artifacts for the host available + // (they were copied in `impl Step for Sysroot`). Don't recompile them. // NOTE: the ABI of the beta compiler is different from the ABI of the downloaded compiler, // so its artifacts can't be reused. - if builder.download_rustc() && compiler.stage != 0 { + if builder.download_rustc() && compiler.stage != 0 && target == builder.build.build { return; } From 33527755a33674880093199e311f1d578edd7397 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 11 Apr 2023 13:25:32 +1000 Subject: [PATCH 180/272] Inline and remove `renumber_regions`. It has a single callsite. --- compiler/rustc_borrowck/src/renumber.rs | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 0fbf01dbe445..6913d74af943 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -29,24 +29,6 @@ pub fn renumber_mir<'tcx>( visitor.visit_body(body); } -/// Replaces all regions appearing in `value` with fresh inference -/// variables. -#[instrument(skip(infcx, get_ctxt_fn), level = "debug")] -pub(crate) fn renumber_regions<'tcx, T, F>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, - value: T, - get_ctxt_fn: F, -) -> T -where - T: TypeFoldable>, - F: Fn() -> RegionCtxt, -{ - infcx.tcx.fold_regions(value, |_region, _depth| { - let origin = NllRegionVariableOrigin::Existential { from_forall: false }; - infcx.next_nll_region_var(origin, || get_ctxt_fn()) - }) -} - #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub(crate) enum BoundRegionInfo { Name(Symbol), @@ -87,12 +69,17 @@ struct NllVisitor<'a, 'tcx> { } impl<'a, 'tcx> NllVisitor<'a, 'tcx> { + /// Replaces all regions appearing in `value` with fresh inference + /// variables. fn renumber_regions(&mut self, value: T, region_ctxt_fn: F) -> T where T: TypeFoldable>, F: Fn() -> RegionCtxt, { - renumber_regions(self.infcx, value, region_ctxt_fn) + let origin = NllRegionVariableOrigin::Existential { from_forall: false }; + self.infcx.tcx.fold_regions(value, |_region, _depth| { + self.infcx.next_nll_region_var(origin, || region_ctxt_fn()) + }) } } From 7e8905cd18901fb0a2fdc68bfbf3133291ca2183 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 11 Apr 2023 13:25:57 +1000 Subject: [PATCH 181/272] Rename a variable. --- compiler/rustc_borrowck/src/renumber.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 6913d74af943..07962267594c 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -111,9 +111,9 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { } #[instrument(skip(self), level = "debug")] - fn visit_constant(&mut self, constant: &mut Constant<'tcx>, _location: Location) { + fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) { let literal = constant.literal; - constant.literal = self.renumber_regions(literal, || RegionCtxt::Location(_location)); + constant.literal = self.renumber_regions(literal, || RegionCtxt::Location(location)); debug!("constant: {:#?}", constant); } } From ca3daa0fb69127ed75e79f8e97b5854288b12d51 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 9 Apr 2023 15:19:03 -0500 Subject: [PATCH 182/272] Fix `x check --stage 1` when `download-ci-llvm=false` --- src/bootstrap/check.rs | 4 ++-- src/bootstrap/compile.rs | 38 ++++++++++++++++++++------------------ src/bootstrap/doc.rs | 2 +- src/bootstrap/test.rs | 2 +- 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index cd19667139ab..44efc502e39d 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -237,7 +237,7 @@ impl Step for Rustc { target, cargo_subcommand(builder.kind), ); - rustc_cargo(builder, &mut cargo, target); + rustc_cargo(builder, &mut cargo, target, compiler.stage); // For ./x.py clippy, don't run with --all-targets because // linting tests and benchmarks can produce very noisy results @@ -315,7 +315,7 @@ impl Step for CodegenBackend { cargo .arg("--manifest-path") .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend))); - rustc_cargo_env(builder, &mut cargo, target); + rustc_cargo_env(builder, &mut cargo, target, compiler.stage); let msg = if compiler.host == target { format!("Checking stage{} {} artifacts ({target})", builder.top_stage, backend) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 8fb5c1460d8e..2e91b968d1cb 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -696,7 +696,7 @@ impl Step for Rustc { )); let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "build"); - rustc_cargo(builder, &mut cargo, target); + rustc_cargo(builder, &mut cargo, target, compiler.stage); if builder.config.rust_profile_use.is_some() && builder.config.rust_profile_generate.is_some() @@ -813,16 +813,21 @@ impl Step for Rustc { } } -pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) { +pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection, stage: u32) { cargo .arg("--features") .arg(builder.rustc_features(builder.kind)) .arg("--manifest-path") .arg(builder.src.join("compiler/rustc/Cargo.toml")); - rustc_cargo_env(builder, cargo, target); + rustc_cargo_env(builder, cargo, target, stage); } -pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) { +pub fn rustc_cargo_env( + builder: &Builder<'_>, + cargo: &mut Cargo, + target: TargetSelection, + stage: u32, +) { // Set some configuration variables picked up by build scripts and // the compiler alike cargo @@ -867,16 +872,18 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS cargo.env("RUSTC_VERIFY_LLVM_IR", "1"); } - // // Note that this is disabled if LLVM itself is disabled or we're in a check // build. If we are in a check build we still go ahead here presuming we've // detected that LLVM is already built and good to go which helps prevent // busting caches (e.g. like #71152). - if builder.config.llvm_enabled() - && (builder.kind != Kind::Check - || crate::llvm::prebuilt_llvm_config(builder, target).is_ok()) - { - rustc_llvm_env(builder, cargo, target) + if builder.config.llvm_enabled() { + let building_is_expensive = crate::llvm::prebuilt_llvm_config(builder, target).is_err(); + // `top_stage == stage` might be false for `check --stage 1`, if we are building the stage 1 compiler + let can_skip_build = builder.kind == Kind::Check && builder.top_stage == stage; + let should_skip_build = building_is_expensive && can_skip_build; + if !should_skip_build { + rustc_llvm_env(builder, cargo, target) + } } } @@ -933,13 +940,8 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect && !target.contains("apple") && !target.contains("solaris") { - let file = compiler_file( - builder, - builder.cxx(target).unwrap(), - target, - CLang::Cxx, - "libstdc++.a", - ); + let file = + compiler_file(builder, builder.cxx(target).unwrap(), target, CLang::Cxx, "libstdc++.a"); cargo.env("LLVM_STATIC_STDCPP", file); } if builder.llvm_link_shared() { @@ -1054,7 +1056,7 @@ impl Step for CodegenBackend { cargo .arg("--manifest-path") .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend))); - rustc_cargo_env(builder, &mut cargo, target); + rustc_cargo_env(builder, &mut cargo, target, compiler.stage); let tmp_stamp = out_dir.join(".tmp.stamp"); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index be43affa404e..9ad98eb57022 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -696,7 +696,7 @@ impl Step for Rustc { cargo.rustdocflag("-Znormalize-docs"); cargo.rustdocflag("--show-type-layout"); cargo.rustdocflag("--generate-link-to-definition"); - compile::rustc_cargo(builder, &mut cargo, target); + compile::rustc_cargo(builder, &mut cargo, target, compiler.stage); cargo.arg("-Zunstable-options"); cargo.arg("-Zskip-rustdoc-fingerprint"); diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 92a7603a9df6..03f20a3390ac 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -2143,7 +2143,7 @@ impl Step for Crate { compile::std_cargo(builder, target, compiler.stage, &mut cargo); } Mode::Rustc => { - compile::rustc_cargo(builder, &mut cargo, target); + compile::rustc_cargo(builder, &mut cargo, target, compiler.stage); } _ => panic!("can only test libraries"), }; From 5716ae6982a4044429eb1d27d1921d70aebde64d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 11 Apr 2023 14:18:30 +1000 Subject: [PATCH 183/272] Introduce `Region::get_name_or_anon`. For a common pattern. --- .../rustc_borrowck/src/universal_regions.rs | 33 ++++--------------- compiler/rustc_middle/src/ty/sty.rs | 15 ++++++--- 2 files changed, 16 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 68c86051364e..9a2c14d96022 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -440,11 +440,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { debug!(?r); if !indices.indices.contains_key(&r) { let region_vid = { - let name = match r.get_name() { - Some(name) => name, - _ => Symbol::intern("anon"), - }; - + let name = r.get_name_or_anon(); self.infcx.next_nll_region_var(FR, || { RegionCtxt::LateBound(BoundRegionInfo::Name(name)) }) @@ -478,11 +474,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { debug!(?r); if !indices.indices.contains_key(&r) { let region_vid = { - let name = match r.get_name() { - Some(name) => name, - _ => Symbol::intern("anon"), - }; - + let name = r.get_name_or_anon(); self.infcx.next_nll_region_var(FR, || { RegionCtxt::LateBound(BoundRegionInfo::Name(name)) }) @@ -768,15 +760,10 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { T: TypeFoldable>, { self.infcx.tcx.fold_regions(value, |region, _depth| { - let name = match region.get_name() { - Some(name) => name, - _ => Symbol::intern("anon"), - }; + let name = region.get_name_or_anon(); debug!(?region, ?name); - let reg_var = self.next_nll_region_var(origin, || RegionCtxt::Free(name)); - - reg_var + self.next_nll_region_var(origin, || RegionCtxt::Free(name)) }) } @@ -829,11 +816,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { debug!(?r); if !indices.indices.contains_key(&r) { let region_vid = { - let name = match r.get_name() { - Some(name) => name, - _ => Symbol::intern("anon"), - }; - + let name = r.get_name_or_anon(); self.next_nll_region_var(FR, || { RegionCtxt::LateBound(BoundRegionInfo::Name(name)) }) @@ -855,11 +838,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { debug!(?r); if !indices.indices.contains_key(&r) { let region_vid = { - let name = match r.get_name() { - Some(name) => name, - _ => Symbol::intern("anon"), - }; - + let name = r.get_name_or_anon(); self.next_nll_region_var(FR, || { RegionCtxt::LateBound(BoundRegionInfo::Name(name)) }) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 24cbe8e8281b..e941a4058de6 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1621,19 +1621,24 @@ impl<'tcx> Region<'tcx> { pub fn get_name(self) -> Option { if self.has_name() { - let name = match *self { + match *self { ty::ReEarlyBound(ebr) => Some(ebr.name), ty::ReLateBound(_, br) => br.kind.get_name(), ty::ReFree(fr) => fr.bound_region.get_name(), ty::ReStatic => Some(kw::StaticLifetime), ty::RePlaceholder(placeholder) => placeholder.bound.kind.get_name(), _ => None, - }; - - return name; + } + } else { + None } + } - None + pub fn get_name_or_anon(self) -> Symbol { + match self.get_name() { + Some(name) => name, + None => Symbol::intern("anon"), + } } /// Is this region named by the user? From 1eb53902f3b2b9c02b20472a8c7747b89bd54203 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 11 Apr 2023 14:37:07 +1000 Subject: [PATCH 184/272] Fix `RegionCtxt::preference_value`. There's a bad pattern matching confusion present in this function. `_anon` gets assigned to, and then `_anon` is used as an unbound variable in the pattern, which is unrelated to the first `_anon`. If the `_anon` didn't start with `_` the compiler would give warnings. This was introduced in #104239. I have rewritten the function to remove the confusion and preserve the existing behaviour. This seems safest, because the original intent is not clear. --- compiler/rustc_borrowck/src/renumber.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 0fbf01dbe445..f37a7cce3b3e 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -69,12 +69,10 @@ impl RegionCtxt { /// Used to determine the representative of a component in the strongly connected /// constraint graph pub(crate) fn preference_value(self) -> usize { - let _anon = Symbol::intern("anon"); - match self { RegionCtxt::Unknown => 1, RegionCtxt::Existential(None) => 2, - RegionCtxt::Existential(Some(_anon)) | RegionCtxt::Free(_anon) => 2, + RegionCtxt::Existential(Some(_)) | RegionCtxt::Free(_) => 2, RegionCtxt::Location(_) => 3, RegionCtxt::TyContext(_) => 4, _ => 5, From bd7f301b20380c1e56e72d17310b89214fddb571 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 11 Apr 2023 13:48:41 +1000 Subject: [PATCH 185/272] Use the existing `static` and `env` symbols instead of interning. --- compiler/rustc_borrowck/src/type_check/mod.rs | 5 ++--- compiler/rustc_borrowck/src/type_check/relate_tys.rs | 3 ++- compiler/rustc_borrowck/src/universal_regions.rs | 7 +++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 624a4a00c319..58812faa500a 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -35,6 +35,7 @@ use rustc_middle::ty::{ OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, }; use rustc_span::def_id::CRATE_DEF_ID; +use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints; @@ -1347,9 +1348,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { BoundRegionInfo::Name(Symbol::intern("anon")) } ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name), - ty::BoundRegionKind::BrEnv => { - BoundRegionInfo::Name(Symbol::intern("env")) - } + ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(sym::env), }; RegionCtxt::LateBound(reg_info) diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 83429f2ddef3..a0e365387234 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -4,6 +4,7 @@ use rustc_infer::traits::PredicateObligations; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::{self, Ty}; +use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; use rustc_trait_selection::traits::query::Fallible; @@ -127,7 +128,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> ty::BoundRegionKind::BrAnon(Some(span)) => BoundRegionInfo::Span(span), ty::BoundRegionKind::BrAnon(..) => BoundRegionInfo::Name(Symbol::intern("anon")), ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name), - ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(Symbol::intern("env")), + ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(sym::env), }; let reg_var = diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 9a2c14d96022..cc351c634314 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -24,6 +24,7 @@ use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt}; use rustc_middle::ty::{InternalSubsts, SubstsRef}; +use rustc_span::symbol::kw; use rustc_span::Symbol; use std::iter; @@ -404,10 +405,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { assert_eq!(FIRST_GLOBAL_INDEX, self.infcx.num_region_vars()); // Create the "global" region that is always free in all contexts: 'static. - let fr_static = self - .infcx - .next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("static"))) - .to_region_vid(); + let fr_static = + self.infcx.next_nll_region_var(FR, || RegionCtxt::Free(kw::Static)).to_region_vid(); // We've now added all the global regions. The next ones we // add will be external. From 79757799185515835306e11bec35b3fd3887ee70 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 11 Apr 2023 14:24:59 +1000 Subject: [PATCH 186/272] Add `sym::anon`. --- compiler/rustc_borrowck/src/type_check/mod.rs | 5 +---- compiler/rustc_borrowck/src/type_check/relate_tys.rs | 2 +- compiler/rustc_borrowck/src/universal_regions.rs | 4 ++-- compiler/rustc_middle/src/ty/sty.rs | 2 +- compiler/rustc_span/src/symbol.rs | 1 + 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 58812faa500a..3790b2f34b3c 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1339,14 +1339,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { }; let (sig, map) = tcx.replace_late_bound_regions(sig, |br| { use crate::renumber::{BoundRegionInfo, RegionCtxt}; - use rustc_span::Symbol; let region_ctxt_fn = || { let reg_info = match br.kind { ty::BoundRegionKind::BrAnon(Some(span)) => BoundRegionInfo::Span(span), - ty::BoundRegionKind::BrAnon(..) => { - BoundRegionInfo::Name(Symbol::intern("anon")) - } + ty::BoundRegionKind::BrAnon(..) => BoundRegionInfo::Name(sym::anon), ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name), ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(sym::env), }; diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index a0e365387234..6b64e65518f5 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -126,7 +126,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> let reg_info = match placeholder.bound.kind { ty::BoundRegionKind::BrAnon(Some(span)) => BoundRegionInfo::Span(span), - ty::BoundRegionKind::BrAnon(..) => BoundRegionInfo::Name(Symbol::intern("anon")), + ty::BoundRegionKind::BrAnon(..) => BoundRegionInfo::Name(sym::anon), ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name), ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(sym::env), }; diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index cc351c634314..35dfc1f7d129 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -24,7 +24,7 @@ use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt}; use rustc_middle::ty::{InternalSubsts, SubstsRef}; -use rustc_span::symbol::kw; +use rustc_span::symbol::{kw, sym}; use rustc_span::Symbol; use std::iter; @@ -783,7 +783,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { let region_vid = { let name = match br.kind.get_name() { Some(name) => name, - _ => Symbol::intern("anon"), + _ => sym::anon, }; self.next_nll_region_var(origin, || RegionCtxt::Bound(BoundRegionInfo::Name(name))) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e941a4058de6..086ceebd24d6 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1637,7 +1637,7 @@ impl<'tcx> Region<'tcx> { pub fn get_name_or_anon(self) -> Symbol { match self.get_name() { Some(name) => name, - None => Symbol::intern("anon"), + None => sym::anon, } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7affad9aa017..84a4f10b8ab1 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -357,6 +357,7 @@ symbols! { always, and, and_then, + anon, anonymous_lifetime_in_impl_trait, any, append_const_msg, From d5339becd43c681111daf0d5b2fb7f270abde60c Mon Sep 17 00:00:00 2001 From: reez12g Date: Thu, 6 Apr 2023 19:30:12 +0900 Subject: [PATCH 187/272] rename tests/ui/unique to tests/ui/box/unit --- tests/ui/{unique => box/unit}/expr-block-generic-unique1.rs | 0 tests/ui/{unique => box/unit}/expr-block-generic-unique2.rs | 0 tests/ui/{unique => box/unit}/expr-if-unique.rs | 0 tests/ui/{unique => box/unit}/unique-assign-copy.rs | 0 tests/ui/{unique => box/unit}/unique-assign-drop.rs | 0 tests/ui/{unique => box/unit}/unique-assign-generic.rs | 0 tests/ui/{unique => box/unit}/unique-assign.rs | 0 tests/ui/{unique => box/unit}/unique-autoderef-field.rs | 0 tests/ui/{unique => box/unit}/unique-autoderef-index.rs | 0 tests/ui/{unique => box/unit}/unique-cmp.rs | 0 tests/ui/{unique => box/unit}/unique-containing-tag.rs | 0 tests/ui/{unique => box/unit}/unique-create.rs | 0 tests/ui/{unique => box/unit}/unique-decl-init-copy.rs | 0 tests/ui/{unique => box/unit}/unique-decl-init.rs | 0 tests/ui/{unique => box/unit}/unique-decl-move.rs | 0 tests/ui/{unique => box/unit}/unique-decl.rs | 0 tests/ui/{unique => box/unit}/unique-deref.rs | 0 tests/ui/{unique => box/unit}/unique-destructure.rs | 0 tests/ui/{unique => box/unit}/unique-drop-complex.rs | 0 tests/ui/{unique => box/unit}/unique-ffi-symbols.rs | 0 tests/ui/{unique => box/unit}/unique-fn-arg-move.rs | 0 tests/ui/{unique => box/unit}/unique-fn-arg-mut.rs | 0 tests/ui/{unique => box/unit}/unique-fn-arg.rs | 0 tests/ui/{unique => box/unit}/unique-fn-ret.rs | 0 tests/ui/{unique => box/unit}/unique-generic-assign.rs | 0 tests/ui/{unique => box/unit}/unique-in-tag.rs | 0 tests/ui/{unique => box/unit}/unique-in-vec-copy.rs | 0 tests/ui/{unique => box/unit}/unique-in-vec.rs | 0 tests/ui/{unique => box/unit}/unique-init.rs | 0 tests/ui/{unique => box/unit}/unique-kinds.rs | 0 tests/ui/{unique => box/unit}/unique-log.rs | 0 tests/ui/{unique => box/unit}/unique-match-discrim.rs | 0 tests/ui/{unique => box/unit}/unique-move-drop.rs | 0 tests/ui/{unique => box/unit}/unique-move-temp.rs | 0 tests/ui/{unique => box/unit}/unique-move.rs | 0 tests/ui/{unique => box/unit}/unique-mutable.rs | 0 tests/ui/{unique => box/unit}/unique-object-move.rs | 0 tests/ui/{unique => box/unit}/unique-object-noncopyable.rs | 0 tests/ui/{unique => box/unit}/unique-object-noncopyable.stderr | 0 tests/ui/{unique => box/unit}/unique-pat-2.rs | 0 tests/ui/{unique => box/unit}/unique-pat-3.rs | 0 tests/ui/{unique => box/unit}/unique-pat.rs | 0 tests/ui/{unique => box/unit}/unique-pinned-nocopy.rs | 0 tests/ui/{unique => box/unit}/unique-pinned-nocopy.stderr | 0 tests/ui/{unique => box/unit}/unique-rec.rs | 0 tests/ui/{unique => box/unit}/unique-send-2.rs | 0 tests/ui/{unique => box/unit}/unique-send.rs | 0 tests/ui/{unique => box/unit}/unique-swap.rs | 0 tests/ui/{unique => box/unit}/unwind-unique.rs | 0 49 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{unique => box/unit}/expr-block-generic-unique1.rs (100%) rename tests/ui/{unique => box/unit}/expr-block-generic-unique2.rs (100%) rename tests/ui/{unique => box/unit}/expr-if-unique.rs (100%) rename tests/ui/{unique => box/unit}/unique-assign-copy.rs (100%) rename tests/ui/{unique => box/unit}/unique-assign-drop.rs (100%) rename tests/ui/{unique => box/unit}/unique-assign-generic.rs (100%) rename tests/ui/{unique => box/unit}/unique-assign.rs (100%) rename tests/ui/{unique => box/unit}/unique-autoderef-field.rs (100%) rename tests/ui/{unique => box/unit}/unique-autoderef-index.rs (100%) rename tests/ui/{unique => box/unit}/unique-cmp.rs (100%) rename tests/ui/{unique => box/unit}/unique-containing-tag.rs (100%) rename tests/ui/{unique => box/unit}/unique-create.rs (100%) rename tests/ui/{unique => box/unit}/unique-decl-init-copy.rs (100%) rename tests/ui/{unique => box/unit}/unique-decl-init.rs (100%) rename tests/ui/{unique => box/unit}/unique-decl-move.rs (100%) rename tests/ui/{unique => box/unit}/unique-decl.rs (100%) rename tests/ui/{unique => box/unit}/unique-deref.rs (100%) rename tests/ui/{unique => box/unit}/unique-destructure.rs (100%) rename tests/ui/{unique => box/unit}/unique-drop-complex.rs (100%) rename tests/ui/{unique => box/unit}/unique-ffi-symbols.rs (100%) rename tests/ui/{unique => box/unit}/unique-fn-arg-move.rs (100%) rename tests/ui/{unique => box/unit}/unique-fn-arg-mut.rs (100%) rename tests/ui/{unique => box/unit}/unique-fn-arg.rs (100%) rename tests/ui/{unique => box/unit}/unique-fn-ret.rs (100%) rename tests/ui/{unique => box/unit}/unique-generic-assign.rs (100%) rename tests/ui/{unique => box/unit}/unique-in-tag.rs (100%) rename tests/ui/{unique => box/unit}/unique-in-vec-copy.rs (100%) rename tests/ui/{unique => box/unit}/unique-in-vec.rs (100%) rename tests/ui/{unique => box/unit}/unique-init.rs (100%) rename tests/ui/{unique => box/unit}/unique-kinds.rs (100%) rename tests/ui/{unique => box/unit}/unique-log.rs (100%) rename tests/ui/{unique => box/unit}/unique-match-discrim.rs (100%) rename tests/ui/{unique => box/unit}/unique-move-drop.rs (100%) rename tests/ui/{unique => box/unit}/unique-move-temp.rs (100%) rename tests/ui/{unique => box/unit}/unique-move.rs (100%) rename tests/ui/{unique => box/unit}/unique-mutable.rs (100%) rename tests/ui/{unique => box/unit}/unique-object-move.rs (100%) rename tests/ui/{unique => box/unit}/unique-object-noncopyable.rs (100%) rename tests/ui/{unique => box/unit}/unique-object-noncopyable.stderr (100%) rename tests/ui/{unique => box/unit}/unique-pat-2.rs (100%) rename tests/ui/{unique => box/unit}/unique-pat-3.rs (100%) rename tests/ui/{unique => box/unit}/unique-pat.rs (100%) rename tests/ui/{unique => box/unit}/unique-pinned-nocopy.rs (100%) rename tests/ui/{unique => box/unit}/unique-pinned-nocopy.stderr (100%) rename tests/ui/{unique => box/unit}/unique-rec.rs (100%) rename tests/ui/{unique => box/unit}/unique-send-2.rs (100%) rename tests/ui/{unique => box/unit}/unique-send.rs (100%) rename tests/ui/{unique => box/unit}/unique-swap.rs (100%) rename tests/ui/{unique => box/unit}/unwind-unique.rs (100%) diff --git a/tests/ui/unique/expr-block-generic-unique1.rs b/tests/ui/box/unit/expr-block-generic-unique1.rs similarity index 100% rename from tests/ui/unique/expr-block-generic-unique1.rs rename to tests/ui/box/unit/expr-block-generic-unique1.rs diff --git a/tests/ui/unique/expr-block-generic-unique2.rs b/tests/ui/box/unit/expr-block-generic-unique2.rs similarity index 100% rename from tests/ui/unique/expr-block-generic-unique2.rs rename to tests/ui/box/unit/expr-block-generic-unique2.rs diff --git a/tests/ui/unique/expr-if-unique.rs b/tests/ui/box/unit/expr-if-unique.rs similarity index 100% rename from tests/ui/unique/expr-if-unique.rs rename to tests/ui/box/unit/expr-if-unique.rs diff --git a/tests/ui/unique/unique-assign-copy.rs b/tests/ui/box/unit/unique-assign-copy.rs similarity index 100% rename from tests/ui/unique/unique-assign-copy.rs rename to tests/ui/box/unit/unique-assign-copy.rs diff --git a/tests/ui/unique/unique-assign-drop.rs b/tests/ui/box/unit/unique-assign-drop.rs similarity index 100% rename from tests/ui/unique/unique-assign-drop.rs rename to tests/ui/box/unit/unique-assign-drop.rs diff --git a/tests/ui/unique/unique-assign-generic.rs b/tests/ui/box/unit/unique-assign-generic.rs similarity index 100% rename from tests/ui/unique/unique-assign-generic.rs rename to tests/ui/box/unit/unique-assign-generic.rs diff --git a/tests/ui/unique/unique-assign.rs b/tests/ui/box/unit/unique-assign.rs similarity index 100% rename from tests/ui/unique/unique-assign.rs rename to tests/ui/box/unit/unique-assign.rs diff --git a/tests/ui/unique/unique-autoderef-field.rs b/tests/ui/box/unit/unique-autoderef-field.rs similarity index 100% rename from tests/ui/unique/unique-autoderef-field.rs rename to tests/ui/box/unit/unique-autoderef-field.rs diff --git a/tests/ui/unique/unique-autoderef-index.rs b/tests/ui/box/unit/unique-autoderef-index.rs similarity index 100% rename from tests/ui/unique/unique-autoderef-index.rs rename to tests/ui/box/unit/unique-autoderef-index.rs diff --git a/tests/ui/unique/unique-cmp.rs b/tests/ui/box/unit/unique-cmp.rs similarity index 100% rename from tests/ui/unique/unique-cmp.rs rename to tests/ui/box/unit/unique-cmp.rs diff --git a/tests/ui/unique/unique-containing-tag.rs b/tests/ui/box/unit/unique-containing-tag.rs similarity index 100% rename from tests/ui/unique/unique-containing-tag.rs rename to tests/ui/box/unit/unique-containing-tag.rs diff --git a/tests/ui/unique/unique-create.rs b/tests/ui/box/unit/unique-create.rs similarity index 100% rename from tests/ui/unique/unique-create.rs rename to tests/ui/box/unit/unique-create.rs diff --git a/tests/ui/unique/unique-decl-init-copy.rs b/tests/ui/box/unit/unique-decl-init-copy.rs similarity index 100% rename from tests/ui/unique/unique-decl-init-copy.rs rename to tests/ui/box/unit/unique-decl-init-copy.rs diff --git a/tests/ui/unique/unique-decl-init.rs b/tests/ui/box/unit/unique-decl-init.rs similarity index 100% rename from tests/ui/unique/unique-decl-init.rs rename to tests/ui/box/unit/unique-decl-init.rs diff --git a/tests/ui/unique/unique-decl-move.rs b/tests/ui/box/unit/unique-decl-move.rs similarity index 100% rename from tests/ui/unique/unique-decl-move.rs rename to tests/ui/box/unit/unique-decl-move.rs diff --git a/tests/ui/unique/unique-decl.rs b/tests/ui/box/unit/unique-decl.rs similarity index 100% rename from tests/ui/unique/unique-decl.rs rename to tests/ui/box/unit/unique-decl.rs diff --git a/tests/ui/unique/unique-deref.rs b/tests/ui/box/unit/unique-deref.rs similarity index 100% rename from tests/ui/unique/unique-deref.rs rename to tests/ui/box/unit/unique-deref.rs diff --git a/tests/ui/unique/unique-destructure.rs b/tests/ui/box/unit/unique-destructure.rs similarity index 100% rename from tests/ui/unique/unique-destructure.rs rename to tests/ui/box/unit/unique-destructure.rs diff --git a/tests/ui/unique/unique-drop-complex.rs b/tests/ui/box/unit/unique-drop-complex.rs similarity index 100% rename from tests/ui/unique/unique-drop-complex.rs rename to tests/ui/box/unit/unique-drop-complex.rs diff --git a/tests/ui/unique/unique-ffi-symbols.rs b/tests/ui/box/unit/unique-ffi-symbols.rs similarity index 100% rename from tests/ui/unique/unique-ffi-symbols.rs rename to tests/ui/box/unit/unique-ffi-symbols.rs diff --git a/tests/ui/unique/unique-fn-arg-move.rs b/tests/ui/box/unit/unique-fn-arg-move.rs similarity index 100% rename from tests/ui/unique/unique-fn-arg-move.rs rename to tests/ui/box/unit/unique-fn-arg-move.rs diff --git a/tests/ui/unique/unique-fn-arg-mut.rs b/tests/ui/box/unit/unique-fn-arg-mut.rs similarity index 100% rename from tests/ui/unique/unique-fn-arg-mut.rs rename to tests/ui/box/unit/unique-fn-arg-mut.rs diff --git a/tests/ui/unique/unique-fn-arg.rs b/tests/ui/box/unit/unique-fn-arg.rs similarity index 100% rename from tests/ui/unique/unique-fn-arg.rs rename to tests/ui/box/unit/unique-fn-arg.rs diff --git a/tests/ui/unique/unique-fn-ret.rs b/tests/ui/box/unit/unique-fn-ret.rs similarity index 100% rename from tests/ui/unique/unique-fn-ret.rs rename to tests/ui/box/unit/unique-fn-ret.rs diff --git a/tests/ui/unique/unique-generic-assign.rs b/tests/ui/box/unit/unique-generic-assign.rs similarity index 100% rename from tests/ui/unique/unique-generic-assign.rs rename to tests/ui/box/unit/unique-generic-assign.rs diff --git a/tests/ui/unique/unique-in-tag.rs b/tests/ui/box/unit/unique-in-tag.rs similarity index 100% rename from tests/ui/unique/unique-in-tag.rs rename to tests/ui/box/unit/unique-in-tag.rs diff --git a/tests/ui/unique/unique-in-vec-copy.rs b/tests/ui/box/unit/unique-in-vec-copy.rs similarity index 100% rename from tests/ui/unique/unique-in-vec-copy.rs rename to tests/ui/box/unit/unique-in-vec-copy.rs diff --git a/tests/ui/unique/unique-in-vec.rs b/tests/ui/box/unit/unique-in-vec.rs similarity index 100% rename from tests/ui/unique/unique-in-vec.rs rename to tests/ui/box/unit/unique-in-vec.rs diff --git a/tests/ui/unique/unique-init.rs b/tests/ui/box/unit/unique-init.rs similarity index 100% rename from tests/ui/unique/unique-init.rs rename to tests/ui/box/unit/unique-init.rs diff --git a/tests/ui/unique/unique-kinds.rs b/tests/ui/box/unit/unique-kinds.rs similarity index 100% rename from tests/ui/unique/unique-kinds.rs rename to tests/ui/box/unit/unique-kinds.rs diff --git a/tests/ui/unique/unique-log.rs b/tests/ui/box/unit/unique-log.rs similarity index 100% rename from tests/ui/unique/unique-log.rs rename to tests/ui/box/unit/unique-log.rs diff --git a/tests/ui/unique/unique-match-discrim.rs b/tests/ui/box/unit/unique-match-discrim.rs similarity index 100% rename from tests/ui/unique/unique-match-discrim.rs rename to tests/ui/box/unit/unique-match-discrim.rs diff --git a/tests/ui/unique/unique-move-drop.rs b/tests/ui/box/unit/unique-move-drop.rs similarity index 100% rename from tests/ui/unique/unique-move-drop.rs rename to tests/ui/box/unit/unique-move-drop.rs diff --git a/tests/ui/unique/unique-move-temp.rs b/tests/ui/box/unit/unique-move-temp.rs similarity index 100% rename from tests/ui/unique/unique-move-temp.rs rename to tests/ui/box/unit/unique-move-temp.rs diff --git a/tests/ui/unique/unique-move.rs b/tests/ui/box/unit/unique-move.rs similarity index 100% rename from tests/ui/unique/unique-move.rs rename to tests/ui/box/unit/unique-move.rs diff --git a/tests/ui/unique/unique-mutable.rs b/tests/ui/box/unit/unique-mutable.rs similarity index 100% rename from tests/ui/unique/unique-mutable.rs rename to tests/ui/box/unit/unique-mutable.rs diff --git a/tests/ui/unique/unique-object-move.rs b/tests/ui/box/unit/unique-object-move.rs similarity index 100% rename from tests/ui/unique/unique-object-move.rs rename to tests/ui/box/unit/unique-object-move.rs diff --git a/tests/ui/unique/unique-object-noncopyable.rs b/tests/ui/box/unit/unique-object-noncopyable.rs similarity index 100% rename from tests/ui/unique/unique-object-noncopyable.rs rename to tests/ui/box/unit/unique-object-noncopyable.rs diff --git a/tests/ui/unique/unique-object-noncopyable.stderr b/tests/ui/box/unit/unique-object-noncopyable.stderr similarity index 100% rename from tests/ui/unique/unique-object-noncopyable.stderr rename to tests/ui/box/unit/unique-object-noncopyable.stderr diff --git a/tests/ui/unique/unique-pat-2.rs b/tests/ui/box/unit/unique-pat-2.rs similarity index 100% rename from tests/ui/unique/unique-pat-2.rs rename to tests/ui/box/unit/unique-pat-2.rs diff --git a/tests/ui/unique/unique-pat-3.rs b/tests/ui/box/unit/unique-pat-3.rs similarity index 100% rename from tests/ui/unique/unique-pat-3.rs rename to tests/ui/box/unit/unique-pat-3.rs diff --git a/tests/ui/unique/unique-pat.rs b/tests/ui/box/unit/unique-pat.rs similarity index 100% rename from tests/ui/unique/unique-pat.rs rename to tests/ui/box/unit/unique-pat.rs diff --git a/tests/ui/unique/unique-pinned-nocopy.rs b/tests/ui/box/unit/unique-pinned-nocopy.rs similarity index 100% rename from tests/ui/unique/unique-pinned-nocopy.rs rename to tests/ui/box/unit/unique-pinned-nocopy.rs diff --git a/tests/ui/unique/unique-pinned-nocopy.stderr b/tests/ui/box/unit/unique-pinned-nocopy.stderr similarity index 100% rename from tests/ui/unique/unique-pinned-nocopy.stderr rename to tests/ui/box/unit/unique-pinned-nocopy.stderr diff --git a/tests/ui/unique/unique-rec.rs b/tests/ui/box/unit/unique-rec.rs similarity index 100% rename from tests/ui/unique/unique-rec.rs rename to tests/ui/box/unit/unique-rec.rs diff --git a/tests/ui/unique/unique-send-2.rs b/tests/ui/box/unit/unique-send-2.rs similarity index 100% rename from tests/ui/unique/unique-send-2.rs rename to tests/ui/box/unit/unique-send-2.rs diff --git a/tests/ui/unique/unique-send.rs b/tests/ui/box/unit/unique-send.rs similarity index 100% rename from tests/ui/unique/unique-send.rs rename to tests/ui/box/unit/unique-send.rs diff --git a/tests/ui/unique/unique-swap.rs b/tests/ui/box/unit/unique-swap.rs similarity index 100% rename from tests/ui/unique/unique-swap.rs rename to tests/ui/box/unit/unique-swap.rs diff --git a/tests/ui/unique/unwind-unique.rs b/tests/ui/box/unit/unwind-unique.rs similarity index 100% rename from tests/ui/unique/unwind-unique.rs rename to tests/ui/box/unit/unwind-unique.rs From 955ba37aa597843abe5171fd80079f4f456785fb Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 11 Apr 2023 17:14:53 +1000 Subject: [PATCH 188/272] Remove the unused `anon_num_here` error. --- compiler/rustc_infer/messages.ftl | 1 - compiler/rustc_infer/src/errors/note_and_explain.rs | 2 -- 2 files changed, 3 deletions(-) diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index 4d4a7880b001..1ae53182046f 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -163,7 +163,6 @@ infer_region_explanation = {$pref_kind -> [as_defined] the lifetime `{$desc_arg}` as defined here [as_defined_anon] the anonymous lifetime as defined here [defined_here] the anonymous lifetime defined here - [anon_num_here] the anonymous lifetime #{$desc_num_arg} defined here [defined_here_reg] the lifetime `{$desc_arg}` as defined here }{$suff_kind -> *[should_not_happen] [{$suff_kind}] diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index 30f6af74b83e..744fb27635aa 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -9,7 +9,6 @@ struct DescriptionCtx<'a> { span: Option, kind: &'a str, arg: String, - num_arg: u32, } impl<'a> DescriptionCtx<'a> { @@ -113,7 +112,6 @@ impl<'a> DescriptionCtx<'a> { fn add_to(self, diag: &mut rustc_errors::Diagnostic) { diag.set_arg("desc_kind", self.kind); diag.set_arg("desc_arg", self.arg); - diag.set_arg("desc_num_arg", self.num_arg); } } From 171f5414705194067557cd7b70bd680308b9cced Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 11 Apr 2023 10:25:49 +0200 Subject: [PATCH 189/272] don't uniquify regions when canonicalizing --- .../src/solve/canonicalize.rs | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs index 55025e2e72b9..479f25298701 100644 --- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs +++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs @@ -125,8 +125,9 @@ impl<'a, 'tcx> Canonicalizer<'a, 'tcx> { // - var_infos: [E0, U1, E1, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 6 // - var_infos: [E0, U1, E1, U1, E1, E2, U2], curr_compressed_uv: 2, next_orig_uv: - // - // This algorithm runs in `O(n²)` where `n` is the number of different universe - // indices in the input. This should be fine as `n` is expected to be small. + // This algorithm runs in `O(nm)` where `n` is the number of different universe + // indices in the input and `m` is the number of canonical variables. + // This should be fine as both `n` and `m` are expected to be small. let mut curr_compressed_uv = ty::UniverseIndex::ROOT; let mut existential_in_new_uv = false; let mut next_orig_uv = Some(ty::UniverseIndex::ROOT); @@ -245,18 +246,14 @@ impl<'tcx> TypeFolder> for Canonicalizer<'_, 'tcx> { ty::ReError(_) => return r, }; - let existing_bound_var = match self.canonicalize_mode { - CanonicalizeMode::Input => None, - CanonicalizeMode::Response { .. } => { - self.variables.iter().position(|&v| v == r.into()).map(ty::BoundVar::from) - } - }; - let var = existing_bound_var.unwrap_or_else(|| { - let var = ty::BoundVar::from(self.variables.len()); - self.variables.push(r.into()); - self.primitive_var_infos.push(CanonicalVarInfo { kind }); - var - }); + let var = ty::BoundVar::from( + self.variables.iter().position(|&v| v == r.into()).unwrap_or_else(|| { + let var = self.variables.len(); + self.variables.push(r.into()); + self.primitive_var_infos.push(CanonicalVarInfo { kind }); + var + }), + ); let br = ty::BoundRegion { var, kind: BrAnon(None) }; self.interner().mk_re_late_bound(self.binder_index, br) } From 43e6f99b9d3f8b4af3373b7c5fab6718410e8cc1 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 11 Apr 2023 10:27:57 +0200 Subject: [PATCH 190/272] remove issue-2718.rs test this test was added for rust 0.4 and doesn't test anything specific. The repro originally relied on extern functions which are now just ordinary methods. It's also a run pass test even though `main` has been commented out. --- tests/ui/regions/issue-2718.rs | 327 --------------------------------- 1 file changed, 327 deletions(-) delete mode 100644 tests/ui/regions/issue-2718.rs diff --git a/tests/ui/regions/issue-2718.rs b/tests/ui/regions/issue-2718.rs deleted file mode 100644 index 6449337eea4e..000000000000 --- a/tests/ui/regions/issue-2718.rs +++ /dev/null @@ -1,327 +0,0 @@ -// run-pass -#![allow(dead_code)] -#![allow(unused_unsafe)] -#![allow(unused_imports)] -#![allow(non_camel_case_types)] - -pub type Task = isize; - -// tjc: I don't know why -pub mod pipes { - use self::state::{empty, full, blocked, terminated}; - use super::Task; - use std::mem::{forget, transmute}; - use std::mem::{replace, swap}; - use std::mem; - use std::thread; - use std::marker::Send; - - pub struct Stuff { - state: state, - blocked_task: Option, - payload: Option - } - - #[derive(PartialEq, Debug)] - #[repr(isize)] - pub enum state { - empty, - full, - blocked, - terminated - } - - pub struct packet { - state: state, - blocked_task: Option, - payload: Option - } - - unsafe impl Send for packet {} - - pub fn packet() -> *const packet { - unsafe { - let p: *const packet = mem::transmute(Box::new(Stuff{ - state: empty, - blocked_task: None::, - payload: None:: - })); - p - } - } - - mod rusti { - pub fn atomic_xchg(_dst: &mut isize, _src: isize) -> isize { panic!(); } - pub fn atomic_xchg_acq(_dst: &mut isize, _src: isize) -> isize { panic!(); } - pub fn atomic_xchg_rel(_dst: &mut isize, _src: isize) -> isize { panic!(); } - } - - // We should consider moving this to ::std::unsafe, although I - // suspect graydon would want us to use void pointers instead. - pub unsafe fn uniquify(x: *const T) -> Box { - mem::transmute(x) - } - - pub fn swap_state_acq(dst: &mut state, src: state) -> state { - unsafe { - transmute(rusti::atomic_xchg_acq(transmute(dst), src as isize)) - } - } - - pub fn swap_state_rel(dst: &mut state, src: state) -> state { - unsafe { - transmute(rusti::atomic_xchg_rel(transmute(dst), src as isize)) - } - } - - pub fn send(mut p: send_packet, payload: T) { - let p = p.unwrap(); - let mut p = unsafe { uniquify(p) }; - assert!((*p).payload.is_none()); - (*p).payload = Some(payload); - let old_state = swap_state_rel(&mut (*p).state, full); - match old_state { - empty => { - // Yay, fastpath. - - // The receiver will eventually clean this up. - unsafe { forget(p); } - } - full => { panic!("duplicate send") } - blocked => { - - // The receiver will eventually clean this up. - unsafe { forget(p); } - } - terminated => { - // The receiver will never receive this. Rely on drop_glue - // to clean everything up. - } - } - } - - pub fn recv(mut p: recv_packet) -> Option { - let p = p.unwrap(); - let mut p = unsafe { uniquify(p) }; - loop { - let old_state = swap_state_acq(&mut (*p).state, - blocked); - match old_state { - empty | blocked => { thread::yield_now(); } - full => { - let payload = replace(&mut p.payload, None); - return Some(payload.unwrap()) - } - terminated => { - assert_eq!(old_state, terminated); - return None; - } - } - } - } - - pub fn sender_terminate(p: *const packet) { - let mut p = unsafe { uniquify(p) }; - match swap_state_rel(&mut (*p).state, terminated) { - empty | blocked => { - // The receiver will eventually clean up. - unsafe { forget(p) } - } - full => { - // This is impossible - panic!("you dun goofed") - } - terminated => { - // I have to clean up, use drop_glue - } - } - } - - pub fn receiver_terminate(p: *const packet) { - let mut p = unsafe { uniquify(p) }; - match swap_state_rel(&mut (*p).state, terminated) { - empty => { - // the sender will clean up - unsafe { forget(p) } - } - blocked => { - // this shouldn't happen. - panic!("terminating a blocked packet") - } - terminated | full => { - // I have to clean up, use drop_glue - } - } - } - - pub struct send_packet { - p: Option<*const packet>, - } - - impl Drop for send_packet { - fn drop(&mut self) { - unsafe { - if self.p != None { - let self_p: &mut Option<*const packet> = - mem::transmute(&mut self.p); - let p = replace(self_p, None); - sender_terminate(p.unwrap()) - } - } - } - } - - impl send_packet { - pub fn unwrap(&mut self) -> *const packet { - replace(&mut self.p, None).unwrap() - } - } - - pub fn send_packet(p: *const packet) -> send_packet { - send_packet { - p: Some(p) - } - } - - pub struct recv_packet { - p: Option<*const packet>, - } - - impl Drop for recv_packet { - fn drop(&mut self) { - unsafe { - if self.p != None { - let self_p: &mut Option<*const packet> = - mem::transmute(&mut self.p); - let p = replace(self_p, None); - receiver_terminate(p.unwrap()) - } - } - } - } - - impl recv_packet { - pub fn unwrap(&mut self) -> *const packet { - replace(&mut self.p, None).unwrap() - } - } - - pub fn recv_packet(p: *const packet) -> recv_packet { - recv_packet { - p: Some(p) - } - } - - pub fn entangle() -> (send_packet, recv_packet) { - let p = packet(); - (send_packet(p), recv_packet(p)) - } -} - -pub mod pingpong { - use std::mem; - - pub struct ping(::pipes::send_packet); - - unsafe impl Send for ping {} - - pub struct pong(::pipes::send_packet); - - unsafe impl Send for pong {} - - pub fn liberate_ping(p: ping) -> ::pipes::send_packet { - unsafe { - let _addr : *const ::pipes::send_packet = match &p { - &ping(ref x) => { mem::transmute(x) } - }; - panic!() - } - } - - pub fn liberate_pong(p: pong) -> ::pipes::send_packet { - unsafe { - let _addr : *const ::pipes::send_packet = match &p { - &pong(ref x) => { mem::transmute(x) } - }; - panic!() - } - } - - pub fn init() -> (client::ping, server::ping) { - ::pipes::entangle() - } - - pub mod client { - use pingpong; - - pub type ping = ::pipes::send_packet; - pub type pong = ::pipes::recv_packet; - - pub fn do_ping(c: ping) -> pong { - let (sp, rp) = ::pipes::entangle(); - - ::pipes::send(c, pingpong::ping(sp)); - rp - } - - pub fn do_pong(c: pong) -> (ping, ()) { - let packet = ::pipes::recv(c); - if packet.is_none() { - panic!("sender closed the connection") - } - (pingpong::liberate_pong(packet.unwrap()), ()) - } - } - - pub mod server { - use pingpong; - - pub type ping = ::pipes::recv_packet; - pub type pong = ::pipes::send_packet; - - pub fn do_ping(c: ping) -> (pong, ()) { - let packet = ::pipes::recv(c); - if packet.is_none() { - panic!("sender closed the connection") - } - (pingpong::liberate_ping(packet.unwrap()), ()) - } - - pub fn do_pong(c: pong) -> ping { - let (sp, rp) = ::pipes::entangle(); - ::pipes::send(c, pingpong::pong(sp)); - rp - } - } -} - -fn client(chan: pingpong::client::ping) { - let chan = pingpong::client::do_ping(chan); - println!("Sent ping"); - let (_chan, _data) = pingpong::client::do_pong(chan); - println!("Received pong"); -} - -fn server(chan: pingpong::server::ping) { - let (chan, _data) = pingpong::server::do_ping(chan); - println!("Received ping"); - let _chan = pingpong::server::do_pong(chan); - println!("Sent pong"); -} - -pub fn main() { - /* -// Commented out because of option::get error - - let (client_, server_) = pingpong::init(); - - task::spawn {|client_| - let client__ = client_.take(); - client(client__); - }; - task::spawn {|server_| - let server__ = server_.take(); - server(server_ˊ); - }; - */ -} From 9e70541eacf60f8ed0b38d7b62315cd730a00821 Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Tue, 11 Apr 2023 21:07:02 +1200 Subject: [PATCH 191/272] refactor: extract `not_testable_error` into function --- compiler/rustc_builtin_macros/src/test.rs | 64 +++++++++++------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 9a50999faa0d..79d8be2484b5 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -107,36 +107,6 @@ pub fn expand_test_or_bench( return vec![]; } - let not_testable_error = |item: Option<&ast::Item>| { - let diag = &cx.sess.parse_sess.span_diagnostic; - let msg = "the `#[test]` attribute may only be used on a non-associated function"; - let mut err = match item.map(|i| &i.kind) { - // These were a warning before #92959 and need to continue being that to avoid breaking - // stable user code (#94508). - Some(ast::ItemKind::MacCall(_)) => diag.struct_span_warn(attr_sp, msg), - // `.forget_guarantee()` needed to get these two arms to match types. Because of how - // locally close the `.emit()` call is I'm comfortable with it, but if it can be - // reworked in the future to not need it, it'd be nice. - _ => diag.struct_span_err(attr_sp, msg).forget_guarantee(), - }; - if let Some(item) = item { - err.span_label( - item.span, - format!( - "expected a non-associated function, found {} {}", - item.kind.article(), - item.kind.descr() - ), - ); - } - err.span_label(attr_sp, "the `#[test]` macro causes a function to be run as a test and has no effect on non-functions") - .span_suggestion(attr_sp, - "replace with conditional compilation to make the item only exist when tests are being run", - "#[cfg(test)]", - Applicability::MaybeIncorrect) - .emit(); - }; - let (item, is_stmt) = match item { Annotatable::Item(i) => (i, false), Annotatable::Stmt(stmt) if matches!(stmt.kind, ast::StmtKind::Item(_)) => { @@ -148,13 +118,13 @@ pub fn expand_test_or_bench( } } other => { - not_testable_error(None); + not_testable_error(cx, attr_sp, None); return vec![other]; } }; let ast::ItemKind::Fn(fn_) = &item.kind else { - not_testable_error(Some(&item)); + not_testable_error(cx, attr_sp, Some(&item)); return if is_stmt { vec![Annotatable::Stmt(P(ast::Stmt { id: ast::DUMMY_NODE_ID, @@ -416,6 +386,36 @@ pub fn expand_test_or_bench( } } +fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) { + let diag = &cx.sess.parse_sess.span_diagnostic; + let msg = "the `#[test]` attribute may only be used on a non-associated function"; + let mut err = match item.map(|i| &i.kind) { + // These were a warning before #92959 and need to continue being that to avoid breaking + // stable user code (#94508). + Some(ast::ItemKind::MacCall(_)) => diag.struct_span_warn(attr_sp, msg), + // `.forget_guarantee()` needed to get these two arms to match types. Because of how + // locally close the `.emit()` call is I'm comfortable with it, but if it can be + // reworked in the future to not need it, it'd be nice. + _ => diag.struct_span_err(attr_sp, msg).forget_guarantee(), + }; + if let Some(item) = item { + err.span_label( + item.span, + format!( + "expected a non-associated function, found {} {}", + item.kind.article(), + item.kind.descr() + ), + ); + } + err.span_label(attr_sp, "the `#[test]` macro causes a function to be run as a test and has no effect on non-functions") + .span_suggestion(attr_sp, + "replace with conditional compilation to make the item only exist when tests are being run", + "#[cfg(test)]", + Applicability::MaybeIncorrect) + .emit(); +} + fn get_location_info(cx: &ExtCtxt<'_>, item: &ast::Item) -> (Symbol, usize, usize, usize, usize) { let span = item.ident.span; let (source_file, lo_line, lo_col, hi_line, hi_col) = From ec635c002b99371c1c45d98df0e5664bdb57a644 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 11 Apr 2023 11:22:15 +0200 Subject: [PATCH 192/272] Add ignore-debug to two tests These don't optimize with debug assertions. For one of them, this is due to the new alignment checks, for the other I'm not sure what specifically blocks it. --- tests/codegen/issues/issue-101082.rs | 1 + tests/codegen/issues/issue-101814.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/codegen/issues/issue-101082.rs b/tests/codegen/issues/issue-101082.rs index effe8f4a60e3..27387d0c1192 100644 --- a/tests/codegen/issues/issue-101082.rs +++ b/tests/codegen/issues/issue-101082.rs @@ -1,5 +1,6 @@ // compile-flags: -O // min-llvm-version: 16 +// ignore-debug: the debug assertions get in the way #![crate_type = "lib"] diff --git a/tests/codegen/issues/issue-101814.rs b/tests/codegen/issues/issue-101814.rs index 4e4745ed633d..13796352c028 100644 --- a/tests/codegen/issues/issue-101814.rs +++ b/tests/codegen/issues/issue-101814.rs @@ -1,5 +1,6 @@ // compile-flags: -O // min-llvm-version: 16 +// ignore-debug: the debug assertions get in the way #![crate_type = "lib"] From 0465201f772bf74e57885cfa64817314ac8c743b Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 11 Apr 2023 10:54:56 +0000 Subject: [PATCH 193/272] Use `itertools::Either` instead of own `EitherIter` impl --- Cargo.lock | 1 + compiler/rustc_data_structures/Cargo.toml | 1 + .../src/sso/either_iter.rs | 73 ------------------- compiler/rustc_data_structures/src/sso/map.rs | 36 ++++----- compiler/rustc_data_structures/src/sso/mod.rs | 1 - 5 files changed, 20 insertions(+), 92 deletions(-) delete mode 100644 compiler/rustc_data_structures/src/sso/either_iter.rs diff --git a/Cargo.lock b/Cargo.lock index 6dd6fbe71b83..5f89f5e4a57e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4575,6 +4575,7 @@ dependencies = [ "elsa", "ena", "indexmap", + "itertools", "jobserver", "libc", "measureme", diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 24b6b5cfb1f7..2102f09c56a0 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -33,6 +33,7 @@ tempfile = "3.2" thin-vec = "0.2.12" tracing = "0.1" elsa = "=1.7.1" +itertools = "0.10.1" [dependencies.parking_lot] version = "0.11" diff --git a/compiler/rustc_data_structures/src/sso/either_iter.rs b/compiler/rustc_data_structures/src/sso/either_iter.rs deleted file mode 100644 index bca6c0955b90..000000000000 --- a/compiler/rustc_data_structures/src/sso/either_iter.rs +++ /dev/null @@ -1,73 +0,0 @@ -use std::fmt; -use std::iter::FusedIterator; - -/// Iterator which may contain instance of -/// one of two specific implementations. -/// -/// Note: For most methods providing custom -/// implementation may marginally -/// improve performance by avoiding -/// doing Left/Right match on every step -/// and doing it only once instead. -#[derive(Clone)] -pub enum EitherIter { - Left(L), - Right(R), -} - -impl Iterator for EitherIter -where - L: Iterator, - R: Iterator, -{ - type Item = L::Item; - - fn next(&mut self) -> Option { - match self { - EitherIter::Left(l) => l.next(), - EitherIter::Right(r) => r.next(), - } - } - - fn size_hint(&self) -> (usize, Option) { - match self { - EitherIter::Left(l) => l.size_hint(), - EitherIter::Right(r) => r.size_hint(), - } - } -} - -impl ExactSizeIterator for EitherIter -where - L: ExactSizeIterator, - R: ExactSizeIterator, - EitherIter: Iterator, -{ - fn len(&self) -> usize { - match self { - EitherIter::Left(l) => l.len(), - EitherIter::Right(r) => r.len(), - } - } -} - -impl FusedIterator for EitherIter -where - L: FusedIterator, - R: FusedIterator, - EitherIter: Iterator, -{ -} - -impl fmt::Debug for EitherIter -where - L: fmt::Debug, - R: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - EitherIter::Left(l) => l.fmt(f), - EitherIter::Right(r) => r.fmt(f), - } - } -} diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs index 7cdac5819771..f9e2dfd16d5c 100644 --- a/compiler/rustc_data_structures/src/sso/map.rs +++ b/compiler/rustc_data_structures/src/sso/map.rs @@ -1,6 +1,6 @@ -use super::either_iter::EitherIter; use crate::fx::FxHashMap; use arrayvec::ArrayVec; +use itertools::Either; use std::fmt; use std::hash::Hash; use std::ops::Index; @@ -138,8 +138,8 @@ impl SsoHashMap { /// The iterator element type is `&'a K`. pub fn keys(&self) -> impl Iterator { match self { - SsoHashMap::Array(array) => EitherIter::Left(array.iter().map(|(k, _v)| k)), - SsoHashMap::Map(map) => EitherIter::Right(map.keys()), + SsoHashMap::Array(array) => Either::Left(array.iter().map(|(k, _v)| k)), + SsoHashMap::Map(map) => Either::Right(map.keys()), } } @@ -147,8 +147,8 @@ impl SsoHashMap { /// The iterator element type is `&'a V`. pub fn values(&self) -> impl Iterator { match self { - SsoHashMap::Array(array) => EitherIter::Left(array.iter().map(|(_k, v)| v)), - SsoHashMap::Map(map) => EitherIter::Right(map.values()), + SsoHashMap::Array(array) => Either::Left(array.iter().map(|(_k, v)| v)), + SsoHashMap::Map(map) => Either::Right(map.values()), } } @@ -156,8 +156,8 @@ impl SsoHashMap { /// The iterator element type is `&'a mut V`. pub fn values_mut(&mut self) -> impl Iterator { match self { - SsoHashMap::Array(array) => EitherIter::Left(array.iter_mut().map(|(_k, v)| v)), - SsoHashMap::Map(map) => EitherIter::Right(map.values_mut()), + SsoHashMap::Array(array) => Either::Left(array.iter_mut().map(|(_k, v)| v)), + SsoHashMap::Map(map) => Either::Right(map.values_mut()), } } @@ -165,8 +165,8 @@ impl SsoHashMap { /// allocated memory for reuse. pub fn drain(&mut self) -> impl Iterator + '_ { match self { - SsoHashMap::Array(array) => EitherIter::Left(array.drain(..)), - SsoHashMap::Map(map) => EitherIter::Right(map.drain()), + SsoHashMap::Array(array) => Either::Left(array.drain(..)), + SsoHashMap::Map(map) => Either::Right(map.drain()), } } } @@ -406,7 +406,7 @@ where } impl IntoIterator for SsoHashMap { - type IntoIter = EitherIter< + type IntoIter = Either< as IntoIterator>::IntoIter, as IntoIterator>::IntoIter, >; @@ -414,8 +414,8 @@ impl IntoIterator for SsoHashMap { fn into_iter(self) -> Self::IntoIter { match self { - SsoHashMap::Array(array) => EitherIter::Left(array.into_iter()), - SsoHashMap::Map(map) => EitherIter::Right(map.into_iter()), + SsoHashMap::Array(array) => Either::Left(array.into_iter()), + SsoHashMap::Map(map) => Either::Right(map.into_iter()), } } } @@ -435,7 +435,7 @@ fn adapt_array_mut_it(pair: &mut (K, V)) -> (&K, &mut V) { } impl<'a, K, V> IntoIterator for &'a SsoHashMap { - type IntoIter = EitherIter< + type IntoIter = Either< std::iter::Map< <&'a ArrayVec<(K, V), 8> as IntoIterator>::IntoIter, fn(&'a (K, V)) -> (&'a K, &'a V), @@ -446,14 +446,14 @@ impl<'a, K, V> IntoIterator for &'a SsoHashMap { fn into_iter(self) -> Self::IntoIter { match self { - SsoHashMap::Array(array) => EitherIter::Left(array.into_iter().map(adapt_array_ref_it)), - SsoHashMap::Map(map) => EitherIter::Right(map.iter()), + SsoHashMap::Array(array) => Either::Left(array.into_iter().map(adapt_array_ref_it)), + SsoHashMap::Map(map) => Either::Right(map.iter()), } } } impl<'a, K, V> IntoIterator for &'a mut SsoHashMap { - type IntoIter = EitherIter< + type IntoIter = Either< std::iter::Map< <&'a mut ArrayVec<(K, V), 8> as IntoIterator>::IntoIter, fn(&'a mut (K, V)) -> (&'a K, &'a mut V), @@ -464,8 +464,8 @@ impl<'a, K, V> IntoIterator for &'a mut SsoHashMap { fn into_iter(self) -> Self::IntoIter { match self { - SsoHashMap::Array(array) => EitherIter::Left(array.into_iter().map(adapt_array_mut_it)), - SsoHashMap::Map(map) => EitherIter::Right(map.iter_mut()), + SsoHashMap::Array(array) => Either::Left(array.into_iter().map(adapt_array_mut_it)), + SsoHashMap::Map(map) => Either::Right(map.iter_mut()), } } } diff --git a/compiler/rustc_data_structures/src/sso/mod.rs b/compiler/rustc_data_structures/src/sso/mod.rs index dd21bc8e6963..ef634b9adcec 100644 --- a/compiler/rustc_data_structures/src/sso/mod.rs +++ b/compiler/rustc_data_structures/src/sso/mod.rs @@ -1,4 +1,3 @@ -mod either_iter; mod map; mod set; From a32959263ca6b798fb02634d49e76c6abac41806 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 11 Apr 2023 10:56:35 +0000 Subject: [PATCH 194/272] Use `SSO_ARRAY_SIZE` instead of `8` in `SsoHashMap` impl --- compiler/rustc_data_structures/src/sso/map.rs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs index f9e2dfd16d5c..89b8c8526496 100644 --- a/compiler/rustc_data_structures/src/sso/map.rs +++ b/compiler/rustc_data_structures/src/sso/map.rs @@ -5,20 +5,20 @@ use std::fmt; use std::hash::Hash; use std::ops::Index; -// For pointer-sized arguments arrays -// are faster than set/map for up to 64 -// arguments. -// -// On the other hand such a big array -// hurts cache performance, makes passing -// sso structures around very expensive. -// -// Biggest performance benefit is gained -// for reasonably small arrays that stay -// small in vast majority of cases. -// -// '8' is chosen as a sane default, to be -// reevaluated later. +/// For pointer-sized arguments arrays +/// are faster than set/map for up to 64 +/// arguments. +/// +/// On the other hand such a big array +/// hurts cache performance, makes passing +/// sso structures around very expensive. +/// +/// Biggest performance benefit is gained +/// for reasonably small arrays that stay +/// small in vast majority of cases. +/// +/// '8' is chosen as a sane default, to be +/// reevaluated later. const SSO_ARRAY_SIZE: usize = 8; /// Small-storage-optimized implementation of a map. @@ -407,7 +407,7 @@ where impl IntoIterator for SsoHashMap { type IntoIter = Either< - as IntoIterator>::IntoIter, + as IntoIterator>::IntoIter, as IntoIterator>::IntoIter, >; type Item = ::Item; @@ -437,7 +437,7 @@ fn adapt_array_mut_it(pair: &mut (K, V)) -> (&K, &mut V) { impl<'a, K, V> IntoIterator for &'a SsoHashMap { type IntoIter = Either< std::iter::Map< - <&'a ArrayVec<(K, V), 8> as IntoIterator>::IntoIter, + <&'a ArrayVec<(K, V), SSO_ARRAY_SIZE> as IntoIterator>::IntoIter, fn(&'a (K, V)) -> (&'a K, &'a V), >, <&'a FxHashMap as IntoIterator>::IntoIter, @@ -455,7 +455,7 @@ impl<'a, K, V> IntoIterator for &'a SsoHashMap { impl<'a, K, V> IntoIterator for &'a mut SsoHashMap { type IntoIter = Either< std::iter::Map< - <&'a mut ArrayVec<(K, V), 8> as IntoIterator>::IntoIter, + <&'a mut ArrayVec<(K, V), SSO_ARRAY_SIZE> as IntoIterator>::IntoIter, fn(&'a mut (K, V)) -> (&'a K, &'a mut V), >, <&'a mut FxHashMap as IntoIterator>::IntoIter, From c37e72897ce8f55f753721541cf4b3ddb083cd7c Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Tue, 11 Apr 2023 14:04:50 +0200 Subject: [PATCH 195/272] rename maybe_delink to maybe_remove_mention --- src/tools/publish_toolstate.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index bad86701daed..2018c239ba06 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -86,7 +86,7 @@ def gh_url(): return os.environ['TOOLSTATE_ISSUES_API_URL'] -def maybe_unlink(message): +def maybe_remove_mention(message): # type: (str) -> str if os.environ.get('TOOLSTATE_SKIP_MENTIONS') is not None: return message.replace("@", "") @@ -109,7 +109,7 @@ def issue( else: status_description = 'no longer builds' request = json.dumps({ - 'body': maybe_unlink(textwrap.dedent('''\ + 'body': maybe_remove_mention(textwrap.dedent('''\ Hello, this is your friendly neighborhood mergebot. After merging PR {}, I observed that the tool {} {}. A follow-up PR to the repository {} is needed to fix the fallout. @@ -285,7 +285,7 @@ try: issue_url = gh_url() + '/{}/comments'.format(number) response = urllib2.urlopen(urllib2.Request( issue_url, - json.dumps({'body': maybe_unlink(message)}).encode(), + json.dumps({'body': maybe_remove_mention(message)}).encode(), { 'Authorization': 'token ' + github_token, 'Content-Type': 'application/json', From a11053ae087503be1b0f23331e320aca1c621cee Mon Sep 17 00:00:00 2001 From: nils <48135649+Nilstrieb@users.noreply.github.com> Date: Tue, 11 Apr 2023 14:14:02 +0200 Subject: [PATCH 196/272] Remove orphaned remove_dir_all implementation from rust-installer I have no idea why it's here, but it's not used at all. --- Cargo.lock | 2 - src/tools/rust-installer/Cargo.toml | 4 - .../rust-installer/src/remove_dir_all.rs | 860 ------------------ 3 files changed, 866 deletions(-) delete mode 100644 src/tools/rust-installer/src/remove_dir_all.rs diff --git a/Cargo.lock b/Cargo.lock index d9e9ef9fb0ff..ae12bbd8789e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2774,13 +2774,11 @@ dependencies = [ "anyhow", "clap 3.2.20", "flate2", - "lazy_static", "num_cpus", "rayon", "remove_dir_all", "tar", "walkdir", - "winapi", "xz2", ] diff --git a/src/tools/rust-installer/Cargo.toml b/src/tools/rust-installer/Cargo.toml index 788e556b0c64..97734f048ab3 100644 --- a/src/tools/rust-installer/Cargo.toml +++ b/src/tools/rust-installer/Cargo.toml @@ -22,7 +22,3 @@ remove_dir_all = "0.5" [dependencies.clap] features = ["derive"] version = "3.1" - -[target."cfg(windows)".dependencies] -lazy_static = "1" -winapi = { version = "0.3", features = ["errhandlingapi", "handleapi", "ioapiset", "winerror", "winioctl", "winnt"] } diff --git a/src/tools/rust-installer/src/remove_dir_all.rs b/src/tools/rust-installer/src/remove_dir_all.rs deleted file mode 100644 index 11097652865c..000000000000 --- a/src/tools/rust-installer/src/remove_dir_all.rs +++ /dev/null @@ -1,860 +0,0 @@ -#![allow(non_snake_case)] - -use std::io; -use std::path::Path; - -#[cfg(not(windows))] -pub fn remove_dir_all(path: &Path) -> io::Result<()> { - ::std::fs::remove_dir_all(path) -} - -#[cfg(windows)] -pub fn remove_dir_all(path: &Path) -> io::Result<()> { - win::remove_dir_all(path) -} - -#[cfg(windows)] -mod win { - use winapi::ctypes::{c_uint, c_ushort}; - use winapi::shared::minwindef::{BOOL, DWORD, FALSE, FILETIME, LPVOID}; - use winapi::shared::winerror::{ - ERROR_CALL_NOT_IMPLEMENTED, ERROR_INSUFFICIENT_BUFFER, ERROR_NO_MORE_FILES, - }; - use winapi::um::errhandlingapi::{GetLastError, SetLastError}; - use winapi::um::fileapi::{ - CreateFileW, FindFirstFileW, FindNextFileW, GetFileInformationByHandle, - }; - use winapi::um::fileapi::{BY_HANDLE_FILE_INFORMATION, CREATE_ALWAYS, CREATE_NEW}; - use winapi::um::fileapi::{FILE_BASIC_INFO, FILE_RENAME_INFO, TRUNCATE_EXISTING}; - use winapi::um::fileapi::{OPEN_ALWAYS, OPEN_EXISTING}; - use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE}; - use winapi::um::ioapiset::DeviceIoControl; - use winapi::um::libloaderapi::{GetModuleHandleW, GetProcAddress}; - use winapi::um::minwinbase::{ - FileBasicInfo, FileRenameInfo, FILE_INFO_BY_HANDLE_CLASS, WIN32_FIND_DATAW, - }; - use winapi::um::winbase::SECURITY_SQOS_PRESENT; - use winapi::um::winbase::{ - FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_DELETE_ON_CLOSE, FILE_FLAG_OPEN_REPARSE_POINT, - }; - use winapi::um::winioctl::FSCTL_GET_REPARSE_POINT; - use winapi::um::winnt::{DELETE, FILE_ATTRIBUTE_DIRECTORY, HANDLE, LPCWSTR}; - use winapi::um::winnt::{FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_REPARSE_POINT}; - use winapi::um::winnt::{FILE_GENERIC_WRITE, FILE_WRITE_DATA, GENERIC_READ, GENERIC_WRITE}; - use winapi::um::winnt::{FILE_READ_ATTRIBUTES, FILE_WRITE_ATTRIBUTES}; - use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE}; - use winapi::um::winnt::{IO_REPARSE_TAG_MOUNT_POINT, IO_REPARSE_TAG_SYMLINK, LARGE_INTEGER}; - - use std::ffi::{OsStr, OsString}; - use std::io; - use std::mem; - use std::os::windows::ffi::{OsStrExt, OsStringExt}; - use std::path::{Path, PathBuf}; - use std::ptr; - use std::sync::Arc; - - pub fn remove_dir_all(path: &Path) -> io::Result<()> { - // On Windows it is not enough to just recursively remove the contents of a - // directory and then the directory itself. Deleting does not happen - // instantaneously, but is scheduled. - // To work around this, we move the file or directory to some `base_dir` - // right before deletion to avoid races. - // - // As `base_dir` we choose the parent dir of the directory we want to - // remove. We very probably have permission to create files here, as we - // already need write permission in this dir to delete the directory. And it - // should be on the same volume. - // - // To handle files with names like `CON` and `morse .. .`, and when a - // directory structure is so deep it needs long path names the path is first - // converted to a `//?/`-path with `get_path()`. - // - // To make sure we don't leave a moved file laying around if the process - // crashes before we can delete the file, we do all operations on an file - // handle. By opening a file with `FILE_FLAG_DELETE_ON_CLOSE` Windows will - // always delete the file when the handle closes. - // - // All files are renamed to be in the `base_dir`, and have their name - // changed to "rm-". After every rename the counter is increased. - // Rename should not overwrite possibly existing files in the base dir. So - // if it fails with `AlreadyExists`, we just increase the counter and try - // again. - // - // For read-only files and directories we first have to remove the read-only - // attribute before we can move or delete them. This also removes the - // attribute from possible hardlinks to the file, so just before closing we - // restore the read-only attribute. - // - // If 'path' points to a directory symlink or junction we should not - // recursively remove the target of the link, but only the link itself. - // - // Moving and deleting is guaranteed to succeed if we are able to open the - // file with `DELETE` permission. If others have the file open we only have - // `DELETE` permission if they have specified `FILE_SHARE_DELETE`. We can - // also delete the file now, but it will not disappear until all others have - // closed the file. But no-one can open the file after we have flagged it - // for deletion. - - // Open the path once to get the canonical path, file type and attributes. - let (path, metadata) = { - let mut opts = OpenOptions::new(); - opts.access_mode(FILE_READ_ATTRIBUTES); - opts.custom_flags(FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT); - let file = File::open(path, &opts)?; - (get_path(&file)?, file.file_attr()?) - }; - - let mut ctx = RmdirContext { - base_dir: match path.parent() { - Some(dir) => dir, - None => { - return Err(io::Error::new( - io::ErrorKind::PermissionDenied, - "can't delete root directory", - )) - } - }, - readonly: metadata.perm().readonly(), - counter: 0, - }; - - let filetype = metadata.file_type(); - if filetype.is_dir() { - remove_dir_all_recursive(path.as_ref(), &mut ctx) - } else if filetype.is_symlink_dir() { - remove_item(path.as_ref(), &mut ctx) - } else { - Err(io::Error::new( - io::ErrorKind::PermissionDenied, - "Not a directory", - )) - } - } - - fn readdir(p: &Path) -> io::Result { - let root = p.to_path_buf(); - let star = p.join("*"); - let path = to_u16s(&star)?; - - unsafe { - let mut wfd = mem::zeroed(); - let find_handle = FindFirstFileW(path.as_ptr(), &mut wfd); - if find_handle != INVALID_HANDLE_VALUE { - Ok(ReadDir { - handle: FindNextFileHandle(find_handle), - root: Arc::new(root), - first: Some(wfd), - }) - } else { - Err(io::Error::last_os_error()) - } - } - } - - struct RmdirContext<'a> { - base_dir: &'a Path, - readonly: bool, - counter: u64, - } - - fn remove_dir_all_recursive(path: &Path, ctx: &mut RmdirContext) -> io::Result<()> { - let dir_readonly = ctx.readonly; - for child in readdir(path)? { - let child = child?; - let child_type = child.file_type()?; - ctx.readonly = child.metadata()?.perm().readonly(); - if child_type.is_dir() { - remove_dir_all_recursive(&child.path(), ctx)?; - } else { - remove_item(&child.path().as_ref(), ctx)?; - } - } - ctx.readonly = dir_readonly; - remove_item(path, ctx) - } - - fn remove_item(path: &Path, ctx: &mut RmdirContext) -> io::Result<()> { - if !ctx.readonly { - let mut opts = OpenOptions::new(); - opts.access_mode(DELETE); - opts.custom_flags( - FILE_FLAG_BACKUP_SEMANTICS | // delete directory - FILE_FLAG_OPEN_REPARSE_POINT | // delete symlink - FILE_FLAG_DELETE_ON_CLOSE, - ); - let file = File::open(path, &opts)?; - move_item(&file, ctx) - } else { - // remove read-only permision - set_perm(&path, FilePermissions::new())?; - // move and delete file, similar to !readonly. - // only the access mode is different. - let mut opts = OpenOptions::new(); - opts.access_mode(DELETE | FILE_WRITE_ATTRIBUTES); - opts.custom_flags( - FILE_FLAG_BACKUP_SEMANTICS - | FILE_FLAG_OPEN_REPARSE_POINT - | FILE_FLAG_DELETE_ON_CLOSE, - ); - let file = File::open(path, &opts)?; - move_item(&file, ctx)?; - // restore read-only flag just in case there are other hard links - let mut perm = FilePermissions::new(); - perm.set_readonly(true); - let _ = file.set_perm(perm); // ignore if this fails - Ok(()) - } - } - - macro_rules! compat_fn { - ($module:ident: $( - fn $symbol:ident($($argname:ident: $argtype:ty),*) - -> $rettype:ty { - $($body:expr);* - } - )*) => ($( - #[allow(unused_variables)] - unsafe fn $symbol($($argname: $argtype),*) -> $rettype { - use std::sync::atomic::{AtomicUsize, Ordering}; - use std::mem; - use std::ffi::CString; - type F = unsafe extern "system" fn($($argtype),*) -> $rettype; - - lazy_static! { static ref PTR: AtomicUsize = AtomicUsize::new(0);} - - fn lookup(module: &str, symbol: &str) -> Option { - let mut module: Vec = module.encode_utf16().collect(); - module.push(0); - let symbol = CString::new(symbol).unwrap(); - unsafe { - let handle = GetModuleHandleW(module.as_ptr()); - match GetProcAddress(handle, symbol.as_ptr()) as usize { - 0 => None, - n => Some(n), - } - } - } - - fn store_func(ptr: &AtomicUsize, module: &str, symbol: &str, - fallback: usize) -> usize { - let value = lookup(module, symbol).unwrap_or(fallback); - ptr.store(value, Ordering::SeqCst); - value - } - - fn load() -> usize { - store_func(&PTR, stringify!($module), stringify!($symbol), fallback as usize) - } - unsafe extern "system" fn fallback($($argname: $argtype),*) - -> $rettype { - $($body);* - } - - let addr = match PTR.load(Ordering::SeqCst) { - 0 => load(), - n => n, - }; - mem::transmute::(addr)($($argname),*) - } - )*) - } - - compat_fn! { - kernel32: - fn GetFinalPathNameByHandleW(_hFile: HANDLE, - _lpszFilePath: LPCWSTR, - _cchFilePath: DWORD, - _dwFlags: DWORD) -> DWORD { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 - } - fn SetFileInformationByHandle(_hFile: HANDLE, - _FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, - _lpFileInformation: LPVOID, - _dwBufferSize: DWORD) -> BOOL { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 - } - } - - fn cvt(i: i32) -> io::Result { - if i == 0 { - Err(io::Error::last_os_error()) - } else { - Ok(i) - } - } - - fn to_u16s>(s: S) -> io::Result> { - fn inner(s: &OsStr) -> io::Result> { - let mut maybe_result: Vec = s.encode_wide().collect(); - if maybe_result.iter().any(|&u| u == 0) { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "strings passed to WinAPI cannot contain NULs", - )); - } - maybe_result.push(0); - Ok(maybe_result) - } - inner(s.as_ref()) - } - - fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] { - match v.iter().position(|c| *c == 0) { - // don't include the 0 - Some(i) => &v[..i], - None => v, - } - } - - fn fill_utf16_buf(mut f1: F1, f2: F2) -> io::Result - where - F1: FnMut(*mut u16, DWORD) -> DWORD, - F2: FnOnce(&[u16]) -> T, - { - // Start off with a stack buf but then spill over to the heap if we end up - // needing more space. - let mut stack_buf = [0u16; 512]; - let mut heap_buf = Vec::new(); - unsafe { - let mut n = stack_buf.len(); - loop { - let buf = if n <= stack_buf.len() { - &mut stack_buf[..] - } else { - let extra = n - heap_buf.len(); - heap_buf.reserve(extra); - heap_buf.set_len(n); - &mut heap_buf[..] - }; - - // This function is typically called on windows API functions which - // will return the correct length of the string, but these functions - // also return the `0` on error. In some cases, however, the - // returned "correct length" may actually be 0! - // - // To handle this case we call `SetLastError` to reset it to 0 and - // then check it again if we get the "0 error value". If the "last - // error" is still 0 then we interpret it as a 0 length buffer and - // not an actual error. - SetLastError(0); - let k = match f1(buf.as_mut_ptr(), n as DWORD) { - 0 if GetLastError() == 0 => 0, - 0 => return Err(io::Error::last_os_error()), - n => n, - } as usize; - if k == n && GetLastError() == ERROR_INSUFFICIENT_BUFFER { - n *= 2; - } else if k >= n { - n = k; - } else { - return Ok(f2(&buf[..k])); - } - } - } - } - - #[derive(Clone, PartialEq, Eq, Debug, Default)] - struct FilePermissions { - readonly: bool, - } - - impl FilePermissions { - fn new() -> FilePermissions { - Default::default() - } - fn readonly(&self) -> bool { - self.readonly - } - fn set_readonly(&mut self, readonly: bool) { - self.readonly = readonly - } - } - - #[derive(Clone)] - struct OpenOptions { - // generic - read: bool, - write: bool, - append: bool, - truncate: bool, - create: bool, - create_new: bool, - // system-specific - custom_flags: u32, - access_mode: Option, - attributes: DWORD, - share_mode: DWORD, - security_qos_flags: DWORD, - security_attributes: usize, // FIXME: should be a reference - } - - impl OpenOptions { - fn new() -> OpenOptions { - OpenOptions { - // generic - read: false, - write: false, - append: false, - truncate: false, - create: false, - create_new: false, - // system-specific - custom_flags: 0, - access_mode: None, - share_mode: FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - attributes: 0, - security_qos_flags: 0, - security_attributes: 0, - } - } - fn custom_flags(&mut self, flags: u32) { - self.custom_flags = flags; - } - fn access_mode(&mut self, access_mode: u32) { - self.access_mode = Some(access_mode); - } - - fn get_access_mode(&self) -> io::Result { - const ERROR_INVALID_PARAMETER: i32 = 87; - - match (self.read, self.write, self.append, self.access_mode) { - (_, _, _, Some(mode)) => Ok(mode), - (true, false, false, None) => Ok(GENERIC_READ), - (false, true, false, None) => Ok(GENERIC_WRITE), - (true, true, false, None) => Ok(GENERIC_READ | GENERIC_WRITE), - (false, _, true, None) => Ok(FILE_GENERIC_WRITE & !FILE_WRITE_DATA), - (true, _, true, None) => Ok(GENERIC_READ | (FILE_GENERIC_WRITE & !FILE_WRITE_DATA)), - (false, false, false, None) => { - Err(io::Error::from_raw_os_error(ERROR_INVALID_PARAMETER)) - } - } - } - - fn get_creation_mode(&self) -> io::Result { - const ERROR_INVALID_PARAMETER: i32 = 87; - - match (self.write, self.append) { - (true, false) => {} - (false, false) => { - if self.truncate || self.create || self.create_new { - return Err(io::Error::from_raw_os_error(ERROR_INVALID_PARAMETER)); - } - } - (_, true) => { - if self.truncate && !self.create_new { - return Err(io::Error::from_raw_os_error(ERROR_INVALID_PARAMETER)); - } - } - } - - Ok(match (self.create, self.truncate, self.create_new) { - (false, false, false) => OPEN_EXISTING, - (true, false, false) => OPEN_ALWAYS, - (false, true, false) => TRUNCATE_EXISTING, - (true, true, false) => CREATE_ALWAYS, - (_, _, true) => CREATE_NEW, - }) - } - - fn get_flags_and_attributes(&self) -> DWORD { - self.custom_flags - | self.attributes - | self.security_qos_flags - | if self.security_qos_flags != 0 { - SECURITY_SQOS_PRESENT - } else { - 0 - } - | if self.create_new { - FILE_FLAG_OPEN_REPARSE_POINT - } else { - 0 - } - } - } - - struct File { - handle: Handle, - } - - impl File { - fn open(path: &Path, opts: &OpenOptions) -> io::Result { - let path = to_u16s(path)?; - let handle = unsafe { - CreateFileW( - path.as_ptr(), - opts.get_access_mode()?, - opts.share_mode, - opts.security_attributes as *mut _, - opts.get_creation_mode()?, - opts.get_flags_and_attributes(), - ptr::null_mut(), - ) - }; - if handle == INVALID_HANDLE_VALUE { - Err(io::Error::last_os_error()) - } else { - Ok(File { - handle: Handle::new(handle), - }) - } - } - - fn file_attr(&self) -> io::Result { - unsafe { - let mut info: BY_HANDLE_FILE_INFORMATION = mem::zeroed(); - cvt(GetFileInformationByHandle(self.handle.raw(), &mut info))?; - let mut attr = FileAttr { - attributes: info.dwFileAttributes, - creation_time: info.ftCreationTime, - last_access_time: info.ftLastAccessTime, - last_write_time: info.ftLastWriteTime, - file_size: ((info.nFileSizeHigh as u64) << 32) | (info.nFileSizeLow as u64), - reparse_tag: 0, - }; - if attr.is_reparse_point() { - let mut b = [0; MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - if let Ok((_, buf)) = self.reparse_point(&mut b) { - attr.reparse_tag = buf.ReparseTag; - } - } - Ok(attr) - } - } - - fn set_attributes(&self, attr: DWORD) -> io::Result<()> { - let zero: LARGE_INTEGER = unsafe { mem::zeroed() }; - - let mut info = FILE_BASIC_INFO { - CreationTime: zero, // do not change - LastAccessTime: zero, // do not change - LastWriteTime: zero, // do not change - ChangeTime: zero, // do not change - FileAttributes: attr, - }; - let size = mem::size_of_val(&info); - cvt(unsafe { - SetFileInformationByHandle( - self.handle.raw(), - FileBasicInfo, - &mut info as *mut _ as *mut _, - size as DWORD, - ) - })?; - Ok(()) - } - - fn rename(&self, new: &Path, replace: bool) -> io::Result<()> { - // &self must be opened with DELETE permission - use std::iter; - #[cfg(target_arch = "x86")] - const STRUCT_SIZE: usize = 12; - #[cfg(target_arch = "x86_64")] - const STRUCT_SIZE: usize = 20; - - // FIXME: check for internal NULs in 'new' - let mut data: Vec = iter::repeat(0u16) - .take(STRUCT_SIZE / 2) - .chain(new.as_os_str().encode_wide()) - .collect(); - data.push(0); - let size = data.len() * 2; - - unsafe { - // Thanks to alignment guarantees on Windows this works - // (8 for 32-bit and 16 for 64-bit) - let info = data.as_mut_ptr() as *mut FILE_RENAME_INFO; - // The type of ReplaceIfExists is BOOL, but it actually expects a - // BOOLEAN. This means true is -1, not c::TRUE. - (*info).ReplaceIfExists = if replace { -1 } else { FALSE }; - (*info).RootDirectory = ptr::null_mut(); - (*info).FileNameLength = (size - STRUCT_SIZE) as DWORD; - cvt(SetFileInformationByHandle( - self.handle().raw(), - FileRenameInfo, - data.as_mut_ptr() as *mut _ as *mut _, - size as DWORD, - ))?; - Ok(()) - } - } - fn set_perm(&self, perm: FilePermissions) -> io::Result<()> { - let attr = self.file_attr()?.attributes; - if perm.readonly == (attr & FILE_ATTRIBUTE_READONLY != 0) { - Ok(()) - } else if perm.readonly { - self.set_attributes(attr | FILE_ATTRIBUTE_READONLY) - } else { - self.set_attributes(attr & !FILE_ATTRIBUTE_READONLY) - } - } - - fn handle(&self) -> &Handle { - &self.handle - } - - fn reparse_point<'a>( - &self, - space: &'a mut [u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE], - ) -> io::Result<(DWORD, &'a REPARSE_DATA_BUFFER)> { - unsafe { - let mut bytes = 0; - cvt({ - DeviceIoControl( - self.handle.raw(), - FSCTL_GET_REPARSE_POINT, - ptr::null_mut(), - 0, - space.as_mut_ptr() as *mut _, - space.len() as DWORD, - &mut bytes, - ptr::null_mut(), - ) - })?; - Ok((bytes, &*(space.as_ptr() as *const REPARSE_DATA_BUFFER))) - } - } - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash)] - enum FileType { - Dir, - File, - SymlinkFile, - SymlinkDir, - ReparsePoint, - MountPoint, - } - - impl FileType { - fn new(attrs: DWORD, reparse_tag: DWORD) -> FileType { - match ( - attrs & FILE_ATTRIBUTE_DIRECTORY != 0, - attrs & FILE_ATTRIBUTE_REPARSE_POINT != 0, - reparse_tag, - ) { - (false, false, _) => FileType::File, - (true, false, _) => FileType::Dir, - (false, true, IO_REPARSE_TAG_SYMLINK) => FileType::SymlinkFile, - (true, true, IO_REPARSE_TAG_SYMLINK) => FileType::SymlinkDir, - (true, true, IO_REPARSE_TAG_MOUNT_POINT) => FileType::MountPoint, - (_, true, _) => FileType::ReparsePoint, - // Note: if a _file_ has a reparse tag of the type IO_REPARSE_TAG_MOUNT_POINT it is - // invalid, as junctions always have to be dirs. We set the filetype to ReparsePoint - // to indicate it is something symlink-like, but not something you can follow. - } - } - - fn is_dir(&self) -> bool { - *self == FileType::Dir - } - fn is_symlink_dir(&self) -> bool { - *self == FileType::SymlinkDir || *self == FileType::MountPoint - } - } - - impl DirEntry { - fn new(root: &Arc, wfd: &WIN32_FIND_DATAW) -> Option { - let first_bytes = &wfd.cFileName[0..3]; - if first_bytes.starts_with(&[46, 0]) || first_bytes.starts_with(&[46, 46, 0]) { - None - } else { - Some(DirEntry { - root: root.clone(), - data: *wfd, - }) - } - } - - fn path(&self) -> PathBuf { - self.root.join(&self.file_name()) - } - - fn file_name(&self) -> OsString { - let filename = truncate_utf16_at_nul(&self.data.cFileName); - OsString::from_wide(filename) - } - - fn file_type(&self) -> io::Result { - Ok(FileType::new( - self.data.dwFileAttributes, - /* reparse_tag = */ self.data.dwReserved0, - )) - } - - fn metadata(&self) -> io::Result { - Ok(FileAttr { - attributes: self.data.dwFileAttributes, - creation_time: self.data.ftCreationTime, - last_access_time: self.data.ftLastAccessTime, - last_write_time: self.data.ftLastWriteTime, - file_size: ((self.data.nFileSizeHigh as u64) << 32) - | (self.data.nFileSizeLow as u64), - reparse_tag: if self.data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT != 0 { - // reserved unless this is a reparse point - self.data.dwReserved0 - } else { - 0 - }, - }) - } - } - - struct DirEntry { - root: Arc, - data: WIN32_FIND_DATAW, - } - - struct ReadDir { - handle: FindNextFileHandle, - root: Arc, - first: Option, - } - - impl Iterator for ReadDir { - type Item = io::Result; - fn next(&mut self) -> Option> { - if let Some(first) = self.first.take() { - if let Some(e) = DirEntry::new(&self.root, &first) { - return Some(Ok(e)); - } - } - unsafe { - let mut wfd = mem::zeroed(); - loop { - if FindNextFileW(self.handle.0, &mut wfd) == 0 { - if GetLastError() == ERROR_NO_MORE_FILES { - return None; - } else { - return Some(Err(io::Error::last_os_error())); - } - } - if let Some(e) = DirEntry::new(&self.root, &wfd) { - return Some(Ok(e)); - } - } - } - } - } - - #[derive(Clone)] - struct FileAttr { - attributes: DWORD, - creation_time: FILETIME, - last_access_time: FILETIME, - last_write_time: FILETIME, - file_size: u64, - reparse_tag: DWORD, - } - - impl FileAttr { - fn perm(&self) -> FilePermissions { - FilePermissions { - readonly: self.attributes & FILE_ATTRIBUTE_READONLY != 0, - } - } - - fn file_type(&self) -> FileType { - FileType::new(self.attributes, self.reparse_tag) - } - - fn is_reparse_point(&self) -> bool { - self.attributes & FILE_ATTRIBUTE_REPARSE_POINT != 0 - } - } - - #[repr(C)] - struct REPARSE_DATA_BUFFER { - ReparseTag: c_uint, - ReparseDataLength: c_ushort, - Reserved: c_ushort, - rest: (), - } - - const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024; - - /// An owned container for `HANDLE` object, closing them on Drop. - /// - /// All methods are inherited through a `Deref` impl to `RawHandle` - struct Handle(RawHandle); - - use std::ops::Deref; - - /// A wrapper type for `HANDLE` objects to give them proper Send/Sync inference - /// as well as Rust-y methods. - /// - /// This does **not** drop the handle when it goes out of scope, use `Handle` - /// instead for that. - #[derive(Copy, Clone)] - struct RawHandle(HANDLE); - - unsafe impl Send for RawHandle {} - unsafe impl Sync for RawHandle {} - - impl Handle { - fn new(handle: HANDLE) -> Handle { - Handle(RawHandle::new(handle)) - } - } - - impl Deref for Handle { - type Target = RawHandle; - fn deref(&self) -> &RawHandle { - &self.0 - } - } - - impl Drop for Handle { - fn drop(&mut self) { - unsafe { - let _ = CloseHandle(self.raw()); - } - } - } - - impl RawHandle { - fn new(handle: HANDLE) -> RawHandle { - RawHandle(handle) - } - - fn raw(&self) -> HANDLE { - self.0 - } - } - - struct FindNextFileHandle(HANDLE); - - fn get_path(f: &File) -> io::Result { - fill_utf16_buf( - |buf, sz| unsafe { - GetFinalPathNameByHandleW(f.handle.raw(), buf, sz, VOLUME_NAME_DOS) - }, - |buf| PathBuf::from(OsString::from_wide(buf)), - ) - } - - fn move_item(file: &File, ctx: &mut RmdirContext) -> io::Result<()> { - let mut tmpname = ctx.base_dir.join(format! {"rm-{}", ctx.counter}); - ctx.counter += 1; - // Try to rename the file. If it already exists, just retry with an other - // filename. - while let Err(err) = file.rename(tmpname.as_ref(), false) { - if err.kind() != io::ErrorKind::AlreadyExists { - return Err(err); - }; - tmpname = ctx.base_dir.join(format!("rm-{}", ctx.counter)); - ctx.counter += 1; - } - Ok(()) - } - - fn set_perm(path: &Path, perm: FilePermissions) -> io::Result<()> { - let mut opts = OpenOptions::new(); - opts.access_mode(FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES); - opts.custom_flags(FILE_FLAG_BACKUP_SEMANTICS); - let file = File::open(path, &opts)?; - file.set_perm(perm) - } - - const VOLUME_NAME_DOS: DWORD = 0x0; -} From 0266a9e9a36d226031b1012d912624d6876dc06f Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Tue, 11 Apr 2023 14:35:45 +0200 Subject: [PATCH 197/272] Fix links in Clippy book Links to README.md files must actually be links to index.md files, because of the inner workings of `mdbook`. Also use the latest mdbook version in CI. --- .github/workflows/remark.yml | 2 +- book/src/development/basics.md | 4 ++-- book/src/usage.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml index 81ef072bbb07..116058b7c753 100644 --- a/.github/workflows/remark.yml +++ b/.github/workflows/remark.yml @@ -29,7 +29,7 @@ jobs: - name: Install mdbook run: | mkdir mdbook - curl -Lf https://github.com/rust-lang/mdBook/releases/download/v0.4.18/mdbook-v0.4.18-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook + curl -Lf https://github.com/rust-lang/mdBook/releases/download/v0.4.28/mdbook-v0.4.28-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook echo `pwd`/mdbook >> $GITHUB_PATH # Run diff --git a/book/src/development/basics.md b/book/src/development/basics.md index b07d3de7187e..7615dc12f9eb 100644 --- a/book/src/development/basics.md +++ b/book/src/development/basics.md @@ -4,8 +4,8 @@ This document explains the basics for hacking on Clippy. Besides others, this includes how to build and test Clippy. For a more in depth description on the codebase take a look at [Adding Lints] or [Common Tools]. -[Adding Lints]: https://github.com/rust-lang/rust-clippy/blob/master/book/src/development/adding_lints.md -[Common Tools]: https://github.com/rust-lang/rust-clippy/blob/master/book/src/development/common_tools_writing_lints.md +[Adding Lints]: adding_lints.md +[Common Tools]: common_tools_writing_lints.md - [Basics for hacking on Clippy](#basics-for-hacking-on-clippy) - [Get the Code](#get-the-code) diff --git a/book/src/usage.md b/book/src/usage.md index 372a23320d85..32084a9199b7 100644 --- a/book/src/usage.md +++ b/book/src/usage.md @@ -148,4 +148,4 @@ clippy-driver --edition 2018 -Cpanic=abort foo.rs > that are not optimized as expected, for example. [Installation]: installation.md -[CI]: continuous_integration/README.md +[CI]: continuous_integration/index.md From c355e6b9a8f9c92f57788566d075dc36de49f006 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Tue, 11 Apr 2023 15:34:15 +0200 Subject: [PATCH 198/272] Update Cargo.lock --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index 321e9cc35c58..78ffa483304a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -830,6 +830,7 @@ dependencies = [ name = "clippy_lints" version = "0.1.70" dependencies = [ + "arrayvec 0.7.0", "cargo_metadata 0.15.3", "clippy_utils", "declare_clippy_lint", From cecb901e683cdc1a2ffbb1e331ba4f262e2215c0 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Tue, 11 Apr 2023 16:23:35 +0200 Subject: [PATCH 199/272] Add Offset binary op to custom mir --- .../src/build/custom/parse/instruction.rs | 5 +++++ library/core/src/intrinsics/mir.rs | 2 ++ .../references.raw_pointer_offset.built.after.mir | 10 ++++++++++ tests/mir-opt/building/custom/references.rs | 11 +++++++++++ 4 files changed, 28 insertions(+) create mode 100644 tests/mir-opt/building/custom/references.raw_pointer_offset.built.after.mir diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 54028dfe87b7..931fe1b2433a 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -148,6 +148,11 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { )), ) }, + @call("mir_offset", args) => { + let ptr = self.parse_operand(args[0])?; + let offset = self.parse_operand(args[1])?; + Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset)))) + }, @call("mir_len", args) => Ok(Rvalue::Len(self.parse_place(args[0])?)), ExprKind::Borrow { borrow_kind, arg } => Ok( Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?) diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index 6690c1a76d5f..d9d62eb759e6 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -232,6 +232,7 @@ //! - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue. //! - [`Discriminant`] and [`Len`] have associated functions. //! - Unary and binary operations use their normal Rust syntax - `a * b`, `!c`, etc. +//! - The binary operation `Offset` can be created via [`Offset`]. //! - Checked binary operations are represented by wrapping the associated binop in [`Checked`]. //! - Array repetition syntax (`[foo; 10]`) creates the associated rvalue. //! @@ -289,6 +290,7 @@ define!( fn Discriminant(place: T) -> ::Discriminant ); define!("mir_set_discriminant", fn SetDiscriminant(place: T, index: u32)); +define!("mir_offset", fn Offset(ptr: T, count: U) -> T); define!( "mir_field", /// Access the field with the given index of some place. diff --git a/tests/mir-opt/building/custom/references.raw_pointer_offset.built.after.mir b/tests/mir-opt/building/custom/references.raw_pointer_offset.built.after.mir new file mode 100644 index 000000000000..f614aef4029d --- /dev/null +++ b/tests/mir-opt/building/custom/references.raw_pointer_offset.built.after.mir @@ -0,0 +1,10 @@ +// MIR for `raw_pointer_offset` after built + +fn raw_pointer_offset(_1: *const i32) -> *const i32 { + let mut _0: *const i32; // return place in scope 0 at $DIR/references.rs:+0:45: +0:55 + + bb0: { + _0 = Offset(_1, const 1_isize); // scope 0 at $DIR/references.rs:+2:9: +2:33 + return; // scope 0 at $DIR/references.rs:+3:9: +3:17 + } +} diff --git a/tests/mir-opt/building/custom/references.rs b/tests/mir-opt/building/custom/references.rs index a1c896de04cf..f87f6664c7a5 100644 --- a/tests/mir-opt/building/custom/references.rs +++ b/tests/mir-opt/building/custom/references.rs @@ -45,11 +45,22 @@ pub fn raw_pointer(x: *const i32) -> *const i32 { }) } +// EMIT_MIR references.raw_pointer_offset.built.after.mir +#[custom_mir(dialect = "built")] +pub fn raw_pointer_offset(x: *const i32) -> *const i32 { + mir!({ + RET = Offset(x, 1_isize); + Return() + }) +} + fn main() { let mut x = 5; + let arr = [1, 2]; assert_eq!(*mut_ref(&mut x), 5); assert_eq!(*immut_ref(&x), 5); unsafe { assert_eq!(*raw_pointer(addr_of!(x)), 5); + assert_eq!(*raw_pointer_offset(addr_of!(arr[0])), 2); } } From 4e84d695f35bc5708ded1d191f22ba961730cac7 Mon Sep 17 00:00:00 2001 From: Patrik Kormosi Date: Tue, 11 Apr 2023 16:29:48 +0200 Subject: [PATCH 200/272] Reword the docstring in todo! macro definition --- library/core/src/macros/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index c39a269c1de4..7c93c93b4a01 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -712,8 +712,8 @@ macro_rules! unimplemented { /// Indicates unfinished code. /// -/// This can be useful if you are prototyping and are just looking to have your -/// code typechecked. +/// This can be useful if you are prototyping and just +/// want a placeholder to let your code pass type analysis. /// /// The difference between [`unimplemented!`] and `todo!` is that while `todo!` conveys /// an intent of implementing the functionality later and the message is "not yet From 83f525cc2897d3561e268d3ea2207cd49a1c1bff Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 11 Apr 2023 17:19:07 +0200 Subject: [PATCH 201/272] Make test compatible with 32-bit --- tests/codegen/issues/issue-101082.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/codegen/issues/issue-101082.rs b/tests/codegen/issues/issue-101082.rs index 27387d0c1192..2cbe99942cba 100644 --- a/tests/codegen/issues/issue-101082.rs +++ b/tests/codegen/issues/issue-101082.rs @@ -7,7 +7,7 @@ #[no_mangle] pub fn test() -> usize { // CHECK-LABEL: @test( - // CHECK: ret i64 165 + // CHECK: ret {{i64|i32}} 165 let values = [23, 16, 54, 3, 60, 9]; let mut acc = 0; for item in values { From 1178c49a1bc76c7ca242cede37855cb5468b290c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 11 Apr 2023 16:52:20 +0000 Subject: [PATCH 202/272] Check for body owner fallibly --- .../src/traits/error_reporting/mod.rs | 2 +- tests/ui/wf/issue-110157.rs | 12 +++++++ tests/ui/wf/issue-110157.stderr | 32 +++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 tests/ui/wf/issue-110157.rs create mode 100644 tests/ui/wf/issue-110157.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 6ebf056f0e83..d7e0fe592b00 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -2380,8 +2380,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } if let Some(ty::subst::GenericArgKind::Type(_)) = subst.map(|subst| subst.unpack()) + && let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) { - let body_id = self.tcx.hir().body_owned_by(obligation.cause.body_id); let mut expr_finder = FindExprBySpan::new(span); expr_finder.visit_expr(&self.tcx.hir().body(body_id).value); diff --git a/tests/ui/wf/issue-110157.rs b/tests/ui/wf/issue-110157.rs new file mode 100644 index 000000000000..43a8ce72ff1b --- /dev/null +++ b/tests/ui/wf/issue-110157.rs @@ -0,0 +1,12 @@ +struct NeedsDropTypes<'tcx, F>(std::marker::PhantomData<&'tcx F>); + +impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F> +//~^ ERROR type annotations needed +where + F: Fn(&Missing) -> Result, + //~^ ERROR cannot find type `Missing` in this scope + I: Iterator, + //~^ ERROR cannot find type `Missing` in this scope +{} + +fn main() {} diff --git a/tests/ui/wf/issue-110157.stderr b/tests/ui/wf/issue-110157.stderr new file mode 100644 index 000000000000..91d801e9470e --- /dev/null +++ b/tests/ui/wf/issue-110157.stderr @@ -0,0 +1,32 @@ +error[E0412]: cannot find type `Missing` in this scope + --> $DIR/issue-110157.rs:6:12 + | +LL | F: Fn(&Missing) -> Result, + | ^^^^^^^ not found in this scope + +error[E0412]: cannot find type `Missing` in this scope + --> $DIR/issue-110157.rs:8:24 + | +LL | I: Iterator, + | ^^^^^^^ not found in this scope + +error[E0283]: type annotations needed + --> $DIR/issue-110157.rs:3:31 + | +LL | impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F> + | ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `I` + | + = note: cannot satisfy `_: Iterator` +note: required for `NeedsDropTypes<'tcx, F>` to implement `Iterator` + --> $DIR/issue-110157.rs:3:18 + | +LL | impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F> + | ^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | I: Iterator, + | ------------------------ unsatisfied trait bound introduced here + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0283, E0412. +For more information about an error, try `rustc --explain E0283`. From 8aba3f3264b33b53f0d4573ff68bd17aee319e72 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 11 Apr 2023 19:14:28 +0200 Subject: [PATCH 203/272] Update browser-ui-test version to 0.15.0 --- .../docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 66fb941ea375..7092c7c46f86 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.14.6 \ No newline at end of file +0.15.0 \ No newline at end of file From 010fa00b80474648268af58dd2edecbf454a9e55 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 11 Apr 2023 19:11:34 +0200 Subject: [PATCH 204/272] Update rustdoc GUI tests to new browser-ui-test version --- tests/rustdoc-gui/anchor-navigable.goml | 2 +- tests/rustdoc-gui/anchors.goml | 8 ++--- tests/rustdoc-gui/basic-code.goml | 2 +- .../rustdoc-gui/check-code-blocks-margin.goml | 2 +- tests/rustdoc-gui/check-stab-in-docblock.goml | 4 +-- .../rustdoc-gui/check_info_sign_position.goml | 4 +-- tests/rustdoc-gui/code-blocks-overflow.goml | 4 +-- tests/rustdoc-gui/code-color.goml | 4 +-- tests/rustdoc-gui/code-sidebar-toggle.goml | 4 +-- tests/rustdoc-gui/code-tags.goml | 12 ++++---- tests/rustdoc-gui/codeblock-sub.goml | 2 +- tests/rustdoc-gui/codeblock-tooltip.goml | 4 +-- tests/rustdoc-gui/cursor.goml | 6 ++-- tests/rustdoc-gui/default-settings.goml | 2 +- .../rustdoc-gui/docblock-big-code-mobile.goml | 4 +-- .../docblock-code-block-line-number.goml | 4 +-- tests/rustdoc-gui/docblock-details.goml | 4 +-- .../rustdoc-gui/docblock-table-overflow.goml | 4 +-- tests/rustdoc-gui/docblock-table.goml | 4 +-- .../rustdoc-gui/duplicate-macro-reexport.goml | 2 +- tests/rustdoc-gui/enum-variants.goml | 2 +- tests/rustdoc-gui/escape-key.goml | 2 +- tests/rustdoc-gui/font-weight.goml | 8 ++--- tests/rustdoc-gui/go-to-collapsed-elem.goml | 14 ++++----- tests/rustdoc-gui/hash-item-expansion.goml | 2 +- tests/rustdoc-gui/headers-color.goml | 12 ++++---- tests/rustdoc-gui/headings.goml | 16 +++++----- tests/rustdoc-gui/help-page.goml | 16 +++++----- tests/rustdoc-gui/highlight-colors.goml | 4 +-- .../huge-collection-of-constants.goml | 2 +- tests/rustdoc-gui/huge-logo.goml | 12 ++++---- tests/rustdoc-gui/impl-default-expansion.goml | 2 +- tests/rustdoc-gui/impl-doc.goml | 2 +- tests/rustdoc-gui/implementors.goml | 10 +++---- tests/rustdoc-gui/item-decl-colors.goml | 6 ++-- tests/rustdoc-gui/item-info-alignment.goml | 6 ++-- tests/rustdoc-gui/item-info-overflow.goml | 6 ++-- tests/rustdoc-gui/item-info.goml | 6 ++-- tests/rustdoc-gui/item-summary-table.goml | 2 +- tests/rustdoc-gui/javascript-disabled.goml | 2 +- tests/rustdoc-gui/jump-to-def-background.goml | 4 +-- tests/rustdoc-gui/label-next-to-symbol.goml | 6 ++-- tests/rustdoc-gui/links-color.goml | 4 +-- tests/rustdoc-gui/list_code_block.goml | 4 +-- tests/rustdoc-gui/method-margins.goml | 2 +- tests/rustdoc-gui/mobile.goml | 12 ++++---- tests/rustdoc-gui/module-items-font.goml | 2 +- tests/rustdoc-gui/no-docblock.goml | 4 +-- tests/rustdoc-gui/notable-trait.goml | 18 +++++------ .../overflow-tooltip-information.goml | 2 +- tests/rustdoc-gui/pocket-menu.goml | 10 +++---- tests/rustdoc-gui/run-on-hover.goml | 4 +-- tests/rustdoc-gui/rust-logo.goml | 14 ++++----- .../scrape-examples-button-focus.goml | 2 +- tests/rustdoc-gui/scrape-examples-color.goml | 8 ++--- tests/rustdoc-gui/scrape-examples-fonts.goml | 2 +- tests/rustdoc-gui/scrape-examples-layout.goml | 4 +-- tests/rustdoc-gui/scrape-examples-toggle.goml | 4 +-- tests/rustdoc-gui/search-error.goml | 4 +-- tests/rustdoc-gui/search-filter.goml | 8 ++--- tests/rustdoc-gui/search-form-elements.goml | 8 ++--- tests/rustdoc-gui/search-input-mobile.goml | 6 ++-- tests/rustdoc-gui/search-keyboard.goml | 2 +- tests/rustdoc-gui/search-no-result.goml | 4 +-- tests/rustdoc-gui/search-reexport.goml | 4 +-- tests/rustdoc-gui/search-result-color.goml | 12 ++++---- .../search-result-description.goml | 2 +- tests/rustdoc-gui/search-result-display.goml | 12 ++++---- .../search-result-go-to-first.goml | 6 ++-- tests/rustdoc-gui/search-result-keyword.goml | 2 +- .../search-tab-change-title-fn-sig.goml | 10 +++---- tests/rustdoc-gui/search-tab.goml | 4 +-- ...setting-auto-hide-content-large-items.goml | 2 +- .../setting-auto-hide-item-methods-docs.goml | 2 +- ...tting-auto-hide-trait-implementations.goml | 2 +- .../setting-go-to-only-result.goml | 10 +++---- tests/rustdoc-gui/settings.goml | 10 +++---- tests/rustdoc-gui/shortcuts.goml | 2 +- tests/rustdoc-gui/sidebar-links-color.goml | 4 +-- tests/rustdoc-gui/sidebar-macro-reexport.goml | 2 +- tests/rustdoc-gui/sidebar-mobile-scroll.goml | 6 ++-- tests/rustdoc-gui/sidebar-mobile.goml | 6 ++-- .../sidebar-source-code-display.goml | 18 +++++------ tests/rustdoc-gui/sidebar-source-code.goml | 10 +++---- tests/rustdoc-gui/sidebar.goml | 22 +++++++------- tests/rustdoc-gui/source-anchor-scroll.goml | 4 +-- .../source-code-page-code-scroll.goml | 4 +-- tests/rustdoc-gui/source-code-page.goml | 12 ++++---- tests/rustdoc-gui/src-font-size.goml | 2 +- tests/rustdoc-gui/stab-badge.goml | 8 ++--- tests/rustdoc-gui/struct-fields.goml | 2 +- tests/rustdoc-gui/target.goml | 4 +-- tests/rustdoc-gui/theme-change.goml | 8 ++--- tests/rustdoc-gui/theme-defaults.goml | 6 ++-- tests/rustdoc-gui/theme-in-history.goml | 6 ++-- tests/rustdoc-gui/toggle-click-deadspace.goml | 2 +- tests/rustdoc-gui/toggle-docs-mobile.goml | 6 ++-- tests/rustdoc-gui/toggle-docs.goml | 6 ++-- tests/rustdoc-gui/toggle-implementors.goml | 2 +- .../toggled-open-implementations.goml | 2 +- .../rustdoc-gui/trait-sidebar-item-order.goml | 2 +- .../rustdoc-gui/type-declation-overflow.goml | 30 +++++++++---------- tests/rustdoc-gui/unsafe-fn.goml | 4 +-- tests/rustdoc-gui/where-whitespace.goml | 6 ++-- 104 files changed, 308 insertions(+), 308 deletions(-) diff --git a/tests/rustdoc-gui/anchor-navigable.goml b/tests/rustdoc-gui/anchor-navigable.goml index 9d5c55a1e1da..61d7c89d434f 100644 --- a/tests/rustdoc-gui/anchor-navigable.goml +++ b/tests/rustdoc-gui/anchor-navigable.goml @@ -4,7 +4,7 @@ // anchor and the `impl Foo`. If there were a gap, this would cause an annoying // problem: you hover `impl Foo` to see the anchor, then when you move your // mouse to the left, the anchor disappears before you reach it. -goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" // We check that ".item-info" is bigger than its content. move-cursor-to: ".impl" assert-property: (".impl > a.anchor", {"offsetWidth": "8"}) diff --git a/tests/rustdoc-gui/anchors.goml b/tests/rustdoc-gui/anchors.goml index 85cb72274208..0904aa90e1bc 100644 --- a/tests/rustdoc-gui/anchors.goml +++ b/tests/rustdoc-gui/anchors.goml @@ -4,12 +4,12 @@ define-function: ( "check-colors", (theme, main_color, title_color, main_heading_color, main_heading_type_color, src_link_color, sidebar_link_color), block { - goto: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html" + go-to: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html" // This is needed to ensure that the text color is computed. show-text: true // Setting the theme. - local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} // We reload the page so the local storage settings are being used. reload: @@ -48,9 +48,9 @@ define-function: ( {"color": |src_link_color|, "text-decoration": "none solid " + |src_link_color|}, ) - goto: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html" + go-to: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html" // Since we changed page, we need to set the theme again. - local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} // We reload the page so the local storage settings are being used. reload: diff --git a/tests/rustdoc-gui/basic-code.goml b/tests/rustdoc-gui/basic-code.goml index 971c2f9480ea..e372f7119743 100644 --- a/tests/rustdoc-gui/basic-code.goml +++ b/tests/rustdoc-gui/basic-code.goml @@ -1,6 +1,6 @@ // Small test to ensure the "src-line-numbers" element is only present once on // the page. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" click: ".srclink" wait-for: ".src-line-numbers" assert-count: (".src-line-numbers", 1) diff --git a/tests/rustdoc-gui/check-code-blocks-margin.goml b/tests/rustdoc-gui/check-code-blocks-margin.goml index c2cec00204d7..8c2cbc4d90eb 100644 --- a/tests/rustdoc-gui/check-code-blocks-margin.goml +++ b/tests/rustdoc-gui/check-code-blocks-margin.goml @@ -1,5 +1,5 @@ // This test ensures that the docblock elements have the appropriate left margin. -goto: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" // The top docblock elements shouldn't have left margin... assert-css: ("#main-content .item-decl", {"margin-left": "0px"}) // ... but all the others should! diff --git a/tests/rustdoc-gui/check-stab-in-docblock.goml b/tests/rustdoc-gui/check-stab-in-docblock.goml index 266fa999728e..2f62636211b8 100644 --- a/tests/rustdoc-gui/check-stab-in-docblock.goml +++ b/tests/rustdoc-gui/check-stab-in-docblock.goml @@ -1,9 +1,9 @@ // This test checks that using `.stab` attributes in `.docblock` elements doesn't // create scrollable paragraphs. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" // Needs the text to be display to check for scrollable content. show-text: true -size: (786, 600) +set-window-size: (786, 600) // Confirms that there 3 paragraphs. assert-count: (".top-doc .docblock p", 3) // Checking that there is no scrollable content. diff --git a/tests/rustdoc-gui/check_info_sign_position.goml b/tests/rustdoc-gui/check_info_sign_position.goml index f36e73fc5e9e..c9a4ea94cfe8 100644 --- a/tests/rustdoc-gui/check_info_sign_position.goml +++ b/tests/rustdoc-gui/check_info_sign_position.goml @@ -1,7 +1,7 @@ // This test checks the position of the information on the code blocks (like // `compile_fail` or `ignore`). -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" -goto: "./fn.check_list_code_block.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +go-to: "./fn.check_list_code_block.html" // If the codeblock is the first element of the docblock, the information tooltip must have // have some top margin to avoid going over the toggle (the "[+]"). assert-css: (".docblock > .example-wrap.compile_fail .tooltip", { "margin-top": "16px" }) diff --git a/tests/rustdoc-gui/code-blocks-overflow.goml b/tests/rustdoc-gui/code-blocks-overflow.goml index fbf0e890bdca..a23136f4b762 100644 --- a/tests/rustdoc-gui/code-blocks-overflow.goml +++ b/tests/rustdoc-gui/code-blocks-overflow.goml @@ -1,6 +1,6 @@ // This test ensures that codeblocks content don't overflow. -goto: "file://" + |DOC_PATH| + "/lib2/sub_mod/struct.Foo.html" -size: (1080, 600) +go-to: "file://" + |DOC_PATH| + "/lib2/sub_mod/struct.Foo.html" +set-window-size: (1080, 600) // There should be two codeblocks: a rust one and a non-rust one. assert-count: (".docblock > .example-wrap", 2) assert: ".docblock > .example-wrap > .language-txt" diff --git a/tests/rustdoc-gui/code-color.goml b/tests/rustdoc-gui/code-color.goml index cb550a4573a6..833fa05db42b 100644 --- a/tests/rustdoc-gui/code-color.goml +++ b/tests/rustdoc-gui/code-color.goml @@ -2,7 +2,7 @@ // check that the rule isn't applied on other "" elements. // // While we're at it, we also check it for the other themes. -goto: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" // If the text isn't displayed, the browser doesn't compute color style correctly... show-text: true @@ -11,7 +11,7 @@ define-function: ( (theme, doc_code_color, doc_inline_code_color), block { // Set the theme. - local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} // We reload the page so the local storage settings are being used. reload: assert-css: (".docblock pre > code", {"color": |doc_code_color|}, ALL) diff --git a/tests/rustdoc-gui/code-sidebar-toggle.goml b/tests/rustdoc-gui/code-sidebar-toggle.goml index df665bd46c03..28c3712f307a 100644 --- a/tests/rustdoc-gui/code-sidebar-toggle.goml +++ b/tests/rustdoc-gui/code-sidebar-toggle.goml @@ -1,7 +1,7 @@ // This test checks that the source code pages sidebar toggle is working as expected. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" click: ".srclink" wait-for: "#src-sidebar-toggle" click: "#src-sidebar-toggle" -fail: true +expect-failure: true assert-css: ("#source-sidebar", { "left": "-300px" }) diff --git a/tests/rustdoc-gui/code-tags.goml b/tests/rustdoc-gui/code-tags.goml index ca337cbc323e..3405d3295e69 100644 --- a/tests/rustdoc-gui/code-tags.goml +++ b/tests/rustdoc-gui/code-tags.goml @@ -3,22 +3,22 @@ // We need to disable this check because `implementors/test_docs/trait.AnotherOne.js` // doesn't exist. fail-on-request-error: false -goto: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" -size: (1080, 600) +go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" +set-window-size: (1080, 600) // There should be four doc codeblocks. // Check that their content is inside

 assert-count: (".example-wrap pre > code", 4)
 // Check that function signature is inside 

 assert: "pre.rust.item-decl > code"
 
-goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
+go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
 assert: "pre.rust.item-decl > code"
 
-goto: "file://" + |DOC_PATH| + "/test_docs/enum.AnEnum.html"
+go-to: "file://" + |DOC_PATH| + "/test_docs/enum.AnEnum.html"
 assert: "pre.rust.item-decl > code"
 
-goto: "file://" + |DOC_PATH| + "/test_docs/trait.AnotherOne.html"
+go-to: "file://" + |DOC_PATH| + "/test_docs/trait.AnotherOne.html"
 assert: "pre.rust.item-decl > code"
 
-goto: "file://" + |DOC_PATH| + "/test_docs/type.SomeType.html"
+go-to: "file://" + |DOC_PATH| + "/test_docs/type.SomeType.html"
 assert: "pre.rust.item-decl > code"
diff --git a/tests/rustdoc-gui/codeblock-sub.goml b/tests/rustdoc-gui/codeblock-sub.goml
index cbd314d27915..03575cc6aaa9 100644
--- a/tests/rustdoc-gui/codeblock-sub.goml
+++ b/tests/rustdoc-gui/codeblock-sub.goml
@@ -1,5 +1,5 @@
 // Test that code blocks nested within  do not have a line height of 0.
-goto: "file://" + |DOC_PATH| + "/test_docs/codeblock_sub/index.html"
+go-to: "file://" + |DOC_PATH| + "/test_docs/codeblock_sub/index.html"
 
 store-property: (codeblock_sub_1, "#codeblock-sub-1", "offsetHeight")
 assert-property-false: ("#codeblock-sub-3", { "offsetHeight": |codeblock_sub_1| })
diff --git a/tests/rustdoc-gui/codeblock-tooltip.goml b/tests/rustdoc-gui/codeblock-tooltip.goml
index 36b67073a035..2ed0579d3141 100644
--- a/tests/rustdoc-gui/codeblock-tooltip.goml
+++ b/tests/rustdoc-gui/codeblock-tooltip.goml
@@ -1,5 +1,5 @@
 // Checking the colors of the codeblocks tooltips.
-goto: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html"
+go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html"
 show-text: true
 
 define-function: (
@@ -7,7 +7,7 @@ define-function: (
     (theme, background, color, border),
     block {
         // Setting the theme.
-        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+        set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         reload:
 
         // compile_fail block
diff --git a/tests/rustdoc-gui/cursor.goml b/tests/rustdoc-gui/cursor.goml
index 59b1397970b5..f318b05cedaa 100644
--- a/tests/rustdoc-gui/cursor.goml
+++ b/tests/rustdoc-gui/cursor.goml
@@ -1,5 +1,5 @@
 // This test ensures that several clickable items actually have the pointer cursor.
-goto: "file://" + |DOC_PATH| + "/lib2/struct.Foo.html"
+go-to: "file://" + |DOC_PATH| + "/lib2/struct.Foo.html"
 
 // the `[+]/[-]` button
 assert-css: ("#toggle-all-docs", {"cursor": "pointer"})
@@ -16,9 +16,9 @@ wait-for: "#search-tabs"
 assert-css: ("#search-tabs > button", {"cursor": "pointer"})
 
 // mobile sidebar toggle button
-size: (500, 700)
+set-window-size: (500, 700)
 assert-css: (".sidebar-menu-toggle", {"cursor": "pointer"})
 
 // the sidebar toggle button on the source code pages
-goto: "file://" + |DOC_PATH| + "/src/lib2/lib.rs.html"
+go-to: "file://" + |DOC_PATH| + "/src/lib2/lib.rs.html"
 assert-css: ("#src-sidebar-toggle > button", {"cursor": "pointer"})
diff --git a/tests/rustdoc-gui/default-settings.goml b/tests/rustdoc-gui/default-settings.goml
index ab27b001eb6a..3466f3693f90 100644
--- a/tests/rustdoc-gui/default-settings.goml
+++ b/tests/rustdoc-gui/default-settings.goml
@@ -2,7 +2,7 @@
 //
 // The "settings" crate uses "ayu" as default setting, which is what we will
 // check.
-goto: "file://" + |DOC_PATH| + "/settings/index.html"
+go-to: "file://" + |DOC_PATH| + "/settings/index.html"
 // Wait a bit to be sure the default theme is applied.
 // If the theme isn't applied, the command will time out.
 wait-for-css: ("body", {"background-color": "rgb(15, 20, 25)"})
diff --git a/tests/rustdoc-gui/docblock-big-code-mobile.goml b/tests/rustdoc-gui/docblock-big-code-mobile.goml
index 3ce921c2c91c..6fc6834768eb 100644
--- a/tests/rustdoc-gui/docblock-big-code-mobile.goml
+++ b/tests/rustdoc-gui/docblock-big-code-mobile.goml
@@ -1,7 +1,7 @@
 // If we have a long ``, we need to ensure that it'll be fully displayed on mobile, meaning
 // that it'll be on two lines.
 emulate: "iPhone 8" // it has the following size: (375, 667)
-goto: "file://" + |DOC_PATH| + "/test_docs/long_code_block/index.html"
+go-to: "file://" + |DOC_PATH| + "/test_docs/long_code_block/index.html"
 // We now check that the block is on two lines:
 show-text: true // We need to enable text draw to be able to have the "real" size
 // Little explanations for this test: if the text wasn't displayed on two lines, it would take
@@ -9,5 +9,5 @@ show-text: true // We need to enable text draw to be able to have the "real" siz
 assert-property: (".docblock p > code", {"offsetHeight": "44"})
 
 // Same check, but where the long code block is also a link
-goto: "file://" + |DOC_PATH| + "/test_docs/long_code_block_link/index.html"
+go-to: "file://" + |DOC_PATH| + "/test_docs/long_code_block_link/index.html"
 assert-property: (".docblock p > a > code", {"offsetHeight": "44"})
diff --git a/tests/rustdoc-gui/docblock-code-block-line-number.goml b/tests/rustdoc-gui/docblock-code-block-line-number.goml
index 69bcf5339ef2..4c36394a30ce 100644
--- a/tests/rustdoc-gui/docblock-code-block-line-number.goml
+++ b/tests/rustdoc-gui/docblock-code-block-line-number.goml
@@ -1,5 +1,5 @@
 // Checks that the setting "line numbers" is working as expected.
-goto: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html"
+go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html"
 
 // Otherwise, we can't check text color
 show-text: true
@@ -13,7 +13,7 @@ define-function: (
     (theme, color),
     block {
         // We now set the setting to show the line numbers on code examples.
-        local-storage: {
+        set-local-storage: {
             "rustdoc-theme": |theme|,
             "rustdoc-use-system-theme": "false",
             "rustdoc-line-numbers": "true"
diff --git a/tests/rustdoc-gui/docblock-details.goml b/tests/rustdoc-gui/docblock-details.goml
index 9ae571efbb58..58ff17619f63 100644
--- a/tests/rustdoc-gui/docblock-details.goml
+++ b/tests/rustdoc-gui/docblock-details.goml
@@ -1,7 +1,7 @@
 // This ensures that the `
`/`` elements are displayed as expected. -goto: "file://" + |DOC_PATH| + "/test_docs/details/struct.Details.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/details/struct.Details.html" show-text: true -local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"} +set-local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"} reload: // We first check that the headers in the `.top-doc` doc block still have their diff --git a/tests/rustdoc-gui/docblock-table-overflow.goml b/tests/rustdoc-gui/docblock-table-overflow.goml index d8670089ad88..1ca919d1eabc 100644 --- a/tests/rustdoc-gui/docblock-table-overflow.goml +++ b/tests/rustdoc-gui/docblock-table-overflow.goml @@ -1,7 +1,7 @@ // This test ensures that the type declaration content overflow is handled inside the
 directly.
-goto: "file://" + |DOC_PATH| + "/lib2/long_table/struct.Foo.html"
+go-to: "file://" + |DOC_PATH| + "/lib2/long_table/struct.Foo.html"
 // We set a fixed size so there is no chance of "random" resize.
-size: (1100, 800)
+set-window-size: (1100, 800)
 // Logically, the ".docblock" and the "

" should have the same scroll width. compare-elements-property: (".top-doc .docblock", ".top-doc .docblock > p", ["scrollWidth"]) assert-property: (".top-doc .docblock", {"scrollWidth": "816"}) diff --git a/tests/rustdoc-gui/docblock-table.goml b/tests/rustdoc-gui/docblock-table.goml index 3dcb8abd4159..011451ef4f39 100644 --- a/tests/rustdoc-gui/docblock-table.goml +++ b/tests/rustdoc-gui/docblock-table.goml @@ -1,5 +1,5 @@ // This test checks the appearance of the tables in the doc comments. -goto: "file://" + |DOC_PATH| + "/test_docs/doc_block_table/struct.DocBlockTable.html#method.func" +go-to: "file://" + |DOC_PATH| + "/test_docs/doc_block_table/struct.DocBlockTable.html#method.func" compare-elements-css: (".impl-items .docblock table th", ".top-doc .docblock table th", ["border"]) compare-elements-css: (".impl-items .docblock table td", ".top-doc .docblock table td", ["border"]) @@ -8,7 +8,7 @@ define-function: ( "check-colors", (theme, border_color, zebra_stripe_color), block { - local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|} + set-local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|} reload: assert-css: (".top-doc .docblock table tbody tr:nth-child(1)", { "background-color": "rgba(0, 0, 0, 0)", diff --git a/tests/rustdoc-gui/duplicate-macro-reexport.goml b/tests/rustdoc-gui/duplicate-macro-reexport.goml index 496203c128ea..7d01c88f31ba 100644 --- a/tests/rustdoc-gui/duplicate-macro-reexport.goml +++ b/tests/rustdoc-gui/duplicate-macro-reexport.goml @@ -1,5 +1,5 @@ // This test ensures that there is no macro duplicates in the sidebar. -goto: "file://" + |DOC_PATH| + "/test_docs/macro.a.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/macro.a.html" // Waiting for the elements in the sidebar to be rendered. wait-for: ".sidebar-elems .macro" // Check there is only one macro named "a" listed in the sidebar. diff --git a/tests/rustdoc-gui/enum-variants.goml b/tests/rustdoc-gui/enum-variants.goml index 8dfc49285f2e..a1f60986ac35 100644 --- a/tests/rustdoc-gui/enum-variants.goml +++ b/tests/rustdoc-gui/enum-variants.goml @@ -1,5 +1,5 @@ // Verifies that there is non-zero margin on variants and their docblocks. -goto: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html" assert-css: (".variants > .variant", {"margin": "0px 0px 12px"}) assert-css: (".variants > .docblock", {"margin": "0px 0px 32px 24px"}) diff --git a/tests/rustdoc-gui/escape-key.goml b/tests/rustdoc-gui/escape-key.goml index 5d80d24969dd..3ea20fd118e6 100644 --- a/tests/rustdoc-gui/escape-key.goml +++ b/tests/rustdoc-gui/escape-key.goml @@ -1,6 +1,6 @@ // This test ensures that the "Escape" shortcut is handled correctly based on the // current content displayed. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" // First, we check that the search results are hidden when the Escape key is pressed. write: (".search-input", "test") // To be SURE that the search will be run. diff --git a/tests/rustdoc-gui/font-weight.goml b/tests/rustdoc-gui/font-weight.goml index aad334d2bd29..6fad128dab8c 100644 --- a/tests/rustdoc-gui/font-weight.goml +++ b/tests/rustdoc-gui/font-weight.goml @@ -1,5 +1,5 @@ // This test checks that the font weight is correctly applied. -goto: "file://" + |DOC_PATH| + "/lib2/struct.Foo.html" +go-to: "file://" + |DOC_PATH| + "/lib2/struct.Foo.html" assert-css: ("//*[@class='rust item-decl']//a[text()='Alias']", {"font-weight": "400"}) assert-css: ( "//*[@class='structfield small-section-header']//a[text()='Alias']", @@ -9,13 +9,13 @@ assert-css: ("#method\.a_method > .code-header", {"font-weight": "600"}) assert-css: ("#associatedtype\.X > .code-header", {"font-weight": "600"}) assert-css: ("#associatedconstant\.Y > .code-header", {"font-weight": "600"}) -goto: "file://" + |DOC_PATH| + "/test_docs/type.SomeType.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/type.SomeType.html" assert-css: (".top-doc .docblock p", {"font-weight": "400"}, ALL) -goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" assert-css: (".impl-items .method > .code-header", {"font-weight": "600"}, ALL) -goto: "file://" + |DOC_PATH| + "/lib2/trait.Trait.html" +go-to: "file://" + |DOC_PATH| + "/lib2/trait.Trait.html" // This is a complex selector, so here's how it works: // diff --git a/tests/rustdoc-gui/go-to-collapsed-elem.goml b/tests/rustdoc-gui/go-to-collapsed-elem.goml index ec4231252364..80e9791775e4 100644 --- a/tests/rustdoc-gui/go-to-collapsed-elem.goml +++ b/tests/rustdoc-gui/go-to-collapsed-elem.goml @@ -1,10 +1,10 @@ // This test ensures that when clicking on a link which leads to an item inside a collapsed element, // the collapsed element will be expanded. -goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" // We check that the implementors block is expanded. assert-property: ("#implementations-list .implementors-toggle", {"open": "true"}) // We now collapse the implementors block. -property: ("#implementations-list .implementors-toggle", {"open": "false"}) +set-property: ("#implementations-list .implementors-toggle", {"open": "false"}) // And now we click on the link to the method to ensure it'll expand the implementors block. click: "//*[@class='sidebar']//a[@href='#method.must_use']" assert-property: ("#implementations-list .implementors-toggle", {"open": "true"}) @@ -12,9 +12,9 @@ assert-property: ("#implementations-list .implementors-toggle", {"open": "true"} define-function: ("collapsed-from-search", (), block { // Now we do the same through search result. // First we reload the page without the anchor in the URL. - goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" + go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" // Then we collapse the section again... - property: ("#implementations-list .implementors-toggle", {"open": "false"}) + set-property: ("#implementations-list .implementors-toggle", {"open": "false"}) // Then we run the search. write: (".search-input", "foo::must_use") wait-for: "//*[@id='search']//a[@href='../test_docs/struct.Foo.html#method.must_use']" @@ -25,12 +25,12 @@ define-function: ("collapsed-from-search", (), block { call-function: ("collapsed-from-search", {}) // Now running the same check but with mobile. -size: (600, 600) -goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" +set-window-size: (600, 600) +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" // We check that the implementors block is expanded. assert-property: ("#implementations-list .implementors-toggle", {"open": "true"}) // We now collapse the implementors block. -property: ("#implementations-list .implementors-toggle", {"open": "false"}) +set-property: ("#implementations-list .implementors-toggle", {"open": "false"}) // First we expand the mobile menu. click: ".sidebar-menu-toggle" // Then we click on the link to the method to ensure it'll expand the implementors block. diff --git a/tests/rustdoc-gui/hash-item-expansion.goml b/tests/rustdoc-gui/hash-item-expansion.goml index 3cf94f624fee..a7a5c3cb4834 100644 --- a/tests/rustdoc-gui/hash-item-expansion.goml +++ b/tests/rustdoc-gui/hash-item-expansion.goml @@ -1,5 +1,5 @@ // This test ensures that the element corresponding to the hash is displayed. -goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#method.borrow" +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#method.borrow" // In the blanket implementations list, "Borrow" is the second one, hence the ":nth(2)". assert-attribute: ("#blanket-implementations-list > details:nth-child(2)", {"open": ""}) // We first check that the impl block is open by default. diff --git a/tests/rustdoc-gui/headers-color.goml b/tests/rustdoc-gui/headers-color.goml index 92cf050a514f..7d83833a8bd0 100644 --- a/tests/rustdoc-gui/headers-color.goml +++ b/tests/rustdoc-gui/headers-color.goml @@ -4,10 +4,10 @@ define-function: ( "check-colors", (theme, color, code_header_color, focus_background_color, headings_color), block { - goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" + go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" // This is needed so that the text color is computed. show-text: true - local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} reload: assert-css: ( ".impl", @@ -19,20 +19,20 @@ define-function: ( {"color": |code_header_color|, "background-color": "rgba(0, 0, 0, 0)"}, ALL, ) - goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#impl-Foo" + go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#impl-Foo" assert-css: ( "#impl-Foo", {"color": |color|, "background-color": |focus_background_color|}, ) - goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#method.must_use" + go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#method.must_use" assert-css: ( "#method\.must_use", {"color": |color|, "background-color": |focus_background_color|}, ALL, ) - goto: "file://" + |DOC_PATH| + "/test_docs/index.html" + go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" assert-css: (".small-section-header a", {"color": |color|}, ALL) - goto: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html" + go-to: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html" // We select headings (h2, h3, h...). assert-css: (".docblock > :not(p) > a", {"color": |headings_color|}, ALL) }, diff --git a/tests/rustdoc-gui/headings.goml b/tests/rustdoc-gui/headings.goml index e4ba5f1246d9..089e2203a048 100644 --- a/tests/rustdoc-gui/headings.goml +++ b/tests/rustdoc-gui/headings.goml @@ -11,7 +11,7 @@ // 18px 1.125em // 16px 1rem // 14px 0.875rem -goto: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html" assert-css: (".main-heading h1", {"font-size": "24px"}) @@ -50,7 +50,7 @@ assert-css: ("h6#sub-heading-for-struct-impl-item-doc", {"font-size": "14px"}) assert-css: ("h6#sub-heading-for-struct-impl-item-doc", {"border-bottom-width": "0px"}) assert-css: ("h6#sub-sub-heading-for-struct-impl-item-doc", {"font-size": "14px"}) -goto: "file://" + |DOC_PATH| + "/test_docs/enum.HeavilyDocumentedEnum.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/enum.HeavilyDocumentedEnum.html" assert-css: (".main-heading h1", {"font-size": "24px"}) @@ -109,7 +109,7 @@ assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"border-bottom-width" assert-text: ("//ul[@class='block mod']/preceding-sibling::h3", "Modules") assert-css: ("//ul[@class='block mod']/preceding-sibling::h3", {"border-bottom-width": "0px"}, ALL) -goto: "file://" + |DOC_PATH| + "/test_docs/union.HeavilyDocumentedUnion.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/union.HeavilyDocumentedUnion.html" assert-css: (".main-heading h1", {"font-size": "24px"}) @@ -141,7 +141,7 @@ assert-css: ("h5#title-for-union-impl-item-doc", {"border-bottom-width": "0px"}) assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"font-size": "14px"}) assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"border-bottom-width": "0px"}) -goto: "file://" + |DOC_PATH| + "/test_docs/macro.heavily_documented_macro.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/macro.heavily_documented_macro.html" assert-css: (".main-heading h1", {"font-size": "24px"}) @@ -152,13 +152,13 @@ assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"}) // Needed to check colors show-text: true -goto: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html" define-function: ( "check-colors", (theme, heading_color, small_heading_color, heading_border_color), block { - local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} reload: assert-css: ( ".top-doc .docblock h2", @@ -222,13 +222,13 @@ define-function: ( "check-since-color", (theme), block { - local-storage: {"rustdoc-theme": |theme|} + set-local-storage: {"rustdoc-theme": |theme|} reload: assert-css: (".since", {"color": "rgb(128, 128, 128)"}, ALL) }, ) -goto: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html" +go-to: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html" call-function: ("check-since-color", ("ayu")) call-function: ("check-since-color", ("dark")) call-function: ("check-since-color", ("light")) diff --git a/tests/rustdoc-gui/help-page.goml b/tests/rustdoc-gui/help-page.goml index 6e2321a69630..1a1c1b28f613 100644 --- a/tests/rustdoc-gui/help-page.goml +++ b/tests/rustdoc-gui/help-page.goml @@ -1,6 +1,6 @@ // This test ensures that opening the help page in its own tab works. -goto: "file://" + |DOC_PATH| + "/help.html" -size: (1000, 1000) // Try desktop size first. +go-to: "file://" + |DOC_PATH| + "/help.html" +set-window-size: (1000, 1000) // Try desktop size first. wait-for: "#help" assert-css: ("#help", {"display": "block"}) assert-css: ("#help dd", {"font-size": "16px"}) @@ -8,7 +8,7 @@ click: "#help-button > a" assert-css: ("#help", {"display": "block"}) compare-elements-property: (".sub", "#help", ["offsetWidth"]) compare-elements-position: (".sub", "#help", ("x")) -size: (500, 1000) // Try mobile next. +set-window-size: (500, 1000) // Try mobile next. assert-css: ("#help", {"display": "block"}) compare-elements-property: (".sub", "#help", ["offsetWidth"]) compare-elements-position: (".sub", "#help", ("x")) @@ -20,7 +20,7 @@ define-function: ( (theme, color, background, box_shadow), block { // Setting the theme. - local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} // We reload the page so the local storage settings are being used. reload: assert-css: ("#help kbd", { @@ -51,8 +51,8 @@ call-function: ("check-colors", { }) // This test ensures that opening the help popover without switching pages works. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" -size: (1000, 1000) // Only supported on desktop. +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +set-window-size: (1000, 1000) // Only supported on desktop. assert-false: "#help" click: "#help-button > a" assert-css: ("#help", {"display": "block"}) @@ -63,8 +63,8 @@ compare-elements-property-false: (".sub", "#help", ["offsetWidth"]) compare-elements-position-false: (".sub", "#help", ("x")) // This test ensures that the "the rustdoc book" anchor link within the help popover works. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" -size: (1000, 1000) // Popover only appears when the screen width is >700px. +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +set-window-size: (1000, 1000) // Popover only appears when the screen width is >700px. assert-false: "#help" click: "#help-button > a" click: ".popover a[href='https://doc.rust-lang.org/rustdoc/']" diff --git a/tests/rustdoc-gui/highlight-colors.goml b/tests/rustdoc-gui/highlight-colors.goml index b182150a577d..4f5e1c110f2c 100644 --- a/tests/rustdoc-gui/highlight-colors.goml +++ b/tests/rustdoc-gui/highlight-colors.goml @@ -1,5 +1,5 @@ // This test checks the highlight colors in the source code pages. -goto: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" +go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" show-text: true define-function: ( @@ -22,7 +22,7 @@ define-function: ( doc_comment, ), block { - local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} reload: assert-css: ("pre.rust .kw", {"color": |kw|}, ALL) assert-css: ("pre.rust .kw-2", {"color": |kw2|}, ALL) diff --git a/tests/rustdoc-gui/huge-collection-of-constants.goml b/tests/rustdoc-gui/huge-collection-of-constants.goml index 636382a91699..387aca6f66cc 100644 --- a/tests/rustdoc-gui/huge-collection-of-constants.goml +++ b/tests/rustdoc-gui/huge-collection-of-constants.goml @@ -1,6 +1,6 @@ // Make sure that the last two entries are more than 12 pixels apart and not stacked on each other. -goto: "file://" + |DOC_PATH| + "/test_docs/huge_amount_of_consts/index.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/huge_amount_of_consts/index.html" compare-elements-position-near-false: ( "//ul[@class='item-table']/li[last()-1]", diff --git a/tests/rustdoc-gui/huge-logo.goml b/tests/rustdoc-gui/huge-logo.goml index 69459bd3e23b..6d3eb66068cf 100644 --- a/tests/rustdoc-gui/huge-logo.goml +++ b/tests/rustdoc-gui/huge-logo.goml @@ -1,23 +1,23 @@ // huge_logo crate has a custom 712x860 logo // test to ensure the maximum size in the layout works correctly -goto: "file://" + |DOC_PATH| + "/huge_logo/index.html" +go-to: "file://" + |DOC_PATH| + "/huge_logo/index.html" -size: (1280, 1024) +set-window-size: (1280, 1024) // offsetWidth = width of sidebar assert-property: (".sidebar .logo-container", {"offsetWidth": "200", "offsetHeight": 100}) assert-property: (".sidebar .logo-container img", {"offsetWidth": "100", "offsetHeight": 100}) -size: (400, 600) +set-window-size: (400, 600) // offset = size + margin assert-property: (".mobile-topbar .logo-container", {"offsetWidth": "55", "offsetHeight": 45}) assert-property: (".mobile-topbar .logo-container img", {"offsetWidth": "35", "offsetHeight": 35}) -goto: "file://" + |DOC_PATH| + "/src/huge_logo/lib.rs.html" +go-to: "file://" + |DOC_PATH| + "/src/huge_logo/lib.rs.html" -size: (1280, 1024) +set-window-size: (1280, 1024) assert-property: (".sub-logo-container", {"offsetWidth": "60", "offsetHeight": 60}) -size: (400, 600) +set-window-size: (400, 600) // 43 because 35px + 8px of margin assert-css: (".sub-logo-container > img", {"margin-bottom": "8px"}) assert-property: (".sub-logo-container", {"offsetWidth": "35", "offsetHeight": 43}) diff --git a/tests/rustdoc-gui/impl-default-expansion.goml b/tests/rustdoc-gui/impl-default-expansion.goml index c3f9240cc936..45bd7beb6e69 100644 --- a/tests/rustdoc-gui/impl-default-expansion.goml +++ b/tests/rustdoc-gui/impl-default-expansion.goml @@ -1,3 +1,3 @@ // This test ensures that the impl blocks are open by default. -goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" assert-attribute: ("#implementations-list details.implementors-toggle", {"open": ""}) diff --git a/tests/rustdoc-gui/impl-doc.goml b/tests/rustdoc-gui/impl-doc.goml index 6caffb9c39fc..4ec46de404fa 100644 --- a/tests/rustdoc-gui/impl-doc.goml +++ b/tests/rustdoc-gui/impl-doc.goml @@ -1,5 +1,5 @@ // A docblock on an impl must have a margin to separate it from the contents. -goto: "file://" + |DOC_PATH| + "/test_docs/struct.TypeWithImplDoc.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.TypeWithImplDoc.html" // The text is about 24px tall, so if there's a margin, then their position will be >24px apart compare-elements-position-near-false: ( diff --git a/tests/rustdoc-gui/implementors.goml b/tests/rustdoc-gui/implementors.goml index 997c0ed8f017..b39b95c1a9bf 100644 --- a/tests/rustdoc-gui/implementors.goml +++ b/tests/rustdoc-gui/implementors.goml @@ -1,6 +1,6 @@ // The goal of this test is to check that the external trait implementors, generated with JS, // have the same display than the "local" ones. -goto: "file://" + |DOC_PATH| + "/implementors/trait.Whatever.html" +go-to: "file://" + |DOC_PATH| + "/implementors/trait.Whatever.html" assert: "#implementors-list" // There are supposed to be two implementors listed. assert-count: ("#implementors-list .impl", 2) @@ -15,7 +15,7 @@ assert-attribute: ("#implementors-list .impl:nth-child(2)", {"id": "impl-Whateve assert-attribute: ("#implementors-list .impl:nth-child(2) > a.anchor", {"href": "#impl-Whatever-1"}) assert: "#implementors-list .impl:nth-child(2) > .code-header" -goto: "file://" + |DOC_PATH| + "/test_docs/struct.HasEmptyTraits.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.HasEmptyTraits.html" compare-elements-position-near-false: ( "#impl-EmptyTrait1-for-HasEmptyTraits", "#impl-EmptyTrait2-for-HasEmptyTraits", @@ -29,13 +29,13 @@ compare-elements-position-near: ( // Now check that re-exports work correctly. // There should be exactly one impl shown on both of these pages. -goto: "file://" + |DOC_PATH| + "/lib2/trait.TraitToReexport.html" +go-to: "file://" + |DOC_PATH| + "/lib2/trait.TraitToReexport.html" assert-count: ("#implementors-list .impl", 1) -goto: "file://" + |DOC_PATH| + "/implementors/trait.TraitToReexport.html" +go-to: "file://" + |DOC_PATH| + "/implementors/trait.TraitToReexport.html" assert-count: ("#implementors-list .impl", 1) // Now check that the link is properly rewritten for a crate called `http`. // An older version of rustdoc had a buggy check for absolute links. -goto: "file://" + |DOC_PATH| + "/http/trait.HttpTrait.html" +go-to: "file://" + |DOC_PATH| + "/http/trait.HttpTrait.html" assert-count: ("#implementors-list .impl", 1) assert-attribute: ("#implementors-list .impl a.trait", {"href": "../http/trait.HttpTrait.html"}) diff --git a/tests/rustdoc-gui/item-decl-colors.goml b/tests/rustdoc-gui/item-decl-colors.goml index c58e3eb7c237..5732dd8eea26 100644 --- a/tests/rustdoc-gui/item-decl-colors.goml +++ b/tests/rustdoc-gui/item-decl-colors.goml @@ -18,9 +18,9 @@ define-function: ( assoc_type_color, ), block { - goto: "file://" + |DOC_PATH| + "/test_docs/struct.WithGenerics.html" + go-to: "file://" + |DOC_PATH| + "/test_docs/struct.WithGenerics.html" show-text: true - local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} reload: assert-css: (".item-decl .code-attribute", {"color": |attr_color|}, ALL) assert-css: (".item-decl .trait", {"color": |trait_color|}, ALL) @@ -29,7 +29,7 @@ define-function: ( assert-css: (".item-decl .enum", {"color": |enum_color|}, ALL) assert-css: (".item-decl .primitive", {"color": |primitive_color|}, ALL) - goto: "file://" + |DOC_PATH| + "/test_docs/trait.TraitWithoutGenerics.html" + go-to: "file://" + |DOC_PATH| + "/test_docs/trait.TraitWithoutGenerics.html" assert-css: (".item-decl .constant", {"color": |constant_color|}, ALL) assert-css: (".item-decl .fn", {"color": |fn_color|}, ALL) assert-css: (".item-decl .associatedtype", {"color": |assoc_type_color|}, ALL) diff --git a/tests/rustdoc-gui/item-info-alignment.goml b/tests/rustdoc-gui/item-info-alignment.goml index 94b52f0056b0..6fc365d1f194 100644 --- a/tests/rustdoc-gui/item-info-alignment.goml +++ b/tests/rustdoc-gui/item-info-alignment.goml @@ -1,10 +1,10 @@ // This test ensures that the "item-info" looks about the same // whether or not it's inside a toggle. -goto: "file://" + |DOC_PATH| + "/lib2/struct.ItemInfoAlignmentTest.html" +go-to: "file://" + |DOC_PATH| + "/lib2/struct.ItemInfoAlignmentTest.html" // First, we try it in "desktop" mode. -size: (1200, 870) +set-window-size: (1200, 870) compare-elements-position: (".impl-items > .item-info", "summary > .item-info", ("x")) // Next, we try it in "mobile" mode (max-width: 700px). -size: (650, 650) +set-window-size: (650, 650) compare-elements-position: (".impl-items > .item-info", "summary > .item-info", ("x")) diff --git a/tests/rustdoc-gui/item-info-overflow.goml b/tests/rustdoc-gui/item-info-overflow.goml index 8ea14621cbf5..23c53c037623 100644 --- a/tests/rustdoc-gui/item-info-overflow.goml +++ b/tests/rustdoc-gui/item-info-overflow.goml @@ -1,7 +1,7 @@ // This test ensures that the "item-info" elements don't overflow. -goto: "file://" + |DOC_PATH| + "/lib2/struct.LongItemInfo.html" +go-to: "file://" + |DOC_PATH| + "/lib2/struct.LongItemInfo.html" // We set a fixed size so there is no chance of "random" resize. -size: (1200, 870) +set-window-size: (1200, 870) // Logically, the "item-decl" and the "item-info" should have the same scroll width. compare-elements-property: (".item-decl", ".item-info", ["scrollWidth"]) assert-property: (".item-info", {"scrollWidth": "940"}) @@ -13,7 +13,7 @@ assert-text: ( ) // Checking the "item-info" on an impl block as well: -goto: "file://" + |DOC_PATH| + "/lib2/struct.LongItemInfo2.html" +go-to: "file://" + |DOC_PATH| + "/lib2/struct.LongItemInfo2.html" compare-elements-property: ( "#impl-SimpleTrait-for-LongItemInfo2 .item-info", "#impl-SimpleTrait-for-LongItemInfo2 + .docblock", diff --git a/tests/rustdoc-gui/item-info.goml b/tests/rustdoc-gui/item-info.goml index 6780dfca68aa..60fd7c4e1981 100644 --- a/tests/rustdoc-gui/item-info.goml +++ b/tests/rustdoc-gui/item-info.goml @@ -1,15 +1,15 @@ // This test ensures a few things for item info elements. -goto: "file://" + |DOC_PATH| + "/lib2/struct.Foo.html" +go-to: "file://" + |DOC_PATH| + "/lib2/struct.Foo.html" // Ensuring that the item information don't take 100% of the width if unnecessary. // We set a fixed size so there is no chance of "random" resize. -size: (1100, 800) +set-window-size: (1100, 800) // We check that ".item-info" is bigger than its content. assert-css: (".item-info", {"width": "840px"}) assert-css: (".item-info .stab", {"width": "289px"}) assert-position: (".item-info .stab", {"x": 245}) // Now we ensure that they're not rendered on the same line. -goto: "file://" + |DOC_PATH| + "/lib2/trait.Trait.html" +go-to: "file://" + |DOC_PATH| + "/lib2/trait.Trait.html" // We first ensure that there are two item info on the trait. assert-count: ("#main-content > .item-info .stab", 2) // They should not have the same `y` position! diff --git a/tests/rustdoc-gui/item-summary-table.goml b/tests/rustdoc-gui/item-summary-table.goml index 7a219bd54c3e..893060303293 100644 --- a/tests/rustdoc-gui/item-summary-table.goml +++ b/tests/rustdoc-gui/item-summary-table.goml @@ -1,5 +1,5 @@ // This test ensures that elements aren't display in items summary. -goto: "file://" + |DOC_PATH| + "/lib2/summary_table/index.html" +go-to: "file://" + |DOC_PATH| + "/lib2/summary_table/index.html" // We check that we picked the right item first. assert-text: (".item-table .item-name", "Foo") // Then we check that its summary is empty. diff --git a/tests/rustdoc-gui/javascript-disabled.goml b/tests/rustdoc-gui/javascript-disabled.goml index edf179d0d5e6..a0872d553af7 100644 --- a/tests/rustdoc-gui/javascript-disabled.goml +++ b/tests/rustdoc-gui/javascript-disabled.goml @@ -2,5 +2,5 @@ // can't be used without JS. javascript: false -goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" assert-css: (".sub", {"display": "none"}) diff --git a/tests/rustdoc-gui/jump-to-def-background.goml b/tests/rustdoc-gui/jump-to-def-background.goml index 8ee3ccf4a211..3a7d48284d7c 100644 --- a/tests/rustdoc-gui/jump-to-def-background.goml +++ b/tests/rustdoc-gui/jump-to-def-background.goml @@ -1,12 +1,12 @@ // We check the background color on the jump to definition links in the source code page. -goto: "file://" + |DOC_PATH| + "/src/link_to_definition/lib.rs.html" +go-to: "file://" + |DOC_PATH| + "/src/link_to_definition/lib.rs.html" define-function: ( "check-background-color", (theme, background_color), block { // Set the theme. - local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" } + set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" } // We reload the page so the local storage settings are being used. reload: assert-css: ( diff --git a/tests/rustdoc-gui/label-next-to-symbol.goml b/tests/rustdoc-gui/label-next-to-symbol.goml index 412e475dcc9b..6c6380256bd1 100644 --- a/tests/rustdoc-gui/label-next-to-symbol.goml +++ b/tests/rustdoc-gui/label-next-to-symbol.goml @@ -1,9 +1,9 @@ // These tests verify that labels like "UNIX" and "Deprecated" stay on the same line as their symbol. // It also verifies the staggered layout on mobile. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" // Desktop view -size: (1080, 600) +set-window-size: (1080, 600) assert: (".stab.deprecated") assert: (".stab.portability") @@ -39,7 +39,7 @@ compare-elements-position: ( // Mobile view -size: (600, 600) +set-window-size: (600, 600) // staggered layout with 2em spacing assert-css: (".desc.docblock-short", { "padding-left": "32px" }) compare-elements-position-near: ( diff --git a/tests/rustdoc-gui/links-color.goml b/tests/rustdoc-gui/links-color.goml index 14f7d99351a6..2ee4bce10156 100644 --- a/tests/rustdoc-gui/links-color.goml +++ b/tests/rustdoc-gui/links-color.goml @@ -1,5 +1,5 @@ // This test checks links colors. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" // This is needed so that the text color is computed. show-text: true @@ -9,7 +9,7 @@ define-function: ( (theme, mod, macro, struct, enum, trait, fn, type, union, keyword, sidebar, sidebar_current, sidebar_current_background), block { - local-storage: { + set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false", } diff --git a/tests/rustdoc-gui/list_code_block.goml b/tests/rustdoc-gui/list_code_block.goml index 4c477d70c895..25ddea319c86 100644 --- a/tests/rustdoc-gui/list_code_block.goml +++ b/tests/rustdoc-gui/list_code_block.goml @@ -1,4 +1,4 @@ // This test checks that code blocks in list are supported. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" -goto: "./fn.check_list_code_block.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +go-to: "./fn.check_list_code_block.html" assert: ("pre.rust.item-decl") diff --git a/tests/rustdoc-gui/method-margins.goml b/tests/rustdoc-gui/method-margins.goml index 720268a9e7eb..ac3caeb237f0 100644 --- a/tests/rustdoc-gui/method-margins.goml +++ b/tests/rustdoc-gui/method-margins.goml @@ -1,5 +1,5 @@ // This test ensures that the margins on methods are coherent inside an impl block. -goto: "file://" + |DOC_PATH| + "/test_docs/trait_members/struct.HasTrait.html#impl-TraitMembers-for-HasTrait" +go-to: "file://" + |DOC_PATH| + "/test_docs/trait_members/struct.HasTrait.html#impl-TraitMembers-for-HasTrait" assert-count: ("#trait-implementations-list > .toggle", 1) diff --git a/tests/rustdoc-gui/mobile.goml b/tests/rustdoc-gui/mobile.goml index 8c8516ebff8e..e576385cd537 100644 --- a/tests/rustdoc-gui/mobile.goml +++ b/tests/rustdoc-gui/mobile.goml @@ -1,8 +1,8 @@ // Test various properties of the mobile UI -goto: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html" -size: (400, 600) +go-to: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html" +set-window-size: (400, 600) -font-size: 18 +set-font-size: 18 wait-for: 100 // wait a bit for the resize and the font-size change to be fully taken into account. // The out-of-band info (source, stable version, collapse) should be below the @@ -18,14 +18,14 @@ assert-property: (".mobile-topbar h2", {"offsetHeight": 33}) // is therefore not part of the DOM. assert-css: (".content .out-of-band .since::before", { "content": "\"Since \"" }) -size: (1000, 1000) +set-window-size: (1000, 1000) wait-for: 100 // wait a bit for the resize to be fully taken into account. assert-css-false: (".content .out-of-band .since::before", { "content": "\"Since \"" }) // On the settings page, the theme buttons should not line-wrap. Instead, they should // all be placed as a group on a line below the setting name "Theme." -goto: "file://" + |DOC_PATH| + "/settings.html" -size: (400, 600) +go-to: "file://" + |DOC_PATH| + "/settings.html" +set-window-size: (400, 600) // Ignored for now https://github.com/rust-lang/rust/issues/93784. // compare-elements-position-near-false: ( // "#preferred-light-theme .setting-radio-name", diff --git a/tests/rustdoc-gui/module-items-font.goml b/tests/rustdoc-gui/module-items-font.goml index 23823f8b6c79..54c8131c3b90 100644 --- a/tests/rustdoc-gui/module-items-font.goml +++ b/tests/rustdoc-gui/module-items-font.goml @@ -1,5 +1,5 @@ // This test checks that the correct font is used on module items (in index.html pages). -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" assert-css: ( ".item-table .item-name > a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, diff --git a/tests/rustdoc-gui/no-docblock.goml b/tests/rustdoc-gui/no-docblock.goml index 17a955064d73..1b4638ef067c 100644 --- a/tests/rustdoc-gui/no-docblock.goml +++ b/tests/rustdoc-gui/no-docblock.goml @@ -4,10 +4,10 @@ // doesn't exist. fail-on-request-error: false -goto: "file://" + |DOC_PATH| + "/test_docs/trait.TraitWithNoDocblocks.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/trait.TraitWithNoDocblocks.html" // Check that the two methods are more than 24px apart. compare-elements-position-near-false: ("//*[@id='tymethod.first_fn']", "//*[@id='tymethod.second_fn']", {"y": 24}) -goto: "file://" + |DOC_PATH| + "/test_docs/struct.TypeWithNoDocblocks.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.TypeWithNoDocblocks.html" // Check that the two methods are more than 24px apart. compare-elements-position-near-false: ("//*[@id='method.first_fn']", "//*[@id='method.second_fn']", {"y": 24}) diff --git a/tests/rustdoc-gui/notable-trait.goml b/tests/rustdoc-gui/notable-trait.goml index 207289151992..f65da5774787 100644 --- a/tests/rustdoc-gui/notable-trait.goml +++ b/tests/rustdoc-gui/notable-trait.goml @@ -1,8 +1,8 @@ // This test checks the position of the `i` for the notable traits. -goto: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html" show-text: true // We start with a wide screen. -size: (1100, 600) +set-window-size: (1100, 600) // Checking they have the same y position. compare-elements-position: ( "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", @@ -44,7 +44,7 @@ move-cursor-to: "//h1" assert-count: ("//*[@class='tooltip popover']", 0) // Now only the `i` should be on the next line. -size: (1055, 600) +set-window-size: (1055, 600) compare-elements-position-false: ( "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", @@ -52,7 +52,7 @@ compare-elements-position-false: ( ) // Now both the `i` and the struct name should be on the next line. -size: (980, 600) +set-window-size: (980, 600) // Checking they have the same y position. compare-elements-position: ( "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", @@ -76,7 +76,7 @@ assert-position: ( ) // Checking on mobile now. -size: (650, 600) +set-window-size: (650, 600) // Checking they have the same y position. compare-elements-position: ( "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']", @@ -124,12 +124,12 @@ define-function: ( "check-colors", (theme, header_color, content_color, type_color, trait_color), block { - goto: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html" + go-to: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html" // This is needed to ensure that the text color is computed. show-text: true // Setting the theme. - local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} // We reload the page so the local storage settings are being used. reload: @@ -253,7 +253,7 @@ press-key: "Escape" assert-window-property-false: {"scrollY": |scroll|} // Opening the mobile sidebar should close the popover. -size: (650, 600) +set-window-size: (650, 600) click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" assert-count: ("//*[@class='tooltip popover']", 1) click: ".sidebar-menu-toggle" @@ -266,7 +266,7 @@ assert-count: ("//*[@class='tooltip popover']", 1) assert-false: "//*[@class='sidebar shown']" // Also check the focus handling for the help button. -size: (1100, 600) +set-window-size: (1100, 600) reload: assert-count: ("//*[@class='tooltip popover']", 0) click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" diff --git a/tests/rustdoc-gui/overflow-tooltip-information.goml b/tests/rustdoc-gui/overflow-tooltip-information.goml index 09ad6cdd7ac6..ab7ffc24ccf8 100644 --- a/tests/rustdoc-gui/overflow-tooltip-information.goml +++ b/tests/rustdoc-gui/overflow-tooltip-information.goml @@ -1,7 +1,7 @@ // The goal of this test is to ensure that the tooltip `.information` class doesn't // have overflow and max-width CSS rules set because they create a bug in firefox on // mac. For more information: https://github.com/rust-lang/rust/issues/89185 -goto: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" assert-css: (".docblock > .example-wrap .tooltip", { "overflow-x": "visible", "max-width": "none" diff --git a/tests/rustdoc-gui/pocket-menu.goml b/tests/rustdoc-gui/pocket-menu.goml index c3649dc7bda2..4bdf31ecb199 100644 --- a/tests/rustdoc-gui/pocket-menu.goml +++ b/tests/rustdoc-gui/pocket-menu.goml @@ -1,5 +1,5 @@ // This test ensures that the "pocket menus" are working as expected. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" // First we check that the help menu doesn't exist yet. assert-false: "#help-button .popover" // Then we display the help menu. @@ -32,7 +32,7 @@ assert-css: ("#settings-menu .popover", {"display": "none"}) // We check the borders color now: // Ayu theme -local-storage: { +set-local-storage: { "rustdoc-theme": "ayu", "rustdoc-use-system-theme": "false", } @@ -47,7 +47,7 @@ compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-co compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"]) // Dark theme -local-storage: { +set-local-storage: { "rustdoc-theme": "dark", "rustdoc-use-system-theme": "false", } @@ -62,7 +62,7 @@ compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-co compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"]) // Light theme -local-storage: { +set-local-storage: { "rustdoc-theme": "light", "rustdoc-use-system-theme": "false", } @@ -77,7 +77,7 @@ compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-co compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"]) // Opening the mobile sidebar should close the settings popover. -size: (650, 600) +set-window-size: (650, 600) click: "#settings-menu a" assert-css: ("#settings-menu .popover", {"display": "block"}) click: ".sidebar-menu-toggle" diff --git a/tests/rustdoc-gui/run-on-hover.goml b/tests/rustdoc-gui/run-on-hover.goml index 8dcb62c10aaa..b5fc49eacaca 100644 --- a/tests/rustdoc-gui/run-on-hover.goml +++ b/tests/rustdoc-gui/run-on-hover.goml @@ -2,14 +2,14 @@ // Playground. That button is hidden until the user hovers over the code block. // This test checks that it is hidden, and that it shows on hover. It also // checks for its color. -goto: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" show-text: true define-function: ( "check-run-button", (theme, color, background, hover_color, hover_background), block { - local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} reload: assert-css: (".test-arrow", {"visibility": "hidden"}) move-cursor-to: ".example-wrap" diff --git a/tests/rustdoc-gui/rust-logo.goml b/tests/rustdoc-gui/rust-logo.goml index 2d15e8b96992..640ed152b0d5 100644 --- a/tests/rustdoc-gui/rust-logo.goml +++ b/tests/rustdoc-gui/rust-logo.goml @@ -1,26 +1,26 @@ // This test ensures that the correct style is applied to the rust logo in the sidebar. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" define-function: ( "check-logo", (theme, filter), block { // Going to the doc page. - goto: "file://" + |DOC_PATH| + "/test_docs/index.html" + go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" // Changing theme. - local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} reload: assert-css: (".rust-logo", {"filter": |filter|}) // Going to the source code page. - goto: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" + go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" // Changing theme (since it's local files, the local storage works by folder). - local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} reload: assert-css: (".rust-logo", {"filter": |filter|}) // Now we check that the non-rust logos don't have a CSS filter set. - goto: "file://" + |DOC_PATH| + "/huge_logo/index.html" + go-to: "file://" + |DOC_PATH| + "/huge_logo/index.html" // Changing theme on the new page (again...). - local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} reload: // Check there is no rust logo assert-false: ".rust-logo" diff --git a/tests/rustdoc-gui/scrape-examples-button-focus.goml b/tests/rustdoc-gui/scrape-examples-button-focus.goml index 16f0ced8c6ea..77061ea2a3f3 100644 --- a/tests/rustdoc-gui/scrape-examples-button-focus.goml +++ b/tests/rustdoc-gui/scrape-examples-button-focus.goml @@ -1,6 +1,6 @@ // This test ensures that the scraped examples buttons are working as expecting // when 'Enter' key is pressed when they're focused. -goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test.html" +go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test.html" // The next/prev buttons vertically scroll the code viewport between examples store-property: (initialScrollTop, ".scraped-example-list > .scraped-example pre", "scrollTop") diff --git a/tests/rustdoc-gui/scrape-examples-color.goml b/tests/rustdoc-gui/scrape-examples-color.goml index 67c58826efc2..8ddb06fccfca 100644 --- a/tests/rustdoc-gui/scrape-examples-color.goml +++ b/tests/rustdoc-gui/scrape-examples-color.goml @@ -1,5 +1,5 @@ // Check that scrape example code blocks have the expected colors. -goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html" +go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html" show-text: true define-function: ( @@ -7,7 +7,7 @@ define-function: ( (theme, highlight, highlight_focus, help_border, help_color, help_hover_border, help_hover_color), block { - local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false", } + set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false", } reload: wait-for: ".more-examples-toggle" assert-css: (".scraped-example .example-wrap .rust span.highlight:not(.focus)", { @@ -60,13 +60,13 @@ call-function: ("check-colors", { }) // Now testing the top and bottom background in case there is only one scraped examples. -goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test.html" +go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test.html" define-function: ( "check-background", (theme, background_color_start, background_color_end), block { - local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false", } + set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false", } reload: assert-css: (".scraped-example:not(.expanded) .code-wrapper::before", { "background-image": "linear-gradient(" + |background_color_start| + ", " + diff --git a/tests/rustdoc-gui/scrape-examples-fonts.goml b/tests/rustdoc-gui/scrape-examples-fonts.goml index 142f337cb74e..4c325bace976 100644 --- a/tests/rustdoc-gui/scrape-examples-fonts.goml +++ b/tests/rustdoc-gui/scrape-examples-fonts.goml @@ -1,5 +1,5 @@ // This test ensures that the correct font is used in scraped examples. -goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html" +go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html" store-value: (font, '"Fira Sans", Arial, NanumBarunGothic, sans-serif') diff --git a/tests/rustdoc-gui/scrape-examples-layout.goml b/tests/rustdoc-gui/scrape-examples-layout.goml index dad727c77577..160056d6d059 100644 --- a/tests/rustdoc-gui/scrape-examples-layout.goml +++ b/tests/rustdoc-gui/scrape-examples-layout.goml @@ -1,5 +1,5 @@ // Check that the line number column has the correct layout. -goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html" +go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html" // Check that it's not zero. assert-property-false: ( @@ -44,6 +44,6 @@ assert-position: (".scraped-example .code-wrapper", {"y": 253}) assert-position: (".scraped-example .code-wrapper .prev", {"y": 253 + |offset_y|}) // Then with mobile -size: (600, 600) +set-window-size: (600, 600) assert-position: (".scraped-example .code-wrapper", {"y": 308}) assert-position: (".scraped-example .code-wrapper .prev", {"y": 308 + |offset_y|}) diff --git a/tests/rustdoc-gui/scrape-examples-toggle.goml b/tests/rustdoc-gui/scrape-examples-toggle.goml index 2d5df6a5d25e..9cec6d2bbe84 100644 --- a/tests/rustdoc-gui/scrape-examples-toggle.goml +++ b/tests/rustdoc-gui/scrape-examples-toggle.goml @@ -1,5 +1,5 @@ // This tests checks that the "scraped examples" toggle is working as expected. -goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html" +go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html" // Checking the color of the toggle line. show-text: true @@ -7,7 +7,7 @@ define-function: ( "check-color", (theme, toggle_line_color, toggle_line_hover_color), block { - local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} reload: // Clicking "More examples..." will open additional examples diff --git a/tests/rustdoc-gui/search-error.goml b/tests/rustdoc-gui/search-error.goml index 2a10a647b53c..d21905e90ae0 100644 --- a/tests/rustdoc-gui/search-error.goml +++ b/tests/rustdoc-gui/search-error.goml @@ -1,5 +1,5 @@ // Checks that the crate search filtering is handled correctly and changes the results. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html?search=sa'%3Bda'%3Bds" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=sa'%3Bda'%3Bds" show-text: true define-function: ( @@ -7,7 +7,7 @@ define-function: ( (theme, error_background), block { // Setting the theme. - local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} // We reload the page so the local storage settings are being used. reload: diff --git a/tests/rustdoc-gui/search-filter.goml b/tests/rustdoc-gui/search-filter.goml index 5bc6e87d6d24..f114c57ff21e 100644 --- a/tests/rustdoc-gui/search-filter.goml +++ b/tests/rustdoc-gui/search-filter.goml @@ -1,5 +1,5 @@ // Checks that the crate search filtering is handled correctly and changes the results. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" show-text: true write: (".search-input", "test") // To be SURE that the search will be run. @@ -47,7 +47,7 @@ wait-for: "#search-tabs" assert-property: ("#crate-search", {"value": "all crates"}) // Checking that the URL parameter is taken into account for crate filtering. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html?search=test&filter-crate=lib2" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=test&filter-crate=lib2" wait-for: "#crate-search" assert-property: ("#crate-search", {"value": "lib2"}) assert-false: "#results .externcrate" @@ -57,10 +57,10 @@ assert-text: (".search-results-title", "Results in all crates", STARTS_WITH) // Checking the display of the crate filter. // We start with the light theme. -local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} +set-local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} reload: -timeout: 2000 +set-timeout: 2000 wait-for: "#crate-search" assert-css: ("#crate-search", { "border": "1px solid rgb(224, 224, 224)", diff --git a/tests/rustdoc-gui/search-form-elements.goml b/tests/rustdoc-gui/search-form-elements.goml index 542db348c3b1..83c6980909c2 100644 --- a/tests/rustdoc-gui/search-form-elements.goml +++ b/tests/rustdoc-gui/search-form-elements.goml @@ -1,9 +1,9 @@ // This test ensures that the elements in ".search-form" have the expected display. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" show-text: true // Ayu theme -local-storage: { +set-local-storage: { "rustdoc-theme": "ayu", "rustdoc-use-system-theme": "false", } @@ -89,7 +89,7 @@ assert-css: ( ) // Dark theme -local-storage: { +set-local-storage: { "rustdoc-theme": "dark", "rustdoc-use-system-theme": "false", } @@ -176,7 +176,7 @@ assert-css: ( ) // Light theme -local-storage: { +set-local-storage: { "rustdoc-theme": "light", "rustdoc-use-system-theme": "false", } diff --git a/tests/rustdoc-gui/search-input-mobile.goml b/tests/rustdoc-gui/search-input-mobile.goml index ce0cef77ce4f..adcb3658a270 100644 --- a/tests/rustdoc-gui/search-input-mobile.goml +++ b/tests/rustdoc-gui/search-input-mobile.goml @@ -1,11 +1,11 @@ // Test to ensure that you can click on the search input, whatever the width. // The PR which fixed it is: https://github.com/rust-lang/rust/pull/81592 -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" -size: (463, 700) +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +set-window-size: (463, 700) // We first check that the search input isn't already focused. assert-false: ("input.search-input:focus") click: "input.search-input" reload: -size: (750, 700) +set-window-size: (750, 700) click: "input.search-input" assert: ("input.search-input:focus") diff --git a/tests/rustdoc-gui/search-keyboard.goml b/tests/rustdoc-gui/search-keyboard.goml index ed975664c66a..f1d8024616bb 100644 --- a/tests/rustdoc-gui/search-keyboard.goml +++ b/tests/rustdoc-gui/search-keyboard.goml @@ -1,6 +1,6 @@ // Checks that the search tab results work correctly with function signature syntax // First, try a search-by-name -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" write: (".search-input", "Foo") // To be SURE that the search will be run. press-key: 'Enter' diff --git a/tests/rustdoc-gui/search-no-result.goml b/tests/rustdoc-gui/search-no-result.goml index b76a44fa992e..46d1856b4d68 100644 --- a/tests/rustdoc-gui/search-no-result.goml +++ b/tests/rustdoc-gui/search-no-result.goml @@ -1,5 +1,5 @@ // The goal of this test is to check the color of the "no result" links. -goto: "file://" + |DOC_PATH| + "/lib2/index.html?search=sdkfskjfsdks" +go-to: "file://" + |DOC_PATH| + "/lib2/index.html?search=sdkfskjfsdks" show-text: true define-function: ( @@ -7,7 +7,7 @@ define-function: ( (theme, link, link_hover), block { // Changing theme. - local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} reload: wait-for: "#results" assert: ".search-failed.active" diff --git a/tests/rustdoc-gui/search-reexport.goml b/tests/rustdoc-gui/search-reexport.goml index dd19f03bd1e0..fd817b58990c 100644 --- a/tests/rustdoc-gui/search-reexport.goml +++ b/tests/rustdoc-gui/search-reexport.goml @@ -1,7 +1,7 @@ // Checks that the reexports are present in the search index, can have // doc aliases and are highligted when their ID is the hash of the page. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" -local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"} +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +set-local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"} reload: // First we check that the reexport has the correct ID and no background color. assert-text: ("//*[@id='reexport.TheStdReexport']", "pub use ::std as TheStdReexport;") diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml index d6d54ec4bee9..da46a90df904 100644 --- a/tests/rustdoc-gui/search-result-color.goml +++ b/tests/rustdoc-gui/search-result-color.goml @@ -31,13 +31,13 @@ define-function: ( }, ) -goto: "file://" + |DOC_PATH| + "/test_docs/index.html?search=coo" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=coo" // This is needed so that the text color is computed. show-text: true // Ayu theme -local-storage: { +set-local-storage: { "rustdoc-theme": "ayu", "rustdoc-use-system-theme": "false", } @@ -154,7 +154,7 @@ assert-css: ( ) // Dark theme -local-storage: { +set-local-storage: { "rustdoc-theme": "dark", "rustdoc-use-system-theme": "false", } @@ -259,7 +259,7 @@ assert-css: ( ) // Light theme -local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} +set-local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} reload: // Waiting for the search results to appear... @@ -361,7 +361,7 @@ assert-css: ( ) // Check the alias. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" // If the text isn't displayed, the browser doesn't compute color style correctly... show-text: true @@ -369,7 +369,7 @@ define-function: ( "check-alias", (theme, alias, grey), block { - local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} reload: write: (".search-input", "thisisanalias") // To be SURE that the search will be run. diff --git a/tests/rustdoc-gui/search-result-description.goml b/tests/rustdoc-gui/search-result-description.goml index 9fa2108045d3..745ef31e6cbe 100644 --- a/tests/rustdoc-gui/search-result-description.goml +++ b/tests/rustdoc-gui/search-result-description.goml @@ -1,5 +1,5 @@ // This test is to ensure that the codeblocks are correctly rendered in the search results. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html?search=some_more_function" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=some_more_function" // Waiting for the search results to appear... wait-for: "#search-tabs" assert-text: (".search-results .desc code", "format!") diff --git a/tests/rustdoc-gui/search-result-display.goml b/tests/rustdoc-gui/search-result-display.goml index 20a88c36edb3..93c71f23f24e 100644 --- a/tests/rustdoc-gui/search-result-display.goml +++ b/tests/rustdoc-gui/search-result-display.goml @@ -1,6 +1,6 @@ // Checks that the search results have the expected width. -goto: "file://" + |DOC_PATH| + "/test_docs/index.html" -size: (900, 1000) +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +set-window-size: (900, 1000) write: (".search-input", "test") // To be SURE that the search will be run. press-key: 'Enter' @@ -8,7 +8,7 @@ wait-for: "#crate-search" // The width is returned by "getComputedStyle" which returns the exact number instead of the // CSS rule which is "50%"... assert-css: (".search-results div.desc", {"width": "310px"}) -size: (600, 100) +set-window-size: (600, 100) // As counter-intuitive as it may seem, in this width, the width is "100%", which is why // when computed it's larger. assert-css: (".search-results div.desc", {"width": "566px"}) @@ -18,7 +18,7 @@ assert-css: (".search-results .result-name > span", {"display": "inline"}) // Check that the crate filter ` { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: ...which immediately requires computing the super traits of `Processor` with associated type name `Input` again -note: cycle used when computing the super traits of `Processor` +note: cycle used when computing the super predicates of `Processor` --> $DIR/issue-20825.rs:5:1 | LL | pub trait Processor: Subscriber { diff --git a/tests/ui/cycle-trait/cycle-trait-supertrait-direct.stderr b/tests/ui/cycle-trait/cycle-trait-supertrait-direct.stderr index f6ffcc4b5aad..e2b2aac05ac9 100644 --- a/tests/ui/cycle-trait/cycle-trait-supertrait-direct.stderr +++ b/tests/ui/cycle-trait/cycle-trait-supertrait-direct.stderr @@ -1,15 +1,10 @@ error[E0391]: cycle detected when computing the super predicates of `Chromosome` - --> $DIR/cycle-trait-supertrait-direct.rs:3:1 - | -LL | trait Chromosome: Chromosome { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires computing the super traits of `Chromosome`... --> $DIR/cycle-trait-supertrait-direct.rs:3:19 | LL | trait Chromosome: Chromosome { | ^^^^^^^^^^ - = note: ...which again requires computing the super predicates of `Chromosome`, completing the cycle + | + = note: ...which immediately requires computing the super predicates of `Chromosome` again note: cycle used when collecting item types in top-level module --> $DIR/cycle-trait-supertrait-direct.rs:3:1 | diff --git a/tests/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr b/tests/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr index 0a2284e0efbc..c903e1146576 100644 --- a/tests/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr +++ b/tests/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr @@ -1,26 +1,16 @@ error[E0391]: cycle detected when computing the super predicates of `B` - --> $DIR/cycle-trait-supertrait-indirect.rs:7:1 - | -LL | trait B: C { - | ^^^^^^^^^^ - | -note: ...which requires computing the super traits of `B`... --> $DIR/cycle-trait-supertrait-indirect.rs:7:10 | LL | trait B: C { | ^ -note: ...which requires computing the super predicates of `C`... - --> $DIR/cycle-trait-supertrait-indirect.rs:11:1 | -LL | trait C: B { } - | ^^^^^^^^^^ -note: ...which requires computing the super traits of `C`... +note: ...which requires computing the super predicates of `C`... --> $DIR/cycle-trait-supertrait-indirect.rs:11:10 | LL | trait C: B { } | ^ = note: ...which again requires computing the super predicates of `B`, completing the cycle -note: cycle used when computing the super traits of `A` +note: cycle used when computing the super predicates of `A` --> $DIR/cycle-trait-supertrait-indirect.rs:4:10 | LL | trait A: B { diff --git a/tests/ui/infinite/infinite-trait-alias-recursion.stderr b/tests/ui/infinite/infinite-trait-alias-recursion.stderr index b925b3b018c0..683987b4943d 100644 --- a/tests/ui/infinite/infinite-trait-alias-recursion.stderr +++ b/tests/ui/infinite/infinite-trait-alias-recursion.stderr @@ -1,30 +1,15 @@ error[E0391]: cycle detected when computing the super predicates of `T1` - --> $DIR/infinite-trait-alias-recursion.rs:3:1 - | -LL | trait T1 = T2; - | ^^^^^^^^ - | -note: ...which requires computing the super traits of `T1`... --> $DIR/infinite-trait-alias-recursion.rs:3:12 | LL | trait T1 = T2; | ^^ -note: ...which requires computing the super predicates of `T2`... - --> $DIR/infinite-trait-alias-recursion.rs:6:1 | -LL | trait T2 = T3; - | ^^^^^^^^ -note: ...which requires computing the super traits of `T2`... +note: ...which requires computing the super predicates of `T2`... --> $DIR/infinite-trait-alias-recursion.rs:6:12 | LL | trait T2 = T3; | ^^ note: ...which requires computing the super predicates of `T3`... - --> $DIR/infinite-trait-alias-recursion.rs:8:1 - | -LL | trait T3 = T1 + T3; - | ^^^^^^^^ -note: ...which requires computing the super traits of `T3`... --> $DIR/infinite-trait-alias-recursion.rs:8:12 | LL | trait T3 = T1 + T3; diff --git a/tests/ui/issues/issue-12511.stderr b/tests/ui/issues/issue-12511.stderr index 789a1141c04f..558aad10946e 100644 --- a/tests/ui/issues/issue-12511.stderr +++ b/tests/ui/issues/issue-12511.stderr @@ -1,20 +1,10 @@ error[E0391]: cycle detected when computing the super predicates of `T1` - --> $DIR/issue-12511.rs:1:1 - | -LL | trait T1 : T2 { - | ^^^^^^^^^^^^^ - | -note: ...which requires computing the super traits of `T1`... --> $DIR/issue-12511.rs:1:12 | LL | trait T1 : T2 { | ^^ -note: ...which requires computing the super predicates of `T2`... - --> $DIR/issue-12511.rs:5:1 | -LL | trait T2 : T1 { - | ^^^^^^^^^^^^^ -note: ...which requires computing the super traits of `T2`... +note: ...which requires computing the super predicates of `T2`... --> $DIR/issue-12511.rs:5:12 | LL | trait T2 : T1 { diff --git a/tests/ui/issues/issue-20772.stderr b/tests/ui/issues/issue-20772.stderr index 22b9f5bd4cb9..416fd8c062fa 100644 --- a/tests/ui/issues/issue-20772.stderr +++ b/tests/ui/issues/issue-20772.stderr @@ -5,7 +5,7 @@ LL | trait T : Iterator | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: ...which immediately requires computing the super traits of `T` with associated type name `Item` again -note: cycle used when computing the super traits of `T` +note: cycle used when computing the super predicates of `T` --> $DIR/issue-20772.rs:1:1 | LL | trait T : Iterator diff --git a/tests/ui/traits/trait-upcasting/cyclic-trait-resolution.stderr b/tests/ui/traits/trait-upcasting/cyclic-trait-resolution.stderr index 15faab16abea..ca98e1831507 100644 --- a/tests/ui/traits/trait-upcasting/cyclic-trait-resolution.stderr +++ b/tests/ui/traits/trait-upcasting/cyclic-trait-resolution.stderr @@ -1,15 +1,10 @@ error[E0391]: cycle detected when computing the super predicates of `A` - --> $DIR/cyclic-trait-resolution.rs:1:1 - | -LL | trait A: B + A {} - | ^^^^^^^^^^^^^^ - | -note: ...which requires computing the super traits of `A`... --> $DIR/cyclic-trait-resolution.rs:1:14 | LL | trait A: B + A {} | ^ - = note: ...which again requires computing the super predicates of `A`, completing the cycle + | + = note: ...which immediately requires computing the super predicates of `A` again note: cycle used when collecting item types in top-level module --> $DIR/cyclic-trait-resolution.rs:1:1 | From 4560b61cd15aa026a03a64c99ead1edf7896826f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 31 Jan 2023 21:22:11 +0000 Subject: [PATCH 208/272] Broken tests --- tests/ui/closures/self-supertrait-bounds.rs | 14 ++++++++ .../ui/lint/unused/trait-alias-supertrait.rs | 15 +++++++++ .../traits/alias/dont-elaborate-non-self.rs | 10 ++++++ .../alias-where-clause-isnt-supertrait.rs | 33 +++++++++++++++++++ 4 files changed, 72 insertions(+) create mode 100644 tests/ui/closures/self-supertrait-bounds.rs create mode 100644 tests/ui/lint/unused/trait-alias-supertrait.rs create mode 100644 tests/ui/traits/alias/dont-elaborate-non-self.rs create mode 100644 tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs diff --git a/tests/ui/closures/self-supertrait-bounds.rs b/tests/ui/closures/self-supertrait-bounds.rs new file mode 100644 index 000000000000..f4f1cea6b817 --- /dev/null +++ b/tests/ui/closures/self-supertrait-bounds.rs @@ -0,0 +1,14 @@ +// check-pass + +// Makes sure that we only consider `Self` supertrait predicates while +// elaborating during closure signature deduction. + +#![feature(trait_alias)] + +trait Confusing = Fn(i32) where F: Fn(u32); + +fn alias, F>(_: T, _: F) {} + +fn main() { + alias(|_| {}, |_| {}); +} diff --git a/tests/ui/lint/unused/trait-alias-supertrait.rs b/tests/ui/lint/unused/trait-alias-supertrait.rs new file mode 100644 index 000000000000..46f00c06bf1c --- /dev/null +++ b/tests/ui/lint/unused/trait-alias-supertrait.rs @@ -0,0 +1,15 @@ +// check-pass + +// Make sure that we only consider *Self* supertrait predicates +// in the `unused_must_use` lint. + +#![feature(trait_alias)] +#![deny(unused_must_use)] + +trait Foo = Sized where T: Iterator; + +fn test() -> impl Foo {} + +fn main() { + test::>(); +} diff --git a/tests/ui/traits/alias/dont-elaborate-non-self.rs b/tests/ui/traits/alias/dont-elaborate-non-self.rs new file mode 100644 index 000000000000..4f9eaacb8ed0 --- /dev/null +++ b/tests/ui/traits/alias/dont-elaborate-non-self.rs @@ -0,0 +1,10 @@ +#![feature(trait_alias)] + +use std::future::Future; + +trait F> = Fn() -> Fut; + +fn f(a: dyn F) {} +//~^ ERROR the size for values of type `(dyn Fn() -> Fut + 'static)` cannot be known at compilation time + +fn main() {} diff --git a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs new file mode 100644 index 000000000000..4a5e445d1efb --- /dev/null +++ b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs @@ -0,0 +1,33 @@ +#![feature(trait_upcasting)] +#![feature(trait_alias)] + +// Although we *elaborate* `T: Alias` to `i32: B`, we should +// not consider `B` to be a supertrait of the type. +trait Alias = A where i32: B; + +trait A {} + +trait B { + fn test(&self); +} + +trait C: Alias {} + +impl A for () {} + +impl C for () {} + +impl B for i32 { + fn test(&self) { + println!("hi {self}"); + } +} + +fn test(x: &dyn C) -> &dyn B { + x + //~^ ERROR mismatched types +} + +fn main() { + let x: &dyn C = &(); +} From 7ec72efe10df28fcf5c6ec13c2a487572041be59 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 2 Feb 2023 21:22:02 +0000 Subject: [PATCH 209/272] Allow the elaborator to only filter to real supertraits --- .../rustc_hir_analysis/src/astconv/mod.rs | 66 ++++++++++--------- compiler/rustc_hir_typeck/src/closure.rs | 5 +- compiler/rustc_infer/src/traits/util.rs | 41 +++++++----- compiler/rustc_lint/src/unused.rs | 2 + .../src/solve/assembly/mod.rs | 5 +- .../alias/dont-elaborate-non-self.stderr | 20 ++++++ .../alias-where-clause-isnt-supertrait.stderr | 14 ++++ 7 files changed, 106 insertions(+), 47 deletions(-) create mode 100644 tests/ui/traits/alias/dont-elaborate-non-self.stderr create mode 100644 tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 37c894348cd4..8cb95610da08 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1663,39 +1663,45 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }) }); - let existential_projections = projection_bounds.iter().map(|(bound, _)| { - bound.map_bound(|mut b| { - assert_eq!(b.projection_ty.self_ty(), dummy_self); + let existential_projections = projection_bounds + .iter() + // We filter out traits that don't have `Self` as their self type above, + // we need to do the same for projections. + .filter(|(bound, _)| bound.skip_binder().self_ty() == dummy_self) + .map(|(bound, _)| { + bound.map_bound(|mut b| { + assert_eq!(b.projection_ty.self_ty(), dummy_self); - // Like for trait refs, verify that `dummy_self` did not leak inside default type - // parameters. - let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| { - if arg.walk().any(|arg| arg == dummy_self.into()) { - return true; + // Like for trait refs, verify that `dummy_self` did not leak inside default type + // parameters. + let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| { + if arg.walk().any(|arg| arg == dummy_self.into()) { + return true; + } + false + }); + if references_self { + let guar = tcx.sess.delay_span_bug( + span, + "trait object projection bounds reference `Self`", + ); + let substs: Vec<_> = b + .projection_ty + .substs + .iter() + .map(|arg| { + if arg.walk().any(|arg| arg == dummy_self.into()) { + return tcx.ty_error(guar).into(); + } + arg + }) + .collect(); + b.projection_ty.substs = tcx.mk_substs(&substs); } - false - }); - if references_self { - let guar = tcx - .sess - .delay_span_bug(span, "trait object projection bounds reference `Self`"); - let substs: Vec<_> = b - .projection_ty - .substs - .iter() - .map(|arg| { - if arg.walk().any(|arg| arg == dummy_self.into()) { - return tcx.ty_error(guar).into(); - } - arg - }) - .collect(); - b.projection_ty.substs = tcx.mk_substs(&substs); - } - ty::ExistentialProjection::erase_self_ty(tcx, b) - }) - }); + ty::ExistentialProjection::erase_self_ty(tcx, b) + }) + }); let regular_trait_predicates = existential_trait_refs .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait)); diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 15eec42d7864..8c2495e1dd8c 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -210,7 +210,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // and we want to keep inference generally in the same order of // the registered obligations. predicates.rev(), - ) { + ) + // We only care about self bounds + .filter_only_self() + { debug!(?pred); let bound_predicate = pred.kind(); diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 1f7c7652d94f..ef01d5d513bb 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -69,6 +69,7 @@ impl<'tcx> Extend> for PredicateSet<'tcx> { pub struct Elaborator<'tcx, O> { stack: Vec, visited: PredicateSet<'tcx>, + only_self: bool, } /// Describes how to elaborate an obligation into a sub-obligation. @@ -170,7 +171,8 @@ pub fn elaborate<'tcx, O: Elaboratable<'tcx>>( tcx: TyCtxt<'tcx>, obligations: impl IntoIterator, ) -> Elaborator<'tcx, O> { - let mut elaborator = Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx) }; + let mut elaborator = + Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx), only_self: false }; elaborator.extend_deduped(obligations); elaborator } @@ -185,14 +187,25 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate()))); } + /// Filter to only the supertraits of trait predicates, i.e. only the predicates + /// that have `Self` as their self type, instead of all implied predicates. + pub fn filter_only_self(mut self) -> Self { + self.only_self = true; + self + } + fn elaborate(&mut self, elaboratable: &O) { let tcx = self.visited.tcx; let bound_predicate = elaboratable.predicate().kind(); match bound_predicate.skip_binder() { ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { - // Get predicates declared on the trait. - let predicates = tcx.implied_predicates_of(data.def_id()); + // Get predicates implied by the trait, or only super predicates if we only care about self predicates. + let predicates = if self.only_self { + tcx.super_predicates_of(data.def_id()) + } else { + tcx.implied_predicates_of(data.def_id()) + }; let obligations = predicates.predicates.iter().enumerate().map(|(index, &(mut pred, span))| { @@ -350,18 +363,16 @@ pub fn supertraits<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, ) -> impl Iterator> { - let pred: ty::Predicate<'tcx> = trait_ref.to_predicate(tcx); - FilterToTraits::new(elaborate(tcx, [pred])) + elaborate(tcx, [trait_ref.to_predicate(tcx)]).filter_only_self().filter_to_traits() } pub fn transitive_bounds<'tcx>( tcx: TyCtxt<'tcx>, trait_refs: impl Iterator>, ) -> impl Iterator> { - FilterToTraits::new(elaborate( - tcx, - trait_refs.map(|trait_ref| -> ty::Predicate<'tcx> { trait_ref.to_predicate(tcx) }), - )) + elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.to_predicate(tcx))) + .filter_only_self() + .filter_to_traits() } /// A specialized variant of `elaborate` that only elaborates trait references that may @@ -402,18 +413,18 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>( // Other /////////////////////////////////////////////////////////////////////////// +impl<'tcx> Elaborator<'tcx, ty::Predicate<'tcx>> { + fn filter_to_traits(self) -> FilterToTraits { + FilterToTraits { base_iterator: self } + } +} + /// A filter around an iterator of predicates that makes it yield up /// just trait references. pub struct FilterToTraits { base_iterator: I, } -impl FilterToTraits { - fn new(base: I) -> FilterToTraits { - FilterToTraits { base_iterator: base } - } -} - impl<'tcx, I: Iterator>> Iterator for FilterToTraits { type Item = ty::PolyTraitRef<'tcx>; diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 35c461f5acee..1159d11e5c0c 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -255,6 +255,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ty::Adt(def, _) => is_def_must_use(cx, def.did(), span), ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { elaborate(cx.tcx, cx.tcx.explicit_item_bounds(def).iter().cloned()) + // We only care about self bounds for the impl-trait + .filter_only_self() .find_map(|(pred, _span)| { // We only look at the `DefId`, so it is safe to skip the binder here. if let ty::PredicateKind::Clause(ty::Clause::Trait( diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 12ee80b6722b..3fb1d49b3380 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -498,7 +498,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let tcx = self.tcx(); let own_bounds: FxIndexSet<_> = bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)).collect(); - for assumption in elaborate(tcx, own_bounds.iter().copied()) { + for assumption in elaborate(tcx, own_bounds.iter().copied()) + // we only care about bounds that match the `Self` type + .filter_only_self() + { // FIXME: Predicates are fully elaborated in the object type's existential bounds // list. We want to only consider these pre-elaborated projections, and not other // projection predicates that we reach by elaborating the principal trait ref, diff --git a/tests/ui/traits/alias/dont-elaborate-non-self.stderr b/tests/ui/traits/alias/dont-elaborate-non-self.stderr new file mode 100644 index 000000000000..247a4f812807 --- /dev/null +++ b/tests/ui/traits/alias/dont-elaborate-non-self.stderr @@ -0,0 +1,20 @@ +error[E0277]: the size for values of type `(dyn Fn() -> Fut + 'static)` cannot be known at compilation time + --> $DIR/dont-elaborate-non-self.rs:7:11 + | +LL | fn f(a: dyn F) {} + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Fn() -> Fut + 'static)` + = help: unsized fn params are gated as an unstable feature +help: you can use `impl Trait` as the argument type + | +LL | fn f(a: impl F) {} + | ~~~~ +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn f(a: &dyn F) {} + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr new file mode 100644 index 000000000000..5574a0320895 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/alias-where-clause-isnt-supertrait.rs:27:5 + | +LL | fn test(x: &dyn C) -> &dyn B { + | ------ expected `&dyn B` because of return type +LL | x + | ^ expected trait `B`, found trait `C` + | + = note: expected reference `&dyn B` + found reference `&dyn C` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From f7c04edadcc1e94bae1e2cc9087319ed2cd76f30 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 11 Apr 2023 19:33:44 +0100 Subject: [PATCH 210/272] Update cargo --- Cargo.lock | 16 ++++++++-------- src/tools/cargo | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 321e9cc35c58..e7605f2f5e30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1841,9 +1841,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be36bc9e0546df253c0cc41fd0af34f5e92845ad8509462ec76672fac6997f5b" +checksum = "89511277159354bea13ae1e53e0c9ab85ba1b20d7e91618fa30e6bc5566857fb" dependencies = [ "bitflags", "libc", @@ -1856,9 +1856,9 @@ dependencies = [ [[package]] name = "git2-curl" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7577f4e6341ba7c90d883511130a45b956c274ba5f4d205d9f9da990f654cd33" +checksum = "f8f8b7432b72928cff76f69e59ed5327f94a52763731e71274960dee72fe5f8c" dependencies = [ "curl", "git2", @@ -2962,9 +2962,9 @@ dependencies = [ [[package]] name = "libgit2-sys" -version = "0.14.1+1.5.0" +version = "0.15.0+1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a07fb2692bc3593bda59de45a502bb3071659f2c515e28c71e728306b038e17" +checksum = "032e537ae4dd4e50c877f258dc55fcd0657b5021f454094a425bb6bcc9edea4c" dependencies = [ "cc", "libc", @@ -3002,9 +3002,9 @@ dependencies = [ [[package]] name = "libssh2-sys" -version = "0.2.23" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b094a36eb4b8b8c8a7b4b8ae43b2944502be3e59cd87687595cf6b0a71b3f4ca" +checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee" dependencies = [ "cc", "libc", diff --git a/src/tools/cargo b/src/tools/cargo index 0e474cfd7b16..7bf43f028ba5 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 0e474cfd7b16b018cf46e95da3f6a5b2f1f6a9e7 +Subproject commit 7bf43f028ba5eb1f4d70d271c2546c38512c9875 From 06ec5faccbe09ddb5e6a29f996e824f28b3efc06 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 12 Apr 2023 06:24:49 +0900 Subject: [PATCH 211/272] Add regression test for #59003 Signed-off-by: Yuki Okushi --- tests/ui/lint/dead-code/issue-59003.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/ui/lint/dead-code/issue-59003.rs diff --git a/tests/ui/lint/dead-code/issue-59003.rs b/tests/ui/lint/dead-code/issue-59003.rs new file mode 100644 index 000000000000..966d6412870b --- /dev/null +++ b/tests/ui/lint/dead-code/issue-59003.rs @@ -0,0 +1,18 @@ +// check-pass + +// Make sure we don't have any false positives about the "struct is never constructed" lint. + +#![deny(dead_code)] + +struct Foo { + #[allow(dead_code)] + inner: u32, +} + +impl From for Foo { + fn from(inner: u32) -> Self { + Self { inner } + } +} + +fn main() {} From 74463214a619a7e9d2d0dc5c6e299c0d0f6f14a5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 12 Apr 2023 07:44:37 +1000 Subject: [PATCH 212/272] Rename `NllVisitor` as `RegionRenumberer`. It's a more descriptive name. --- compiler/rustc_borrowck/src/renumber.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 07962267594c..2c1d74ef9ca8 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -20,13 +20,13 @@ pub fn renumber_mir<'tcx>( ) { debug!(?body.arg_count); - let mut visitor = NllVisitor { infcx }; + let mut renumberer = RegionRenumberer { infcx }; for body in promoted.iter_mut() { - visitor.visit_body(body); + renumberer.visit_body(body); } - visitor.visit_body(body); + renumberer.visit_body(body); } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] @@ -64,11 +64,11 @@ impl RegionCtxt { } } -struct NllVisitor<'a, 'tcx> { +struct RegionRenumberer<'a, 'tcx> { infcx: &'a BorrowckInferCtxt<'a, 'tcx>, } -impl<'a, 'tcx> NllVisitor<'a, 'tcx> { +impl<'a, 'tcx> RegionRenumberer<'a, 'tcx> { /// Replaces all regions appearing in `value` with fresh inference /// variables. fn renumber_regions(&mut self, value: T, region_ctxt_fn: F) -> T @@ -83,7 +83,7 @@ impl<'a, 'tcx> NllVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { +impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } From c9b0635679fc5bb4fd157e1eaad8e7f21705d68a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 11 Apr 2023 17:29:51 +1000 Subject: [PATCH 213/272] Inline and remove `DescriptionCtx::add_to`. It has a single callsite. --- compiler/rustc_infer/src/errors/note_and_explain.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index 744fb27635aa..c4f2cf62ddda 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -108,11 +108,6 @@ impl<'a> DescriptionCtx<'a> { } Some(me) } - - fn add_to(self, diag: &mut rustc_errors::Diagnostic) { - diag.set_arg("desc_kind", self.kind); - diag.set_arg("desc_arg", self.arg); - } } pub enum PrefixKind { @@ -196,10 +191,11 @@ impl AddToDiagnostic for RegionExplanation<'_> { { diag.set_arg("pref_kind", self.prefix); diag.set_arg("suff_kind", self.suffix); - let desc_span = self.desc.span; - self.desc.add_to(diag); + diag.set_arg("desc_kind", self.desc.kind); + diag.set_arg("desc_arg", self.desc.arg); + let msg = f(diag, fluent::infer_region_explanation.into()); - if let Some(span) = desc_span { + if let Some(span) = self.desc.span { diag.span_note(span, msg); } else { diag.note(msg); From 877777f5bc0d02d409bbc6d68d8a7de8529254be Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 11 Apr 2023 17:14:41 +1000 Subject: [PATCH 214/272] Inline and remove `DescriptionCtx::from_early_bound_and_free_regions`. It has a single call site, and the code is clearer with all region kinds handled in one function, instead of splitting the handling across two functions. The commit also changes `DescriptionCtx::new` to use a more declarative style, instead of creating a default `DescriptionCtx` and modifying it, which I find easier to read. --- .../src/errors/note_and_explain.rs | 133 ++++++++---------- 1 file changed, 55 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index c4f2cf62ddda..7328241dfbca 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -4,7 +4,6 @@ use rustc_errors::{self, AddToDiagnostic, Diagnostic, IntoDiagnosticArg, Subdiag use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{symbol::kw, Span}; -#[derive(Default)] struct DescriptionCtx<'a> { span: Option, kind: &'a str, @@ -17,19 +16,63 @@ impl<'a> DescriptionCtx<'a> { region: ty::Region<'tcx>, alt_span: Option, ) -> Option { - let mut me = DescriptionCtx::default(); - me.span = alt_span; - match *region { - ty::ReEarlyBound(_) | ty::ReFree(_) => { - return Self::from_early_bound_and_free_regions(tcx, region); + let (span, kind, arg) = match *region { + ty::ReEarlyBound(ref br) => { + let scope = region.free_region_binding_scope(tcx).expect_local(); + let span = if let Some(param) = + tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) + { + param.span + } else { + tcx.def_span(scope) + }; + if br.has_name() { + (Some(span), "as_defined", br.name.to_string()) + } else { + (Some(span), "as_defined_anon", String::new()) + } } - ty::ReStatic => { - me.kind = "restatic"; + ty::ReFree(ref fr) => { + if !fr.bound_region.is_named() + && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) + { + (Some(ty.span), "defined_here", String::new()) + } else { + let scope = region.free_region_binding_scope(tcx).expect_local(); + match fr.bound_region { + ty::BoundRegionKind::BrNamed(_, name) => { + let span = if let Some(param) = tcx + .hir() + .get_generics(scope) + .and_then(|generics| generics.get_named(name)) + { + param.span + } else { + tcx.def_span(scope) + }; + if name == kw::UnderscoreLifetime { + (Some(span), "as_defined_anon", String::new()) + } else { + (Some(span), "as_defined", name.to_string()) + } + } + ty::BrAnon(span) => { + let span = match span { + Some(_) => span, + None => Some(tcx.def_span(scope)), + }; + (span, "defined_here", String::new()) + } + _ => { + (Some(tcx.def_span(scope)), "defined_here_reg", region.to_string()) + } + } + } } - ty::RePlaceholder(_) => return None, + ty::ReStatic => (alt_span, "restatic", String::new()), - ty::ReError(_) => return None, + ty::RePlaceholder(_) | ty::ReError(_) => return None, // FIXME(#13998) RePlaceholder should probably print like // ReFree rather than dumping Debug output on the user. @@ -37,76 +80,10 @@ impl<'a> DescriptionCtx<'a> { // We shouldn't really be having unification failures with ReVar // and ReLateBound though. ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => { - me.kind = "revar"; - me.arg = format!("{:?}", region); + (alt_span, "revar", format!("{:?}", region)) } }; - Some(me) - } - - fn from_early_bound_and_free_regions<'tcx>( - tcx: TyCtxt<'tcx>, - region: ty::Region<'tcx>, - ) -> Option { - let mut me = DescriptionCtx::default(); - let scope = region.free_region_binding_scope(tcx).expect_local(); - match *region { - ty::ReEarlyBound(ref br) => { - let mut sp = tcx.def_span(scope); - if let Some(param) = - tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) - { - sp = param.span; - } - if br.has_name() { - me.kind = "as_defined"; - me.arg = br.name.to_string(); - } else { - me.kind = "as_defined_anon"; - }; - me.span = Some(sp) - } - ty::ReFree(ref fr) => { - if !fr.bound_region.is_named() - && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) - { - me.kind = "defined_here"; - me.span = Some(ty.span); - } else { - match fr.bound_region { - ty::BoundRegionKind::BrNamed(_, name) => { - let mut sp = tcx.def_span(scope); - if let Some(param) = - tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name)) - { - sp = param.span; - } - if name == kw::UnderscoreLifetime { - me.kind = "as_defined_anon"; - } else { - me.kind = "as_defined"; - me.arg = name.to_string(); - }; - me.span = Some(sp); - } - ty::BrAnon(span) => { - me.kind = "defined_here"; - me.span = match span { - Some(_) => span, - None => Some(tcx.def_span(scope)), - } - }, - _ => { - me.kind = "defined_here_reg"; - me.arg = region.to_string(); - me.span = Some(tcx.def_span(scope)); - }, - } - } - } - _ => bug!(), - } - Some(me) + Some(DescriptionCtx { span, kind, arg }) } } From 76d0c6f5186826d57d80bb5f2435454837c8a449 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 11 Apr 2023 18:50:52 +1000 Subject: [PATCH 215/272] Inline and remove `msg_span_from_early_bound_and_free_regions`. For similar reasons to the previous commit. --- .../src/infer/error_reporting/mod.rs | 114 ++++++++---------- 1 file changed, 52 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 7901bc940212..b68ffaed69da 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -185,9 +185,58 @@ fn msg_span_from_named_region<'tcx>( alt_span: Option, ) -> (String, Option) { match *region { - ty::ReEarlyBound(_) | ty::ReFree(_) => { - let (msg, span) = msg_span_from_early_bound_and_free_regions(tcx, region); - (msg, Some(span)) + ty::ReEarlyBound(ref br) => { + let scope = region.free_region_binding_scope(tcx).expect_local(); + let span = if let Some(param) = + tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) + { + param.span + } else { + tcx.def_span(scope) + }; + let text = if br.has_name() { + format!("the lifetime `{}` as defined here", br.name) + } else { + "the anonymous lifetime as defined here".to_string() + }; + (text, Some(span)) + } + ty::ReFree(ref fr) => { + if !fr.bound_region.is_named() + && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) + { + ("the anonymous lifetime defined here".to_string(), Some(ty.span)) + } else { + let scope = region.free_region_binding_scope(tcx).expect_local(); + match fr.bound_region { + ty::BoundRegionKind::BrNamed(_, name) => { + let span = if let Some(param) = + tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name)) + { + param.span + } else { + tcx.def_span(scope) + }; + let text = if name == kw::UnderscoreLifetime { + "the anonymous lifetime as defined here".to_string() + } else { + format!("the lifetime `{}` as defined here", name) + }; + (text, Some(span)) + } + ty::BrAnon(span) => ( + "the anonymous lifetime as defined here".to_string(), + Some(match span { + Some(span) => span, + None => tcx.def_span(scope) + }) + ), + _ => ( + format!("the lifetime `{}` as defined here", region), + Some(tcx.def_span(scope)), + ), + } + } } ty::ReStatic => ("the static lifetime".to_owned(), alt_span), ty::RePlaceholder(ty::PlaceholderRegion { @@ -206,65 +255,6 @@ fn msg_span_from_named_region<'tcx>( } } -fn msg_span_from_early_bound_and_free_regions<'tcx>( - tcx: TyCtxt<'tcx>, - region: ty::Region<'tcx>, -) -> (String, Span) { - let scope = region.free_region_binding_scope(tcx).expect_local(); - match *region { - ty::ReEarlyBound(ref br) => { - let mut sp = tcx.def_span(scope); - if let Some(param) = - tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) - { - sp = param.span; - } - let text = if br.has_name() { - format!("the lifetime `{}` as defined here", br.name) - } else { - "the anonymous lifetime as defined here".to_string() - }; - (text, sp) - } - ty::ReFree(ref fr) => { - if !fr.bound_region.is_named() - && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) - { - ("the anonymous lifetime defined here".to_string(), ty.span) - } else { - match fr.bound_region { - ty::BoundRegionKind::BrNamed(_, name) => { - let mut sp = tcx.def_span(scope); - if let Some(param) = - tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name)) - { - sp = param.span; - } - let text = if name == kw::UnderscoreLifetime { - "the anonymous lifetime as defined here".to_string() - } else { - format!("the lifetime `{}` as defined here", name) - }; - (text, sp) - } - ty::BrAnon(span) => ( - "the anonymous lifetime as defined here".to_string(), - match span { - Some(span) => span, - None => tcx.def_span(scope) - } - ), - _ => ( - format!("the lifetime `{}` as defined here", region), - tcx.def_span(scope), - ), - } - } - } - _ => bug!(), - } -} - fn emit_msg_span( err: &mut Diagnostic, prefix: &str, From f45417bd1cb9a1dce5506d0d79dda12a6dc568e4 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Wed, 12 Apr 2023 10:20:00 +0800 Subject: [PATCH 216/272] doc: loongarch: Fix typos --- src/doc/rustc/src/platform-support/loongarch-linux.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/rustc/src/platform-support/loongarch-linux.md b/src/doc/rustc/src/platform-support/loongarch-linux.md index e046ec244ece..d7d31d8724c6 100644 --- a/src/doc/rustc/src/platform-support/loongarch-linux.md +++ b/src/doc/rustc/src/platform-support/loongarch-linux.md @@ -6,12 +6,12 @@ [LoongArch]: https://loongson.github.io/LoongArch-Documentation/README-EN.html -The target name follow this format: `--, where `` specifies the CPU family/model, `` specifies the vendor and `` the operating system name. +The target name follow this format: `--`, where `` specifies the CPU family/model, `` specifies the vendor and `` the operating system name. While the integer base ABI is implied by the machine field, the floating point base ABI type is encoded into the os field of the specifier using the string suffix ``. | `` | `Description` | |------------------------|--------------------------------------------------------------------| -| f64 | The base ABI use 64-bits FPRs for parameter passing.(lp64d)| +| f64 | The base ABI use 64-bits FPRs for parameter passing. (lp64d)| | f32 | The base ABI uses 32-bit FPRs for parameter passing. (lp64f)| | sf | The base ABI uses no FPR for parameter passing. (lp64s) | @@ -26,9 +26,9 @@ While the integer base ABI is implied by the machine field, the floating po ## Target maintainers -- [ZHAI xiaojuan](https://github.com/zhaixiaojuan) `zhaixiaojuan@loongson.cn` -- [WANG rui](https://github.com/heiher) `wangrui@loongson.cn` -- [ZHAI xiang](https://github.com/xiangzhai) `zhaixiang@loongson.cn` +- [ZHAI Xiaojuan](https://github.com/zhaixiaojuan) `zhaixiaojuan@loongson.cn` +- [WANG Rui](https://github.com/heiher) `wangrui@loongson.cn` +- [ZHAI Xiang](https://github.com/xiangzhai) `zhaixiang@loongson.cn` - [WANG Xuerui](https://github.com/xen0n) `git@xen0n.name` ## Requirements From a19adefa0e5aca0aabca2430530577ee140e4efa Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 12 Apr 2023 10:24:36 +0200 Subject: [PATCH 217/272] region error cleanup - require `TypeErrCtxt` to always result in an error - move `resolve_regions_and_report_errors` to the `ObligationCtxt` - merge `process_registered_region_obligations` into `resolve_regions` --- .../rustc_hir_analysis/src/check/check.rs | 7 +- .../src/check/compare_impl_item.rs | 40 ++--- .../rustc_hir_analysis/src/check/wfcheck.rs | 11 +- .../src/coherence/builtin.rs | 6 +- .../src/impl_wf_check/min_specialization.rs | 3 +- .../src/infer/error_reporting/mod.rs | 30 +++- compiler/rustc_infer/src/infer/mod.rs | 142 +----------------- .../rustc_infer/src/infer/outlives/mod.rs | 104 ++++++++++++- .../src/infer/outlives/obligations.rs | 47 ++---- .../src/traits/auto_trait.rs | 3 +- .../src/traits/coherence.rs | 3 - .../src/traits/engine.rs | 19 +++ .../rustc_trait_selection/src/traits/misc.rs | 4 - 13 files changed, 183 insertions(+), 236 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 8617bca08258..0bb98fdf2a23 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -452,11 +452,8 @@ fn check_opaque_meets_bounds<'tcx>( hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {} // Can have different predicates to their defining use hir::OpaqueTyOrigin::TyAlias => { - let outlives_environment = OutlivesEnvironment::new(param_env); - let _ = infcx.err_ctxt().check_region_obligations_and_report_errors( - defining_use_anchor, - &outlives_environment, - ); + let outlives_env = OutlivesEnvironment::new(param_env); + let _ = ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env); } } // Clean up after ourselves diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index f6c2004c4a67..5d119a7737a4 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -332,10 +332,6 @@ fn compare_method_predicate_entailment<'tcx>( param_env, infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys.clone()), ); - infcx.process_registered_region_obligations( - outlives_env.region_bound_pairs(), - outlives_env.param_env, - ); let errors = infcx.resolve_regions(&outlives_env); if !errors.is_empty() { // FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT @@ -722,18 +718,18 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( return Err(reported); } + let collected_types = collector.types; + // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. - let outlives_environment = OutlivesEnvironment::with_bounds( + let outlives_env = OutlivesEnvironment::with_bounds( param_env, infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys), ); - infcx - .err_ctxt() - .check_region_obligations_and_report_errors(impl_m_def_id, &outlives_environment)?; + ocx.resolve_regions_and_report_errors(impl_m_def_id, &outlives_env)?; let mut collected_tys = FxHashMap::default(); - for (def_id, (ty, substs)) in collector.types { + for (def_id, (ty, substs)) in collected_types { match infcx.fully_resolve(ty) { Ok(ty) => { // `ty` contains free regions that we created earlier while liberating the @@ -1742,11 +1738,8 @@ pub(super) fn compare_impl_const_raw( return Err(infcx.err_ctxt().report_fulfillment_errors(&errors)); } - let outlives_environment = OutlivesEnvironment::new(param_env); - infcx - .err_ctxt() - .check_region_obligations_and_report_errors(impl_const_item_def, &outlives_environment)?; - Ok(()) + let outlives_env = OutlivesEnvironment::new(param_env); + ocx.resolve_regions_and_report_errors(impl_const_item_def, &outlives_env) } pub(super) fn compare_impl_ty<'tcx>( @@ -1845,13 +1838,8 @@ fn compare_type_predicate_entailment<'tcx>( // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. - let outlives_environment = OutlivesEnvironment::new(param_env); - infcx.err_ctxt().check_region_obligations_and_report_errors( - impl_ty.def_id.expect_local(), - &outlives_environment, - )?; - - Ok(()) + let outlives_env = OutlivesEnvironment::new(param_env); + ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env) } /// Validate that `ProjectionCandidate`s created for this associated type will @@ -2063,14 +2051,8 @@ pub(super) fn check_type_bounds<'tcx>( // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, assumed_wf_types); - let outlives_environment = OutlivesEnvironment::with_bounds(param_env, implied_bounds); - - infcx.err_ctxt().check_region_obligations_and_report_errors( - impl_ty.def_id.expect_local(), - &outlives_environment, - )?; - - Ok(()) + let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); + ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env) } fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str { diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index c03621fcfb22..53197bc84910 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -114,11 +114,9 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( return; } - let outlives_environment = OutlivesEnvironment::with_bounds(param_env, implied_bounds); + let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); - let _ = infcx - .err_ctxt() - .check_region_obligations_and_report_errors(body_def_id, &outlives_environment); + let _ = wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env); } fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) { @@ -680,12 +678,7 @@ fn resolve_regions_with_wf_tys<'tcx>( add_constraints(&infcx, region_bound_pairs); - infcx.process_registered_region_obligations( - outlives_environment.region_bound_pairs(), - param_env, - ); let errors = infcx.resolve_regions(&outlives_environment); - debug!(?errors, "errors"); // If we were able to prove that the type outlives the region without diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index ac7c68d9c4b3..0f40cca9427b 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -354,9 +354,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef // Finally, resolve all regions. let outlives_env = OutlivesEnvironment::new(param_env); - let _ = infcx - .err_ctxt() - .check_region_obligations_and_report_errors(impl_did, &outlives_env); + let _ = ocx.resolve_regions_and_report_errors(impl_did, &outlives_env); } } _ => { @@ -592,7 +590,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe // Finally, resolve all regions. let outlives_env = OutlivesEnvironment::new(param_env); - let _ = infcx.err_ctxt().check_region_obligations_and_report_errors(impl_did, &outlives_env); + let _ = ocx.resolve_regions_and_report_errors(impl_did, &outlives_env); CoerceUnsizedInfo { custom_kind: kind } } diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 35785e81ff49..eb2fc395223e 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -180,8 +180,7 @@ fn get_impl_substs( let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types); let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); - let _ = - infcx.err_ctxt().check_region_obligations_and_report_errors(impl1_def_id, &outlives_env); + let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env); let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else { let span = tcx.def_span(impl1_def_id); tcx.sess.emit_err(SubstsOnOverriddenImpl { span }); diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 7901bc940212..f6bed12ee2d4 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -74,6 +74,7 @@ use rustc_middle::ty::{ self, error::TypeError, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, }; +use rustc_span::DUMMY_SP; use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; use std::ops::{ControlFlow, Deref}; @@ -113,7 +114,11 @@ fn escape_literal(s: &str) -> String { /// A helper for building type related errors. The `typeck_results` /// field is only populated during an in-progress typeck. -/// Get an instance by calling `InferCtxt::err` or `FnCtxt::infer_err`. +/// Get an instance by calling `InferCtxt::err_ctxt` or `FnCtxt::err_ctxt`. +/// +/// You must only create this if you intend to actually emit an error. +/// This provides a lot of utility methods which should not be used +/// during the happy path. pub struct TypeErrCtxt<'a, 'tcx> { pub infcx: &'a InferCtxt<'tcx>, pub typeck_results: Option>>, @@ -125,6 +130,19 @@ pub struct TypeErrCtxt<'a, 'tcx> { Box) -> Vec<(Ty<'tcx>, Vec>)> + 'a>, } +impl Drop for TypeErrCtxt<'_, '_> { + fn drop(&mut self) { + if let Some(_) = self.infcx.tcx.sess.has_errors_or_delayed_span_bugs() { + // ok, emitted an error. + } else { + self.infcx + .tcx + .sess + .delay_span_bug(DUMMY_SP, "used a `TypeErrCtxt` without failing compilation"); + } + } +} + impl TypeErrCtxt<'_, '_> { /// This is just to avoid a potential footgun of accidentally /// dropping `typeck_results` by calling `InferCtxt::err_ctxt` @@ -419,7 +437,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, generic_param_scope: LocalDefId, errors: &[RegionResolutionError<'tcx>], - ) { + ) -> ErrorGuaranteed { + if let Some(guaranteed) = self.infcx.tainted_by_errors() { + return guaranteed; + } + debug!("report_region_errors(): {} errors to start", errors.len()); // try to pre-process the errors, which will group some of them @@ -499,6 +521,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } } + + self.tcx + .sess + .delay_span_bug(self.tcx.def_span(generic_param_scope), "expected region errors") } // This method goes through all the errors and try to group certain types diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index b4f2ad0bb343..66f51328bbe7 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -45,8 +45,7 @@ use self::combine::CombineFields; use self::error_reporting::TypeErrCtxt; use self::free_regions::RegionRelations; use self::lexical_region_resolve::LexicalRegionResolutions; -use self::outlives::env::OutlivesEnvironment; -use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound}; +use self::region_constraints::{GenericKind, VarInfos, VerifyBound}; use self::region_constraints::{ RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot, }; @@ -1213,95 +1212,6 @@ impl<'tcx> InferCtxt<'tcx> { self.tainted_by_errors.set(Some(e)); } - pub fn skip_region_resolution(&self) { - let (var_infos, _) = { - let mut inner = self.inner.borrow_mut(); - let inner = &mut *inner; - // Note: `inner.region_obligations` may not be empty, because we - // didn't necessarily call `process_registered_region_obligations`. - // This is okay, because that doesn't introduce new vars. - inner - .region_constraint_storage - .take() - .expect("regions already resolved") - .with_log(&mut inner.undo_log) - .into_infos_and_data() - }; - - let lexical_region_resolutions = LexicalRegionResolutions { - values: rustc_index::vec::IndexVec::from_elem_n( - crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased), - var_infos.len(), - ), - }; - - let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions)); - assert!(old_value.is_none()); - } - - /// Process the region constraints and return any errors that - /// result. After this, no more unification operations should be - /// done -- or the compiler will panic -- but it is legal to use - /// `resolve_vars_if_possible` as well as `fully_resolve`. - pub fn resolve_regions( - &self, - outlives_env: &OutlivesEnvironment<'tcx>, - ) -> Vec> { - let (var_infos, data) = { - let mut inner = self.inner.borrow_mut(); - let inner = &mut *inner; - assert!( - self.tainted_by_errors().is_some() || inner.region_obligations.is_empty(), - "region_obligations not empty: {:#?}", - inner.region_obligations - ); - inner - .region_constraint_storage - .take() - .expect("regions already resolved") - .with_log(&mut inner.undo_log) - .into_infos_and_data() - }; - - let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map()); - - let (lexical_region_resolutions, errors) = - lexical_region_resolve::resolve(outlives_env.param_env, region_rels, var_infos, data); - - let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions)); - assert!(old_value.is_none()); - - errors - } - /// Obtains (and clears) the current set of region - /// constraints. The inference context is still usable: further - /// unifications will simply add new constraints. - /// - /// This method is not meant to be used with normal lexical region - /// resolution. Rather, it is used in the NLL mode as a kind of - /// interim hack: basically we run normal type-check and generate - /// region constraints as normal, but then we take them and - /// translate them into the form that the NLL solver - /// understands. See the NLL module for mode details. - pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> { - assert!( - self.inner.borrow().region_obligations.is_empty(), - "region_obligations not empty: {:#?}", - self.inner.borrow().region_obligations - ); - - self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data() - } - - /// Gives temporary access to the region constraint data. - pub fn with_region_constraints( - &self, - op: impl FnOnce(&RegionConstraintData<'tcx>) -> R, - ) -> R { - let mut inner = self.inner.borrow_mut(); - op(inner.unwrap_region_constraints().data()) - } - pub fn region_var_origin(&self, vid: ty::RegionVid) -> RegionVariableOrigin { let mut inner = self.inner.borrow_mut(); let inner = &mut *inner; @@ -1754,56 +1664,6 @@ impl<'cx, 'tcx> Drop for CanonicalizationCtxtGuard<'cx, 'tcx> { } impl<'tcx> TypeErrCtxt<'_, 'tcx> { - /// Processes registered region obliations and resolves regions, reporting - /// any errors if any were raised. Prefer using this function over manually - /// calling `resolve_regions_and_report_errors`. - pub fn check_region_obligations_and_report_errors( - &self, - generic_param_scope: LocalDefId, - outlives_env: &OutlivesEnvironment<'tcx>, - ) -> Result<(), ErrorGuaranteed> { - self.process_registered_region_obligations( - outlives_env.region_bound_pairs(), - outlives_env.param_env, - ); - - self.resolve_regions_and_report_errors(generic_param_scope, outlives_env) - } - - /// Process the region constraints and report any errors that - /// result. After this, no more unification operations should be - /// done -- or the compiler will panic -- but it is legal to use - /// `resolve_vars_if_possible` as well as `fully_resolve`. - /// - /// Make sure to call [`InferCtxt::process_registered_region_obligations`] - /// first, or preferably use [`TypeErrCtxt::check_region_obligations_and_report_errors`] - /// to do both of these operations together. - pub fn resolve_regions_and_report_errors( - &self, - generic_param_scope: LocalDefId, - outlives_env: &OutlivesEnvironment<'tcx>, - ) -> Result<(), ErrorGuaranteed> { - let errors = self.resolve_regions(outlives_env); - - if let None = self.tainted_by_errors() { - // As a heuristic, just skip reporting region errors - // altogether if other errors have been reported while - // this infcx was in use. This is totally hokey but - // otherwise we have a hard time separating legit region - // errors from silly ones. - self.report_region_errors(generic_param_scope, &errors); - } - - if errors.is_empty() { - Ok(()) - } else { - Err(self - .tcx - .sess - .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted")) - } - } - // [Note-Type-error-reporting] // An invariant is that anytime the expected or actual type is Error (the special // error type, meaning that an error occurred when typechecking this expression), diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 048dad3a48bc..21907c4b4234 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -1,4 +1,11 @@ //! Various code related to computing outlives relations. +use self::env::OutlivesEnvironment; +use super::region_constraints::RegionConstraintData; +use super::{InferCtxt, RegionResolutionError}; +use crate::infer::free_regions::RegionRelations; +use crate::infer::lexical_region_resolve::{self, LexicalRegionResolutions}; +use rustc_middle::traits::query::OutlivesBound; +use rustc_middle::ty; pub mod components; pub mod env; @@ -6,9 +13,6 @@ pub mod obligations; pub mod test_type_match; pub mod verify; -use rustc_middle::traits::query::OutlivesBound; -use rustc_middle::ty; - #[instrument(level = "debug", skip(param_env), ret)] pub fn explicit_outlives_bounds<'tcx>( param_env: ty::ParamEnv<'tcx>, @@ -39,3 +43,97 @@ pub fn explicit_outlives_bounds<'tcx>( ))) => Some(OutlivesBound::RegionSubRegion(r_b, r_a)), }) } + +impl<'tcx> InferCtxt<'tcx> { + pub fn skip_region_resolution(&self) { + let (var_infos, _) = { + let mut inner = self.inner.borrow_mut(); + let inner = &mut *inner; + // Note: `inner.region_obligations` may not be empty, because we + // didn't necessarily call `process_registered_region_obligations`. + // This is okay, because that doesn't introduce new vars. + inner + .region_constraint_storage + .take() + .expect("regions already resolved") + .with_log(&mut inner.undo_log) + .into_infos_and_data() + }; + + let lexical_region_resolutions = LexicalRegionResolutions { + values: rustc_index::vec::IndexVec::from_elem_n( + crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased), + var_infos.len(), + ), + }; + + let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions)); + assert!(old_value.is_none()); + } + + /// Process the region constraints and return any errors that + /// result. After this, no more unification operations should be + /// done -- or the compiler will panic -- but it is legal to use + /// `resolve_vars_if_possible` as well as `fully_resolve`. + pub fn resolve_regions( + &self, + outlives_env: &OutlivesEnvironment<'tcx>, + ) -> Vec> { + self.process_registered_region_obligations(outlives_env); + + let (var_infos, data) = { + let mut inner = self.inner.borrow_mut(); + let inner = &mut *inner; + assert!( + self.tainted_by_errors().is_some() || inner.region_obligations.is_empty(), + "region_obligations not empty: {:#?}", + inner.region_obligations + ); + inner + .region_constraint_storage + .take() + .expect("regions already resolved") + .with_log(&mut inner.undo_log) + .into_infos_and_data() + }; + + let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map()); + + let (lexical_region_resolutions, errors) = + lexical_region_resolve::resolve(outlives_env.param_env, region_rels, var_infos, data); + + let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions)); + assert!(old_value.is_none()); + + errors + } + + /// Obtains (and clears) the current set of region + /// constraints. The inference context is still usable: further + /// unifications will simply add new constraints. + /// + /// This method is not meant to be used with normal lexical region + /// resolution. Rather, it is used in the NLL mode as a kind of + /// interim hack: basically we run normal type-check and generate + /// region constraints as normal, but then we take them and + /// translate them into the form that the NLL solver + /// understands. See the NLL module for mode details. + pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> { + assert!( + self.inner.borrow().region_obligations.is_empty(), + "region_obligations not empty: {:#?}", + self.inner.borrow().region_obligations + ); + + self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data() + } + + /// Gives temporary access to the region constraint data. + pub fn with_region_constraints( + &self, + op: impl FnOnce(&RegionConstraintData<'tcx>) -> R, + ) -> R { + let mut inner = self.inner.borrow_mut(); + op(inner.unwrap_region_constraints().data()) + } +} diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index bbe7d4c63f79..ccf11c61b573 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -72,6 +72,8 @@ use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitableExt}; use smallvec::smallvec; +use super::env::OutlivesEnvironment; + impl<'tcx> InferCtxt<'tcx> { /// Registers that the given region obligation must be resolved /// from within the scope of `body_id`. These regions are enqueued @@ -112,39 +114,17 @@ impl<'tcx> InferCtxt<'tcx> { std::mem::take(&mut self.inner.borrow_mut().region_obligations) } - /// NOTE: Prefer using `TypeErrCtxt::check_region_obligations_and_report_errors` - /// instead of calling this directly. - /// /// Process the region obligations that must be proven (during /// `regionck`) for the given `body_id`, given information about - /// the region bounds in scope and so forth. This function must be - /// invoked for all relevant body-ids before region inference is - /// done (or else an assert will fire). + /// the region bounds in scope and so forth. /// /// See the `region_obligations` field of `InferCtxt` for some /// comments about how this function fits into the overall expected /// flow of the inferencer. The key point is that it is /// invoked after all type-inference variables have been bound -- - /// towards the end of regionck. This also ensures that the - /// region-bound-pairs are available (see comments above regarding - /// closures). - /// - /// # Parameters - /// - /// - `region_bound_pairs_map`: the set of region bounds implied by - /// the parameters and where-clauses. In particular, each pair - /// `('a, K)` in this list tells us that the bounds in scope - /// indicate that `K: 'a`, where `K` is either a generic - /// parameter like `T` or a projection like `T::Item`. - /// - `param_env` is the parameter environment for the enclosing function. - /// - `body_id` is the body-id whose region obligations are being - /// processed. - #[instrument(level = "debug", skip(self, region_bound_pairs))] - pub fn process_registered_region_obligations( - &self, - region_bound_pairs: &RegionBoundPairs<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) { + /// right before lexical region resolution. + #[instrument(level = "debug", skip(self, outlives_env))] + pub fn process_registered_region_obligations(&self, outlives_env: &OutlivesEnvironment<'tcx>) { assert!( !self.in_snapshot.get(), "cannot process registered region obligations in a snapshot" @@ -153,15 +133,16 @@ impl<'tcx> InferCtxt<'tcx> { let my_region_obligations = self.take_registered_region_obligations(); for RegionObligation { sup_type, sub_region, origin } in my_region_obligations { - debug!( - "process_registered_region_obligations: sup_type={:?} sub_region={:?} origin={:?}", - sup_type, sub_region, origin - ); - + debug!(?sup_type, ?sub_region, ?origin); let sup_type = self.resolve_vars_if_possible(sup_type); - let outlives = - &mut TypeOutlives::new(self, self.tcx, ®ion_bound_pairs, None, param_env); + let outlives = &mut TypeOutlives::new( + self, + self.tcx, + &outlives_env.region_bound_pairs(), + None, + outlives_env.param_env, + ); let category = origin.to_constraint_category(); outlives.type_must_outlive(origin, sup_type, sub_region, category); } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index a53d414be9e7..fd45ef99aa9d 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -187,7 +187,8 @@ impl<'tcx> AutoTraitFinder<'tcx> { panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors); } - infcx.process_registered_region_obligations(&Default::default(), full_env); + let outlives_env = OutlivesEnvironment::new(full_env); + infcx.process_registered_region_obligations(&outlives_env); let region_data = infcx.inner.borrow_mut().unwrap_region_constraints().region_constraint_data().clone(); diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 53d4f95e9e30..3c918b6028d4 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -405,9 +405,6 @@ fn resolve_negative_obligation<'tcx>( param_env, infcx.implied_bounds_tys(param_env, body_def_id, wf_tys), ); - - infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env); - infcx.resolve_regions(&outlives_env).is_empty() } diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 8acc31cd410b..d2b39ed226f0 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -6,11 +6,13 @@ use super::{ChalkFulfillmentContext, FulfillmentContext}; use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt; use crate::traits::NormalizeExt; use rustc_data_structures::fx::FxIndexSet; +use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::canonical::{ Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse, }; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_infer::traits::query::Fallible; use rustc_infer::traits::{ @@ -181,6 +183,23 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { self.engine.borrow_mut().select_all_or_error(self.infcx) } + /// Resolves regions and reports errors. + /// + /// Takes ownership of the context as doing trait solving afterwards + /// will result in region constraints getting ignored. + pub fn resolve_regions_and_report_errors( + self, + generic_param_scope: LocalDefId, + outlives_env: &OutlivesEnvironment<'tcx>, + ) -> Result<(), ErrorGuaranteed> { + let errors = self.infcx.resolve_regions(&outlives_env); + if errors.is_empty() { + Ok(()) + } else { + Err(self.infcx.err_ctxt().report_region_errors(generic_param_scope, &errors)) + } + } + pub fn assumed_wf_types( &self, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 0bde43c54df9..af567c074384 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -117,10 +117,6 @@ pub fn type_allowed_to_implement_copy<'tcx>( FxIndexSet::from_iter([self_type]), ), ); - infcx.process_registered_region_obligations( - outlives_env.region_bound_pairs(), - param_env, - ); let errors = infcx.resolve_regions(&outlives_env); if !errors.is_empty() { infringing.push((field, ty, InfringingFieldsReason::Regions(errors))); From cc82ccb145f2056854b499d5033be1a06ddfa29c Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 12 Apr 2023 10:31:41 +0200 Subject: [PATCH 218/272] `#[must_use]` for fns returning a list of errors --- compiler/rustc_infer/src/infer/outlives/mod.rs | 1 + compiler/rustc_infer/src/traits/engine.rs | 2 ++ compiler/rustc_trait_selection/src/traits/engine.rs | 2 ++ .../rustc_trait_selection/src/traits/error_reporting/mod.rs | 4 +++- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 21907c4b4234..9a9a1696b006 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -75,6 +75,7 @@ impl<'tcx> InferCtxt<'tcx> { /// result. After this, no more unification operations should be /// done -- or the compiler will panic -- but it is legal to use /// `resolve_vars_if_possible` as well as `fully_resolve`. + #[must_use] pub fn resolve_regions( &self, outlives_env: &OutlivesEnvironment<'tcx>, diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index f75344f20b6d..a188bb238827 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -36,6 +36,7 @@ pub trait TraitEngine<'tcx>: 'tcx { obligation: PredicateObligation<'tcx>, ); + #[must_use] fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec>; fn collect_remaining_errors(&mut self) -> Vec>; @@ -58,6 +59,7 @@ pub trait TraitEngineExt<'tcx> { obligations: impl IntoIterator>, ); + #[must_use] fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec>; } diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index d2b39ed226f0..2beebe94b6d1 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -175,10 +175,12 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } + #[must_use] pub fn select_where_possible(&self) -> Vec> { self.engine.borrow_mut().select_where_possible(self.infcx) } + #[must_use] pub fn select_all_or_error(&self) -> Vec> { self.engine.borrow_mut().select_all_or_error(self.infcx) } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 6ebf056f0e83..6790d7b76a3a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1763,7 +1763,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // constrain inference variables a bit more to nested obligations from normalize so // we can have more helpful errors. - ocx.select_where_possible(); + // + // we intentionally errors from normalization here. + let _ = ocx.select_where_possible(); if let Err(new_err) = ocx.eq_exp( &obligation.cause, From 4b456cb68314bce1ddb5140e0c234510e489c9fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lena=20Miliz=C3=A9?= Date: Wed, 12 Apr 2023 11:18:50 +0200 Subject: [PATCH 219/272] compiler: improve captured metavariables diagnostic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a link to the relevant part of The Rust Reference in the eror message, and suggests a possible fix (replacing the fragment specifier with :tt in the macro definition). Fixes typos in the original message. Signed-off-by: Lena Milizé --- compiler/rustc_expand/src/mbe/diagnostics.rs | 4 +++- tests/ui/macros/nonterminal-matching.stderr | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 6bc393c6534f..00bb7b0f2a24 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -66,7 +66,9 @@ pub(super) fn failed_to_match_macro<'cx>( && (matches!(expected_token.kind, TokenKind::Interpolated(_)) || matches!(token.kind, TokenKind::Interpolated(_))) { - err.note("captured metavariables except for `$tt`, `$ident` and `$lifetime` cannot be compared to other tokens"); + err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens"); + err.note("see https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment for more information"); + err.help("try using `:tt` instead in the macro definition"); } // Check whether there's a missing comma in this macro call, like `println!("{}" a);` diff --git a/tests/ui/macros/nonterminal-matching.stderr b/tests/ui/macros/nonterminal-matching.stderr index 762ecc3207fa..c295eddbe47e 100644 --- a/tests/ui/macros/nonterminal-matching.stderr +++ b/tests/ui/macros/nonterminal-matching.stderr @@ -18,7 +18,9 @@ LL | macro n(a $nt_item b) { ... LL | complex_nonterminal!(enum E {}); | ------------------------------- in this macro invocation - = note: captured metavariables except for `$tt`, `$ident` and `$lifetime` cannot be compared to other tokens + = note: captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens + = note: see https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment for more information + = help: try using `:tt` instead in the macro definition = note: this error originates in the macro `complex_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error From bad2af1d389fd2240d9057e42c30e6b0b9498f65 Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Fri, 31 Mar 2023 06:59:13 -0400 Subject: [PATCH 220/272] Make rustdoc and rustc's help match exactly Before, rustdoc was missing `-C passes=list` and the "Available options" header. Making these match allows testing that they match exactly. --- compiler/rustc_driver_impl/src/lib.rs | 76 +++++++++++++++------------ src/librustdoc/config.rs | 10 +--- src/librustdoc/doctest.rs | 2 + 3 files changed, 46 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 730d41ab962f..634d06da7f5d 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -37,7 +37,7 @@ use rustc_metadata::locator; use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS}; use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths}; use rustc_session::cstore::MetadataLoader; -use rustc_session::getopts; +use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; use rustc_session::{config, Session}; use rustc_session::{early_error, early_error_no_abort, early_warn}; @@ -956,6 +956,46 @@ Available lint options: } } +/// Show help for flag categories shared between rustdoc and rustc. +/// +/// Returns whether a help option was printed. +pub fn describe_flag_categories(matches: &Matches) -> bool { + // Handle the special case of -Wall. + let wall = matches.opt_strs("W"); + if wall.iter().any(|x| *x == "all") { + print_wall_help(); + rustc_errors::FatalError.raise(); + } + + // Don't handle -W help here, because we might first load plugins. + let debug_flags = matches.opt_strs("Z"); + if debug_flags.iter().any(|x| *x == "help") { + describe_debug_flags(); + return true; + } + + let cg_flags = matches.opt_strs("C"); + if cg_flags.iter().any(|x| *x == "help") { + describe_codegen_flags(); + return true; + } + + if cg_flags.iter().any(|x| *x == "no-stack-check") { + early_warn( + ErrorOutputType::default(), + "the --no-stack-check flag is deprecated and does nothing", + ); + } + + if cg_flags.iter().any(|x| *x == "passes=list") { + let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); + get_codegen_backend(&None, backend_name).print_passes(); + return true; + } + + false +} + fn describe_debug_flags() { println!("\nAvailable options:\n"); print_flag_list("-Z", config::Z_OPTIONS); @@ -966,7 +1006,7 @@ fn describe_codegen_flags() { print_flag_list("-C", config::CG_OPTIONS); } -pub fn print_flag_list( +fn print_flag_list( cmdline_opt: &str, flag_list: &[(&'static str, T, &'static str, &'static str)], ) { @@ -1059,37 +1099,7 @@ pub fn handle_options(args: &[String]) -> Option { return None; } - // Handle the special case of -Wall. - let wall = matches.opt_strs("W"); - if wall.iter().any(|x| *x == "all") { - print_wall_help(); - rustc_errors::FatalError.raise(); - } - - // Don't handle -W help here, because we might first load plugins. - let debug_flags = matches.opt_strs("Z"); - if debug_flags.iter().any(|x| *x == "help") { - describe_debug_flags(); - return None; - } - - let cg_flags = matches.opt_strs("C"); - - if cg_flags.iter().any(|x| *x == "help") { - describe_codegen_flags(); - return None; - } - - if cg_flags.iter().any(|x| *x == "no-stack-check") { - early_warn( - ErrorOutputType::default(), - "the --no-stack-check flag is deprecated and does nothing", - ); - } - - if cg_flags.iter().any(|x| *x == "passes=list") { - let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); - get_codegen_backend(&None, backend_name).print_passes(); + if describe_flag_categories(&matches) { return None; } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index ea8c7e9a67c3..989fefd32434 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -6,7 +6,6 @@ use std::path::PathBuf; use std::str::FromStr; use rustc_data_structures::fx::FxHashMap; -use rustc_driver::print_flag_list; use rustc_session::config::{ self, parse_crate_types_from_list, parse_externs, parse_target_triple, CrateType, }; @@ -328,14 +327,7 @@ impl Options { return Err(0); } - let z_flags = matches.opt_strs("Z"); - if z_flags.iter().any(|x| *x == "help") { - print_flag_list("-Z", config::Z_OPTIONS); - return Err(0); - } - let c_flags = matches.opt_strs("C"); - if c_flags.iter().any(|x| *x == "help") { - print_flag_list("-C", config::CG_OPTIONS); + if rustc_driver::describe_flag_categories(&matches) { return Err(0); } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 1a896b411ab0..daf10e5b88a8 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -398,6 +398,8 @@ fn run_test( compiler.stdin(Stdio::piped()); compiler.stderr(Stdio::piped()); + debug!("compiler invocation for doctest: {:?}", compiler); + let mut child = compiler.spawn().expect("Failed to spawn rustc process"); { let stdin = child.stdin.as_mut().expect("Failed to open stdin"); From 67b391968d85b6f09eb563f4ca962e6fe05c91c5 Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Fri, 31 Mar 2023 07:02:16 -0400 Subject: [PATCH 221/272] Replace rustdoc-ui/{c,z}-help tests with a run-make test This make rustdoc resilient to changes in the debugging options while still testing that it matches rustc. --- tests/run-make/rustdoc-shared-flags/Makefile | 18 ++ tests/rustdoc-ui/c-help.rs | 6 - tests/rustdoc-ui/c-help.stdout | 51 ----- tests/rustdoc-ui/z-help.rs | 6 - tests/rustdoc-ui/z-help.stdout | 220 ------------------- 5 files changed, 18 insertions(+), 283 deletions(-) create mode 100644 tests/run-make/rustdoc-shared-flags/Makefile delete mode 100644 tests/rustdoc-ui/c-help.rs delete mode 100644 tests/rustdoc-ui/c-help.stdout delete mode 100644 tests/rustdoc-ui/z-help.rs delete mode 100644 tests/rustdoc-ui/z-help.stdout diff --git a/tests/run-make/rustdoc-shared-flags/Makefile b/tests/run-make/rustdoc-shared-flags/Makefile new file mode 100644 index 000000000000..a2a7d7b3634a --- /dev/null +++ b/tests/run-make/rustdoc-shared-flags/Makefile @@ -0,0 +1,18 @@ +include ../tools.mk + +all: z_help c_help list_passes + +c_help: + $(RUSTC) -C help > $(TMPDIR)/rustc.c_help.txt + $(RUSTDOC) -C help > $(TMPDIR)/rustdoc.c_help.txt + $(DIFF) $(TMPDIR)/rustc.c_help.txt $(TMPDIR)/rustdoc.c_help.txt + +z_help: + $(RUSTC) -Z help > $(TMPDIR)/rustc.z_help.txt + $(RUSTDOC) -Z help > $(TMPDIR)/rustdoc.z_help.txt + $(DIFF) $(TMPDIR)/rustc.z_help.txt $(TMPDIR)/rustdoc.z_help.txt + +list_passes: + $(RUSTC) -C passes=list > $(TMPDIR)/rustc.passes.txt + $(RUSTDOC) -C passes=list > $(TMPDIR)/rustdoc.passes.txt + $(DIFF) $(TMPDIR)/rustc.passes.txt $(TMPDIR)/rustdoc.passes.txt diff --git a/tests/rustdoc-ui/c-help.rs b/tests/rustdoc-ui/c-help.rs deleted file mode 100644 index e166edf8b619..000000000000 --- a/tests/rustdoc-ui/c-help.rs +++ /dev/null @@ -1,6 +0,0 @@ -// check-pass -// compile-flags: -Chelp -// check-stdout -// regex-error-pattern: -C\s+incremental - -pub struct Foo; diff --git a/tests/rustdoc-ui/c-help.stdout b/tests/rustdoc-ui/c-help.stdout deleted file mode 100644 index 0bd2d73efee5..000000000000 --- a/tests/rustdoc-ui/c-help.stdout +++ /dev/null @@ -1,51 +0,0 @@ - -C ar=val -- this option is deprecated and does nothing - -C code-model=val -- choose the code model to use (`rustc --print code-models` for details) - -C codegen-units=val -- divide crate into N units to optimize in parallel - -C control-flow-guard=val -- use Windows Control Flow Guard (default: no) - -C debug-assertions=val -- explicitly enable the `cfg(debug_assertions)` directive - -C debuginfo=val -- debug info emission level (0-2, none, line-directives-only, line-tables-only, limited, or full; default: 0) - -C default-linker-libraries=val -- allow the linker to link its default libraries (default: no) - -C embed-bitcode=val -- emit bitcode in rlibs (default: yes) - -C extra-filename=val -- extra data to put in each output filename - -C force-frame-pointers=val -- force use of the frame pointers - -C force-unwind-tables=val -- force use of unwind tables - -C incremental=val -- enable incremental compilation - -C inline-threshold=val -- set the threshold for inlining a function - -C instrument-coverage=val -- instrument the generated code to support LLVM source-based code coverage reports (note, the compiler build config must include `profiler = true`); implies `-C symbol-mangling-version=v0`. Optional values are: - `=all` (implicit value) - `=except-unused-generics` - `=except-unused-functions` - `=off` (default) - -C link-arg=val -- a single extra argument to append to the linker invocation (can be used several times) - -C link-args=val -- extra arguments to append to the linker invocation (space separated) - -C link-dead-code=val -- keep dead code at link time (useful for code coverage) (default: no) - -C link-self-contained=val -- control whether to link Rust provided C objects/libraries or rely - on C toolchain installed in the system - -C linker=val -- system linker to link outputs with - -C linker-flavor=val -- linker flavor - -C linker-plugin-lto=val -- generate build artifacts that are compatible with linker-based LTO - -C llvm-args=val -- a list of arguments to pass to LLVM (space separated) - -C lto=val -- perform LLVM link-time optimizations - -C metadata=val -- metadata to mangle symbol names with - -C no-prepopulate-passes=val -- give an empty list of passes to the pass manager - -C no-redzone=val -- disable the use of the redzone - -C no-stack-check=val -- this option is deprecated and does nothing - -C no-vectorize-loops=val -- disable loop vectorization optimization passes - -C no-vectorize-slp=val -- disable LLVM's SLP vectorization pass - -C opt-level=val -- optimization level (0-3, s, or z; default: 0) - -C overflow-checks=val -- use overflow checks for integer arithmetic - -C panic=val -- panic strategy to compile crate with - -C passes=val -- a list of extra LLVM passes to run (space separated) - -C prefer-dynamic=val -- prefer dynamic linking to static linking (default: no) - -C profile-generate=val -- compile the program with profiling instrumentation - -C profile-use=val -- use the given `.profdata` file for profile-guided optimization - -C relocation-model=val -- control generation of position-independent code (PIC) (`rustc --print relocation-models` for details) - -C remark=val -- print remarks for these optimization passes (space separated, or "all") - -C rpath=val -- set rpath values in libs/exes (default: no) - -C save-temps=val -- save all temporary output files during compilation (default: no) - -C soft-float=val -- use soft float ABI (*eabihf targets only) (default: no) - -C split-debuginfo=val -- how to handle split-debuginfo, a platform-specific option - -C strip=val -- tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`) - -C symbol-mangling-version=val -- which mangling version to use for symbol names ('legacy' (default) or 'v0') - -C target-cpu=val -- select target processor (`rustc --print target-cpus` for details) - -C target-feature=val -- target specific attributes. (`rustc --print target-features` for details). This feature is unsafe. diff --git a/tests/rustdoc-ui/z-help.rs b/tests/rustdoc-ui/z-help.rs deleted file mode 100644 index c7cf841b9370..000000000000 --- a/tests/rustdoc-ui/z-help.rs +++ /dev/null @@ -1,6 +0,0 @@ -// check-pass -// compile-flags: -Zhelp -// check-stdout -// regex-error-pattern: -Z\s+self-profile - -pub struct Foo; diff --git a/tests/rustdoc-ui/z-help.stdout b/tests/rustdoc-ui/z-help.stdout deleted file mode 100644 index 72f5f933d8db..000000000000 --- a/tests/rustdoc-ui/z-help.stdout +++ /dev/null @@ -1,220 +0,0 @@ - -Z allow-features=val -- only allow the listed language features to be enabled in code (comma separated) - -Z always-encode-mir=val -- encode MIR of all functions into the crate metadata (default: no) - -Z asm-comments=val -- generate comments into the assembly (may change behavior) (default: no) - -Z assert-incr-state=val -- assert that the incremental cache is in given state: either `loaded` or `not-loaded`. - -Z assume-incomplete-release=val -- make cfg(version) treat the current version as incomplete (default: no) - -Z binary-dep-depinfo=val -- include artifacts (sysroot, crate dependencies) used during compilation in dep-info (default: no) - -Z box-noalias=val -- emit noalias metadata for box (default: yes) - -Z branch-protection=val -- set options for branch target identification and pointer authentication on AArch64 - -Z cf-protection=val -- instrument control-flow architecture protection - -Z cgu-partitioning-strategy=val -- the codegen unit partitioning strategy to use - -Z codegen-backend=val -- the backend to use - -Z combine-cgu=val -- combine CGUs into a single one - -Z crate-attr=val -- inject the given attribute in the crate - -Z debug-info-for-profiling=val -- emit discriminators and other data necessary for AutoFDO - -Z debug-macros=val -- emit line numbers debug info inside macros (default: no) - -Z deduplicate-diagnostics=val -- deduplicate identical diagnostics (default: yes) - -Z dep-info-omit-d-target=val -- in dep-info output, omit targets for tracking dependencies of the dep-info files themselves (default: no) - -Z dep-tasks=val -- print tasks that execute and the color their dep node gets (requires debug build) (default: no) - -Z diagnostic-width=val -- set the current output width for diagnostic truncation - -Z dlltool=val -- import library generation tool (windows-gnu only) - -Z dont-buffer-diagnostics=val -- emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) (default: no) - -Z drop-tracking=val -- enables drop tracking in generators (default: no) - -Z drop-tracking-mir=val -- enables drop tracking on MIR in generators (default: no) - -Z dual-proc-macros=val -- load proc macros for both target and host, but only link to the target (default: no) - -Z dump-dep-graph=val -- dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) (default: no) - -Z dump-drop-tracking-cfg=val -- dump drop-tracking control-flow graph as a `.dot` file (default: no) - -Z dump-mir=val -- dump MIR state to file. - `val` is used to select which passes and functions to dump. For example: - `all` matches all passes and functions, - `foo` matches all passes for functions whose name contains 'foo', - `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo', - `foo | bar` all passes for function names containing 'foo' or 'bar'. - -Z dump-mir-dataflow=val -- in addition to `.mir` files, create graphviz `.dot` files with dataflow results (default: no) - -Z dump-mir-dir=val -- the directory the MIR is dumped into (default: `mir_dump`) - -Z dump-mir-exclude-pass-number=val -- exclude the pass number when dumping MIR (used in tests) (default: no) - -Z dump-mir-graphviz=val -- in addition to `.mir` files, create graphviz `.dot` files (and with `-Z instrument-coverage`, also create a `.dot` file for the MIR-derived coverage graph) (default: no) - -Z dump-mir-spanview=val -- in addition to `.mir` files, create `.html` files to view spans for all `statement`s (including terminators), only `terminator` spans, or computed `block` spans (one span encompassing a block's terminator and all statements). If `-Z instrument-coverage` is also enabled, create an additional `.html` file showing the computed coverage spans. - -Z dump-mono-stats=val -- output statistics about monomorphization collection - -Z dump-mono-stats-format=val -- the format to use for -Z dump-mono-stats (`markdown` (default) or `json`) - -Z dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform) - -Z dylib-lto=val -- enables LTO for dylib crate type - -Z emit-stack-sizes=val -- emit a section containing stack size metadata (default: no) - -Z emit-thin-lto=val -- emit the bc module with thin LTO info (default: yes) - -Z export-executable-symbols=val -- export symbols from executables, as if they were dynamic libraries - -Z extra-const-ub-checks=val -- turns on more checks to detect const UB, which can be slow (default: no) - -Z fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no) - -Z flatten-format-args=val -- flatten nested format_args!() and literals into a simplified format_args!() call (default: no) - -Z force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no) - -Z fuel=val -- set the optimization fuel quota for a crate - -Z function-sections=val -- whether each function should go in its own section - -Z future-incompat-test=val -- forces all lints to be future incompatible, used for internal testing (default: no) - -Z gcc-ld=val -- implementation of ld used by cc - -Z graphviz-dark-mode=val -- use dark-themed colors in graphviz output (default: no) - -Z graphviz-font=val -- use the given `fontname` in graphviz output; can be overridden by setting environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`) - -Z hir-stats=val -- print some statistics about AST and HIR (default: no) - -Z human-readable-cgu-names=val -- generate human-readable, predictable names for codegen units (default: no) - -Z identify-regions=val -- display unnamed regions as `'`, using a non-ident unique id (default: no) - -Z incremental-ignore-spans=val -- ignore spans during ICH computation -- used for testing (default: no) - -Z incremental-info=val -- print high-level information about incremental reuse (or the lack thereof) (default: no) - -Z incremental-relative-spans=val -- hash spans relative to their parent item for incr. comp. (default: no) - -Z incremental-verify-ich=val -- verify incr. comp. hashes of green query instances (default: no) - -Z inline-in-all-cgus=val -- control whether `#[inline]` functions are in all CGUs - -Z inline-llvm=val -- enable LLVM inlining (default: yes) - -Z inline-mir=val -- enable MIR inlining (default: no) - -Z inline-mir-hint-threshold=val -- inlining threshold for functions with inline hint (default: 100) - -Z inline-mir-threshold=val -- a default MIR inlining threshold (default: 50) - -Z input-stats=val -- gather statistics about the input (default: no) - -Z instrument-coverage=val -- instrument the generated code to support LLVM source-based code coverage reports (note, the compiler build config must include `profiler = true`); implies `-C symbol-mangling-version=v0`. Optional values are: - `=all` (implicit value) - `=except-unused-generics` - `=except-unused-functions` - `=off` (default) - -Z instrument-mcount=val -- insert function instrument code for mcount-based tracing (default: no) - -Z instrument-xray=val -- insert function instrument code for XRay-based tracing (default: no) - Optional extra settings: - `=always` - `=never` - `=ignore-loops` - `=instruction-threshold=N` - `=skip-entry` - `=skip-exit` - Multiple options can be combined with commas. - -Z keep-hygiene-data=val -- keep hygiene data after analysis (default: no) - -Z layout-seed=val -- seed layout randomization - -Z link-directives=val -- honor #[link] directives in the compiled crate (default: yes) - -Z link-native-libraries=val -- link native libraries in the linker invocation (default: yes) - -Z link-only=val -- link the `.rlink` file generated by `-Z no-link` (default: no) - -Z llvm-plugins=val -- a list LLVM plugins to enable (space separated) - -Z llvm-time-trace=val -- generate JSON tracing data file from LLVM data (default: no) - -Z location-detail=val -- what location details should be tracked when using caller_location, either `none`, or a comma separated list of location details, for which valid options are `file`, `line`, and `column` (default: `file,line,column`) - -Z lower-impl-trait-in-trait-to-assoc-ty=val -- modify the lowering strategy for `impl Trait` in traits so that they are lowered to generic associated types - -Z ls=val -- list the symbols defined by a library crate (default: no) - -Z macro-backtrace=val -- show macro backtraces (default: no) - -Z maximal-hir-to-mir-coverage=val -- save as much information as possible about the correspondence between MIR and HIR as source scopes (default: no) - -Z merge-functions=val -- control the operation of the MergeFunctions LLVM pass, taking the same values as the target option of the same name - -Z meta-stats=val -- gather metadata statistics (default: no) - -Z mir-emit-retag=val -- emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 (default: no) - -Z mir-enable-passes=val -- use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be enabled, overriding all other checks. Passes that are not specified are enabled or disabled by other flags as usual. - -Z mir-opt-level=val -- MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds) - -Z mir-pretty-relative-line-numbers=val -- use line numbers relative to the function in mir pretty printing - -Z move-size-limit=val -- the size at which the `large_assignments` lint starts to be emitted - -Z mutable-noalias=val -- emit noalias metadata for mutable references (default: yes) - -Z nll-facts=val -- dump facts from NLL analysis into side files (default: no) - -Z nll-facts-dir=val -- the directory the NLL facts are dumped into (default: `nll-facts`) - -Z no-analysis=val -- parse and expand the source, but run no analysis - -Z no-codegen=val -- run all passes except codegen; no output - -Z no-generate-arange-section=val -- omit DWARF address ranges that give faster lookups - -Z no-jump-tables=val -- disable the jump tables and lookup tables that can be generated from a switch case lowering - -Z no-leak-check=val -- disable the 'leak check' for subtyping; unsound, but useful for tests - -Z no-link=val -- compile without linking - -Z no-parallel-llvm=val -- run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO) - -Z no-profiler-runtime=val -- prevent automatic injection of the profiler_builtins crate - -Z no-unique-section-names=val -- do not use unique names for text and data sections when -Z function-sections is used - -Z normalize-docs=val -- normalize associated items in rustdoc when generating documentation - -Z oom=val -- panic strategy for out-of-memory handling - -Z osx-rpath-install-name=val -- pass `-install_name @rpath/...` to the macOS linker (default: no) - -Z packed-bundled-libs=val -- change rlib format to store native libraries as archives - -Z panic-abort-tests=val -- support compiling tests with panic=abort (default: no) - -Z panic-in-drop=val -- panic strategy for panics in drops - -Z parse-only=val -- parse only; do not compile, assemble, or link (default: no) - -Z perf-stats=val -- print some performance-related statistics (default: no) - -Z plt=val -- whether to use the PLT when calling into shared libraries; - only has effect for PIC code on systems with ELF binaries - (default: PLT is disabled if full relro is enabled) - -Z polonius=val -- enable polonius-based borrow-checker (default: no) - -Z polymorphize=val -- perform polymorphization analysis - -Z pre-link-arg=val -- a single extra argument to prepend the linker invocation (can be used several times) - -Z pre-link-args=val -- extra arguments to prepend to the linker invocation (space separated) - -Z precise-enum-drop-elaboration=val -- use a more precise version of drop elaboration for matches on enums (default: yes). This results in better codegen, but has caused miscompilations on some tier 2 platforms. See #77382 and #74551. - -Z print-fuel=val -- make rustc print the total optimization fuel used by a crate - -Z print-llvm-passes=val -- print the LLVM optimization passes being run (default: no) - -Z print-mono-items=val -- print the result of the monomorphization collection pass - -Z print-type-sizes=val -- print layout information for each type encountered (default: no) - -Z proc-macro-backtrace=val -- show backtraces for panics during proc-macro execution (default: no) - -Z proc-macro-execution-strategy=val -- how to run proc-macro code (default: same-thread) - -Z profile=val -- insert profiling code (default: no) - -Z profile-closures=val -- profile size of closures - -Z profile-emit=val -- file path to emit profiling data at runtime when using 'profile' (default based on relative source path) - -Z profile-sample-use=val -- use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO) - -Z profiler-runtime=val -- name of the profiler runtime crate to automatically inject (default: `profiler_builtins`) - -Z query-dep-graph=val -- enable queries of the dependency graph for regression testing (default: no) - -Z randomize-layout=val -- randomize the layout of types (default: no) - -Z relax-elf-relocations=val -- whether ELF relocations can be relaxed - -Z relro-level=val -- choose which RELRO level to use - -Z remap-cwd-prefix=val -- remap paths under the current working directory to this path prefix - -Z report-delayed-bugs=val -- immediately print bugs registered with `delay_span_bug` (default: no) - -Z sanitizer=val -- use a sanitizer - -Z sanitizer-memory-track-origins=val -- enable origins tracking in MemorySanitizer - -Z sanitizer-recover=val -- enable recovery for selected sanitizers - -Z saturating-float-casts=val -- make float->int casts UB-free: numbers outside the integer type's range are clipped to the max/min integer respectively, and NaN is mapped to 0 (default: yes) - -Z self-profile=val -- run the self profiler and output the raw event data - -Z self-profile-counter=val -- counter used by the self profiler (default: `wall-time`), one of: - `wall-time` (monotonic clock, i.e. `std::time::Instant`) - `instructions:u` (retired instructions, userspace-only) - `instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy) - -Z self-profile-events=val -- specify the events recorded by the self profiler; - for example: `-Z self-profile-events=default,query-keys` - all options: none, all, default, generic-activity, query-provider, query-cache-hit - query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes - -Z share-generics=val -- make the current crate share its generic instantiations - -Z show-span=val -- show spans for compiler debugging (expr|pat|ty) - -Z simulate-remapped-rust-src-base=val -- simulate the effect of remap-debuginfo = true at bootstrapping by remapping path to rust's source base directory. only meant for testing purposes - -Z span-debug=val -- forward proc_macro::Span's `Debug` impl to `Span` - -Z span-free-formats=val -- exclude spans when debug-printing compiler state (default: no) - -Z split-dwarf-inlining=val -- provide minimal debug info in the object/executable to facilitate online symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF - -Z split-dwarf-kind=val -- split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform) - (default: `split`) - - `split`: sections which do not require relocation are written into a DWARF object (`.dwo`) - file which is ignored by the linker - `single`: sections which do not require relocation are written into object file but ignored - by the linker - -Z src-hash-algorithm=val -- hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`) - -Z stack-protector=val -- control stack smash protection strategy (`rustc --print stack-protector-strategies` for details) - -Z strict-init-checks=val -- control if mem::uninitialized and mem::zeroed panic on more UB - -Z strip=val -- tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`) - -Z symbol-mangling-version=val -- which mangling version to use for symbol names ('legacy' (default) or 'v0') - -Z teach=val -- show extended diagnostic help (default: no) - -Z temps-dir=val -- the directory the intermediate files are written to - -Z terminal-urls=val -- use the OSC 8 hyperlink terminal specification to print hyperlinks in the compiler output - -Z thinlto=val -- enable ThinLTO when possible - -Z thir-unsafeck=val -- use the THIR unsafety checker (default: no) - -Z threads=val -- use a thread pool with N threads - -Z time-llvm-passes=val -- measure time of each LLVM pass (default: no) - -Z time-passes=val -- measure time of each rustc pass (default: no) - -Z time-passes-format=val -- the format to use for -Z time-passes (`text` (default) or `json`) - -Z tiny-const-eval-limit=val -- sets a tiny, non-configurable limit for const eval; useful for compiler tests - -Z tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details) - -Z trace-macros=val -- for every macro invocation, print its name and arguments (default: no) - -Z track-diagnostics=val -- tracks where in rustc a diagnostic was emitted - -Z trait-solver=val -- specify the trait solver mode used by rustc (default: classic) - -Z translate-additional-ftl=val -- additional fluent translation to preferentially use (for testing translation) - -Z translate-directionality-markers=val -- emit directionality isolation markers in translated diagnostics - -Z translate-lang=val -- language identifier for diagnostic output - -Z translate-remapped-path-to-local-path=val -- translate remapped paths into local paths when possible (default: yes) - -Z trap-unreachable=val -- generate trap instructions for unreachable intrinsics (default: use target setting, usually yes) - -Z treat-err-as-bug=val -- treat error number `val` that occurs as bug - -Z trim-diagnostic-paths=val -- in diagnostics, use heuristics to shorten paths referring to items - -Z tune-cpu=val -- select processor to schedule for (`rustc --print target-cpus` for details) - -Z ui-testing=val -- emit compiler diagnostics in a form suitable for UI testing (default: no) - -Z uninit-const-chunk-threshold=val -- allow generating const initializers with mixed init/uninit chunks, and set the maximum number of chunks for which this is allowed (default: 16) - -Z unleash-the-miri-inside-of-you=val -- take the brakes off const evaluation. NOTE: this is unsound (default: no) - -Z unpretty=val -- present the input source, unstable (and less-pretty) variants; - `normal`, `identified`, - `expanded`, `expanded,identified`, - `expanded,hygiene` (with internal representations), - `ast-tree` (raw AST before expansion), - `ast-tree,expanded` (raw AST after expansion), - `hir` (the HIR), `hir,identified`, - `hir,typed` (HIR with types for each node), - `hir-tree` (dump the raw HIR), - `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR) - -Z unsound-mir-opts=val -- enable unsound and buggy MIR optimizations (default: no) - -Z unstable-options=val -- adds unstable command line options to rustc interface (default: no) - -Z use-ctors-section=val -- use legacy .ctors section for initializers rather than .init_array - -Z validate-mir=val -- validate MIR after each transformation - -Z verbose=val -- in general, enable more debug printouts (default: no) - -Z verify-llvm-ir=val -- verify LLVM IR (default: no) - -Z virtual-function-elimination=val -- enables dead virtual function elimination optimization. Requires `-Clto[=[fat,yes]]` - -Z wasi-exec-model=val -- whether to build a wasi command or reactor From 7c40a6fb34d29fce69a16b7b65871999ef3d1628 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 10 Apr 2023 19:07:57 +0300 Subject: [PATCH 222/272] resolve: Pre-compute non-reexport module children Instead of repeating the same logic by walking HIR during metadata encoding. The only difference is that we are no longer encoding `macro_rules` items, but we never currently need them as a part of this list. They can be encoded separately if this need ever arises. `module_reexports` is also un-querified, because I don't see any reasons to make it a query, only overhead. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 15 ++--- compiler/rustc_metadata/src/rmeta/encoder.rs | 62 +++++-------------- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/metadata.rs | 2 - compiler/rustc_middle/src/query/mod.rs | 4 -- compiler/rustc_middle/src/ty/context.rs | 25 +++++++- compiler/rustc_middle/src/ty/mod.rs | 3 +- compiler/rustc_privacy/src/lib.rs | 2 +- .../rustc_resolve/src/build_reduced_graph.rs | 6 +- compiler/rustc_resolve/src/imports.rs | 16 +++-- compiler/rustc_resolve/src/lib.rs | 24 ++----- src/librustdoc/clean/inline.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/visit_ast.rs | 2 +- .../clippy/tests/ui/macro_use_imports.fixed | 2 +- .../clippy/tests/ui/macro_use_imports.stderr | 2 +- 16 files changed, 72 insertions(+), 99 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 77308212c32d..2930ce75028b 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1,6 +1,7 @@ // Decoding metadata from a single crate's metadata use crate::creader::{CStore, CrateMetadataRef}; +use crate::rmeta::table::IsDefault; use crate::rmeta::*; use rustc_ast as ast; @@ -995,17 +996,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_mod_child(self, id: DefIndex, sess: &Session) -> ModChild { let ident = self.item_ident(id, sess); - let kind = self.def_kind(id); - let def_id = self.local_def_id(id); - let res = Res::Def(kind, def_id); + let res = Res::Def(self.def_kind(id), self.local_def_id(id)); let vis = self.get_visibility(id); let span = self.get_span(id, sess); - let macro_rules = match kind { - DefKind::Macro(..) => self.root.tables.is_macro_rules.get(self, id), - _ => false, - }; - ModChild { ident, res, vis, span, macro_rules, reexport_chain: Default::default() } + ModChild { ident, res, vis, span, reexport_chain: Default::default() } } /// Iterates over all named children of the given module, @@ -1029,12 +1024,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } else { // Iterate over all children. for child_index in self.root.tables.children.get(self, id).unwrap().decode(self) { + // FIXME: Do not encode RPITITs as a part of this list. if self.root.tables.opt_rpitit_info.get(self, child_index).is_none() { yield self.get_mod_child(child_index, sess); } } - if let Some(reexports) = self.root.tables.module_reexports.get(self, id) { + let reexports = self.root.tables.module_children_reexports.get(self, id); + if !reexports.is_default() { for reexport in reexports.decode((self, sess)) { yield reexport; } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index dc8fa1ab7d31..657b903e0a8a 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -43,7 +43,6 @@ use std::borrow::Borrow; use std::collections::hash_map::Entry; use std::hash::Hash; use std::io::{Read, Seek, Write}; -use std::iter; use std::num::NonZeroUsize; use std::path::{Path, PathBuf}; @@ -456,7 +455,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } fn encode_info_for_items(&mut self) { - self.encode_info_for_mod(CRATE_DEF_ID, self.tcx.hir().root_module()); + self.encode_info_for_mod(CRATE_DEF_ID); // Proc-macro crates only export proc-macro items, which are looked // up using `proc_macro_data` @@ -1324,7 +1323,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.implied_predicates_of[def_id] <- self.tcx.implied_predicates_of(def_id)); } if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { - self.encode_info_for_adt(def_id); + self.encode_info_for_adt(local_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) @@ -1357,7 +1356,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } #[instrument(level = "trace", skip(self))] - fn encode_info_for_adt(&mut self, def_id: DefId) { + fn encode_info_for_adt(&mut self, local_def_id: LocalDefId) { + let def_id = local_def_id.to_def_id(); let tcx = self.tcx; let adt_def = tcx.adt_def(def_id); record!(self.tables.repr_options[def_id] <- adt_def.repr()); @@ -1366,15 +1366,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.params_in_repr[def_id] <- params_in_repr); if adt_def.is_enum() { - record_array!(self.tables.children[def_id] <- iter::from_generator(|| - for variant in tcx.adt_def(def_id).variants() { - yield variant.def_id.index; - // Encode constructors which take a separate slot in value namespace. - if let Some(ctor_def_id) = variant.ctor_def_id() { - yield ctor_def_id.index; - } - } - )); + let module_children = tcx.module_children_non_reexports(local_def_id); + record_array!(self.tables.children[def_id] <- + module_children.iter().map(|def_id| def_id.local_def_index)); } else { // For non-enum, there is only one variant, and its def_id is the adt's. debug_assert_eq!(adt_def.variants().len(), 1); @@ -1406,7 +1400,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - fn encode_info_for_mod(&mut self, local_def_id: LocalDefId, md: &hir::Mod<'_>) { + fn encode_info_for_mod(&mut self, local_def_id: LocalDefId) { let tcx = self.tcx; let def_id = local_def_id.to_def_id(); debug!("EncodeContext::encode_info_for_mod({:?})", def_id); @@ -1420,38 +1414,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Encode this here because we don't do it in encode_def_ids. record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id)); } else { - record_array!(self.tables.children[def_id] <- iter::from_generator(|| { - for item_id in md.item_ids { - match tcx.hir().item(*item_id).kind { - // Foreign items are planted into their parent modules - // from name resolution point of view. - hir::ItemKind::ForeignMod { items, .. } => { - for foreign_item in items { - yield foreign_item.id.owner_id.def_id.local_def_index; - } - } - // Only encode named non-reexport children, reexports are encoded - // separately and unnamed items are not used by name resolution. - hir::ItemKind::ExternCrate(..) => continue, - hir::ItemKind::Struct(ref vdata, _) => { - yield item_id.owner_id.def_id.local_def_index; - // Encode constructors which take a separate slot in value namespace. - if let Some(ctor_def_id) = vdata.ctor_def_id() { - yield ctor_def_id.local_def_index; - } - } - _ if tcx.def_key(item_id.owner_id.to_def_id()).get_opt_name().is_some() => { - yield item_id.owner_id.def_id.local_def_index; - } - _ => continue, - } - } - })); + let non_reexports = tcx.module_children_non_reexports(local_def_id); + record_array!(self.tables.children[def_id] <- + non_reexports.iter().map(|def_id| def_id.local_def_index)); - let reexports = tcx.module_reexports(local_def_id); - if !reexports.is_empty() { - record_array!(self.tables.module_reexports[def_id] <- reexports); - } + record_defaulted_array!(self.tables.module_children_reexports[def_id] <- + tcx.module_children_reexports(local_def_id)); } } @@ -1668,8 +1636,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tables.is_macro_rules.set(def_id.index, macro_def.macro_rules); record!(self.tables.macro_definition[def_id] <- &*macro_def.body); } - hir::ItemKind::Mod(ref m) => { - self.encode_info_for_mod(item.owner_id.def_id, m); + hir::ItemKind::Mod(..) => { + self.encode_info_for_mod(item.owner_id.def_id); } hir::ItemKind::OpaqueTy(ref opaque) => { self.encode_explicit_item_bounds(def_id); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 569fd20fdfe6..dc77a079b075 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -357,6 +357,7 @@ define_tables! { associated_types_for_impl_traits_in_associated_fn: Table>, opt_rpitit_info: Table>>, unused_generic_params: Table, + module_children_reexports: Table>, - optional: attributes: Table>, @@ -414,7 +415,6 @@ define_tables! { assoc_container: Table, macro_definition: Table>, proc_macro: Table, - module_reexports: Table>, deduced_param_attrs: Table>, trait_impl_trait_tys: Table>>>, doc_link_resolutions: Table>, diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs index fabc6bce7317..f3170e0ec0e1 100644 --- a/compiler/rustc_middle/src/metadata.rs +++ b/compiler/rustc_middle/src/metadata.rs @@ -43,8 +43,6 @@ pub struct ModChild { pub vis: ty::Visibility, /// Span of the item. pub span: Span, - /// A proper `macro_rules` item (not a reexport). - pub macro_rules: bool, /// Reexport chain linking this module child to its original reexported item. /// Empty if the module child is a proper item. pub reexport_chain: SmallVec<[Reexport; 2]>, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 2f6b7a3c860b..ef9f91f88597 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1516,10 +1516,6 @@ rustc_queries! { desc { "getting traits in scope at a block" } } - query module_reexports(def_id: LocalDefId) -> &'tcx [ModChild] { - desc { |tcx| "looking up reexports of module `{}`", tcx.def_path_str(def_id.to_def_id()) } - } - query impl_defaultness(def_id: DefId) -> hir::Defaultness { desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) } cache_on_disk_if { def_id.is_local() } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c312aaf6819a..63f7cc2ee735 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -8,6 +8,7 @@ use crate::arena::Arena; use crate::dep_graph::{DepGraph, DepKindStruct}; use crate::infer::canonical::CanonicalVarInfo; use crate::lint::struct_lint_level; +use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::resolve_bound_vars; use crate::middle::stability; @@ -2459,6 +2460,28 @@ impl<'tcx> TyCtxt<'tcx> { self.def_kind(def_id) == DefKind::ImplTraitPlaceholder } } + + /// Named module children from all items except `use` and `extern crate` imports. + /// + /// In addition to regular items this list also includes struct or variant constructors, and + /// items inside `extern {}` blocks because all of them introduce names into parent module. + /// For non-reexported children every such name is associated with a separate `DefId`. + /// + /// Module here is understood in name resolution sense - it can be a `mod` item, + /// or a crate root, or an enum, or a trait. + pub fn module_children_non_reexports(self, def_id: LocalDefId) -> &'tcx [LocalDefId] { + self.resolutions(()).module_children_non_reexports.get(&def_id).map_or(&[], |v| &v[..]) + } + + /// Named module children from `use` and `extern crate` imports. + /// + /// Reexported names are not associated with individual `DefId`s, + /// e.g. a glob import can introduce a lot of names, all with the same `DefId`. + /// That's why the list needs to contain `ModChild` structures describing all the names + /// individually instead of `DefId`s. + pub fn module_children_reexports(self, def_id: LocalDefId) -> &'tcx [ModChild] { + self.resolutions(()).module_children_reexports.get(&def_id).map_or(&[], |v| &v[..]) + } } impl<'tcx> TyCtxtAt<'tcx> { @@ -2501,8 +2524,6 @@ pub struct DeducedParamAttrs { } pub fn provide(providers: &mut ty::query::Providers) { - providers.module_reexports = - |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map_or(&[], |v| &v[..]); providers.maybe_unused_trait_imports = |tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports; providers.names_imported_by_glob_use = |tcx, id| { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c856bb25e147..2e516f291bc0 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -166,7 +166,8 @@ pub struct ResolverGlobalCtxt { pub effective_visibilities: EffectiveVisibilities, pub extern_crate_map: FxHashMap, pub maybe_unused_trait_imports: FxIndexSet, - pub reexport_map: FxHashMap>, + pub module_children_non_reexports: LocalDefIdMap>, + pub module_children_reexports: LocalDefIdMap>, pub glob_map: FxHashMap>, pub main_def: Option, pub trait_impls: FxIndexMap>, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 089e043d61c3..dcebfca08fac 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -515,7 +515,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { let vis = self.tcx.local_visibility(item_id.owner_id.def_id); self.update_macro_reachable_def(item_id.owner_id.def_id, def_kind, vis, defining_mod); } - for export in self.tcx.module_reexports(module_def_id) { + for export in self.tcx.module_children_reexports(module_def_id) { if export.vis.is_accessible_from(defining_mod, self.tcx) && let Res::Def(def_kind, def_id) = export.res && let Some(def_id) = def_id.as_local() { diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 1f2a90829ec7..ff0f1f55975f 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -931,7 +931,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { /// Builds the reduced graph for a single item in an external crate. fn build_reduced_graph_for_external_crate_res(&mut self, child: ModChild) { let parent = self.parent_scope.module; - let ModChild { ident, res, vis, span, macro_rules, .. } = child; + let ModChild { ident, res, vis, span, .. } = child; let res = res.expect_non_local(); let expansion = self.parent_scope.expansion; // Record primary definitions. @@ -964,9 +964,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { _, ) => self.r.define(parent, ident, ValueNS, (res, vis, span, expansion)), Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => { - if !macro_rules { - self.r.define(parent, ident, MacroNS, (res, vis, span, expansion)) - } + self.r.define(parent, ident, MacroNS, (res, vis, span, expansion)) } Res::Def( DefKind::TyParam diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 77bfcb659de1..3c22d51c3d47 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1261,10 +1261,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { *module.globs.borrow_mut() = Vec::new(); if let Some(def_id) = module.opt_def_id() { + let mut non_reexports = Vec::new(); let mut reexports = Vec::new(); module.for_each_child(self, |this, ident, _, binding| { - if let Some(res) = this.is_reexport(binding) { + let res = binding.res().expect_non_local(); + if !binding.is_import() { + non_reexports.push(res.def_id().expect_local()); + } else if res != def::Res::Err && !binding.is_ambiguity() { let mut reexport_chain = SmallVec::new(); let mut next_binding = binding; while let NameBindingKind::Import { binding, import, .. } = next_binding.kind { @@ -1277,16 +1281,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { res, vis: binding.vis, span: binding.span, - macro_rules: false, reexport_chain, }); } }); + // Should be fine because this code is only called for local modules. + let def_id = def_id.expect_local(); + if !non_reexports.is_empty() { + self.module_children_non_reexports.insert(def_id, non_reexports); + } if !reexports.is_empty() { - // Call to `expect_local` should be fine because current - // code is only called for local modules. - self.reexport_map.insert(def_id.expect_local(), reexports); + self.module_children_reexports.insert(def_id, reexports); } } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 99fad22d4a12..2ed871a4f776 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -910,7 +910,8 @@ pub struct Resolver<'a, 'tcx> { /// `CrateNum` resolutions of `extern crate` items. extern_crate_map: FxHashMap, - reexport_map: FxHashMap>, + module_children_non_reexports: LocalDefIdMap>, + module_children_reexports: LocalDefIdMap>, trait_map: NodeMap>, /// A map from nodes to anonymous modules. @@ -1260,7 +1261,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { lifetimes_res_map: Default::default(), extra_lifetime_params_map: Default::default(), extern_crate_map: Default::default(), - reexport_map: FxHashMap::default(), + module_children_non_reexports: Default::default(), + module_children_reexports: Default::default(), trait_map: NodeMap::default(), underscore_disambiguator: 0, empty_module, @@ -1387,7 +1389,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let visibilities = self.visibilities; let has_pub_restricted = self.has_pub_restricted; let extern_crate_map = self.extern_crate_map; - let reexport_map = self.reexport_map; let maybe_unused_trait_imports = self.maybe_unused_trait_imports; let glob_map = self.glob_map; let main_def = self.main_def; @@ -1399,7 +1400,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { has_pub_restricted, effective_visibilities, extern_crate_map, - reexport_map, + module_children_non_reexports: self.module_children_non_reexports, + module_children_reexports: self.module_children_reexports, glob_map, maybe_unused_trait_imports, main_def, @@ -1950,20 +1952,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } self.main_def = Some(MainDefinition { res, is_import, span }); } - - // Items that go to reexport table encoded to metadata and visible through it to other crates. - fn is_reexport(&self, binding: &NameBinding<'a>) -> Option> { - if binding.is_import() { - let res = binding.res().expect_non_local(); - // Ambiguous imports are treated as errors at this point and are - // not exposed to other crates (see #36837 for more details). - if res != def::Res::Err && !binding.is_ambiguity() { - return Some(res); - } - } - - return None; - } } fn names_to_string(names: &[Symbol]) -> String { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 9270d1c02e21..e4b29fa91c86 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -152,7 +152,7 @@ pub(crate) fn try_inline_glob( // reexported by the glob, e.g. because they are shadowed by something else. let reexports = cx .tcx - .module_reexports(current_mod) + .module_children_reexports(current_mod) .iter() .filter_map(|child| child.res.opt_def_id()) .collect(); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b3df12a9df13..989e75cb8280 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2062,7 +2062,7 @@ pub(crate) fn reexport_chain<'tcx>( import_def_id: LocalDefId, target_def_id: LocalDefId, ) -> &'tcx [Reexport] { - for child in tcx.module_reexports(tcx.local_parent(import_def_id)) { + for child in tcx.module_children_reexports(tcx.local_parent(import_def_id)) { if child.res.opt_def_id() == Some(target_def_id.to_def_id()) && child.reexport_chain[0].id() == Some(import_def_id.to_def_id()) { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 393d51fe0906..f54b70b417d7 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -133,7 +133,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // is declared but also a reexport of itself producing two exports of the same // macro in the same module. let mut inserted = FxHashSet::default(); - for export in self.cx.tcx.module_reexports(CRATE_DEF_ID) { + for export in self.cx.tcx.module_children_reexports(CRATE_DEF_ID) { if let Res::Def(DefKind::Macro(_), def_id) = export.res && let Some(local_def_id) = def_id.as_local() && self.cx.tcx.has_attr(def_id, sym::macro_export) && diff --git a/src/tools/clippy/tests/ui/macro_use_imports.fixed b/src/tools/clippy/tests/ui/macro_use_imports.fixed index 15f7a099a7de..a395e4f5653f 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.fixed +++ b/src/tools/clippy/tests/ui/macro_use_imports.fixed @@ -16,7 +16,7 @@ extern crate macro_use_helper as mac; extern crate proc_macro_derive as mini_mac; mod a { - use mac::{pub_macro, function_macro, ty_macro, inner_mod_macro, pub_in_private_macro}; + use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro}; use mac; use mini_mac::ClippyMiniMacroTest; use mini_mac; diff --git a/src/tools/clippy/tests/ui/macro_use_imports.stderr b/src/tools/clippy/tests/ui/macro_use_imports.stderr index 68d558dede05..6fd338cef868 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.stderr +++ b/src/tools/clippy/tests/ui/macro_use_imports.stderr @@ -22,7 +22,7 @@ error: `macro_use` attributes are no longer needed in the Rust 2018 edition --> $DIR/macro_use_imports.rs:19:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, function_macro, ty_macro, inner_mod_macro, pub_in_private_macro};` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};` error: aborting due to 4 previous errors From 229b0a0fdca1fa2bbf27a13c7dbb205c6a78af86 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 12 Apr 2023 13:57:12 +0100 Subject: [PATCH 223/272] Make rust-intrinsic ABI unwindable Stick `#[rustc_nounwind]` to all except `const_eval_select` to undo the change for all other intrinsics. --- compiler/rustc_middle/src/ty/layout.rs | 5 +- library/core/src/ffi/mod.rs | 3 + library/core/src/intrinsics.rs | 230 ++++++++++++++++++++++++- library/core/src/ptr/mod.rs | 1 + 4 files changed, 236 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 2328a1324fc3..195d951f9f36 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1226,10 +1226,11 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: SpecAbi) -> | AvrNonBlockingInterrupt | CCmseNonSecureCall | Wasm - | RustIntrinsic | PlatformIntrinsic | Unadjusted => false, - Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind, + Rust | RustCall | RustCold | RustIntrinsic => { + tcx.sess.panic_strategy() == PanicStrategy::Unwind + } } } diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 27f6659049c5..c4f554c8c6bf 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -615,12 +615,15 @@ impl<'f> Drop for VaListImpl<'f> { extern "rust-intrinsic" { /// Destroy the arglist `ap` after initialization with `va_start` or /// `va_copy`. + #[rustc_nounwind] fn va_end(ap: &mut VaListImpl<'_>); /// Copies the current location of arglist `src` to the arglist `dst`. + #[rustc_nounwind] fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>); /// Loads an argument of type `T` from the `va_list` `ap` and increment the /// argument `ap` points to. + #[rustc_nounwind] fn va_arg(ap: &mut VaListImpl<'_>) -> T; } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 7482b8b0862e..10c5425b7cf0 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -84,6 +84,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::Relaxed`] as both the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. + #[rustc_nounwind] pub fn atomic_cxchg_relaxed_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -91,6 +92,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::Relaxed`] and [`Ordering::Acquire`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. + #[rustc_nounwind] pub fn atomic_cxchg_relaxed_acquire(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -98,6 +100,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::Relaxed`] and [`Ordering::SeqCst`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. + #[rustc_nounwind] pub fn atomic_cxchg_relaxed_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -105,6 +108,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::Acquire`] and [`Ordering::Relaxed`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. + #[rustc_nounwind] pub fn atomic_cxchg_acquire_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -112,6 +116,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::Acquire`] as both the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. + #[rustc_nounwind] pub fn atomic_cxchg_acquire_acquire(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -119,6 +124,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::Acquire`] and [`Ordering::SeqCst`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. + #[rustc_nounwind] pub fn atomic_cxchg_acquire_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -126,6 +132,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::Release`] and [`Ordering::Relaxed`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. + #[rustc_nounwind] pub fn atomic_cxchg_release_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -133,6 +140,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::Release`] and [`Ordering::Acquire`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. + #[rustc_nounwind] pub fn atomic_cxchg_release_acquire(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -140,6 +148,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::Release`] and [`Ordering::SeqCst`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. + #[rustc_nounwind] pub fn atomic_cxchg_release_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -147,6 +156,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::AcqRel`] and [`Ordering::Relaxed`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. + #[rustc_nounwind] pub fn atomic_cxchg_acqrel_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -154,6 +164,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::AcqRel`] and [`Ordering::Acquire`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. + #[rustc_nounwind] pub fn atomic_cxchg_acqrel_acquire(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -161,6 +172,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::AcqRel`] and [`Ordering::SeqCst`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. + #[rustc_nounwind] pub fn atomic_cxchg_acqrel_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -168,6 +180,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::SeqCst`] and [`Ordering::Relaxed`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. + #[rustc_nounwind] pub fn atomic_cxchg_seqcst_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -175,6 +188,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::SeqCst`] and [`Ordering::Acquire`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. + #[rustc_nounwind] pub fn atomic_cxchg_seqcst_acquire(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -182,6 +196,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::SeqCst`] as both the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. + #[rustc_nounwind] pub fn atomic_cxchg_seqcst_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. @@ -190,6 +205,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::Relaxed`] as both the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. + #[rustc_nounwind] pub fn atomic_cxchgweak_relaxed_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -197,6 +213,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::Relaxed`] and [`Ordering::Acquire`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. + #[rustc_nounwind] pub fn atomic_cxchgweak_relaxed_acquire(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -204,6 +221,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::Relaxed`] and [`Ordering::SeqCst`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. + #[rustc_nounwind] pub fn atomic_cxchgweak_relaxed_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -211,6 +229,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::Acquire`] and [`Ordering::Relaxed`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. + #[rustc_nounwind] pub fn atomic_cxchgweak_acquire_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -218,6 +237,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::Acquire`] as both the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. + #[rustc_nounwind] pub fn atomic_cxchgweak_acquire_acquire(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -225,6 +245,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::Acquire`] and [`Ordering::SeqCst`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. + #[rustc_nounwind] pub fn atomic_cxchgweak_acquire_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -232,6 +253,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::Release`] and [`Ordering::Relaxed`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. + #[rustc_nounwind] pub fn atomic_cxchgweak_release_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -239,6 +261,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::Release`] and [`Ordering::Acquire`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. + #[rustc_nounwind] pub fn atomic_cxchgweak_release_acquire(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -246,6 +269,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::Release`] and [`Ordering::SeqCst`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. + #[rustc_nounwind] pub fn atomic_cxchgweak_release_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -253,6 +277,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::AcqRel`] and [`Ordering::Relaxed`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. + #[rustc_nounwind] pub fn atomic_cxchgweak_acqrel_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -260,6 +285,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::AcqRel`] and [`Ordering::Acquire`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. + #[rustc_nounwind] pub fn atomic_cxchgweak_acqrel_acquire(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -267,6 +293,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::AcqRel`] and [`Ordering::SeqCst`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. + #[rustc_nounwind] pub fn atomic_cxchgweak_acqrel_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -274,6 +301,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::SeqCst`] and [`Ordering::Relaxed`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. + #[rustc_nounwind] pub fn atomic_cxchgweak_seqcst_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -281,6 +309,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::SeqCst`] and [`Ordering::Acquire`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. + #[rustc_nounwind] pub fn atomic_cxchgweak_seqcst_acquire(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// @@ -288,6 +317,7 @@ extern "rust-intrinsic" { /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::SeqCst`] as both the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. + #[rustc_nounwind] pub fn atomic_cxchgweak_seqcst_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Loads the current value of the pointer. @@ -295,19 +325,23 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `load` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::load`]. + #[rustc_nounwind] pub fn atomic_load_seqcst(src: *const T) -> T; /// Loads the current value of the pointer. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `load` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::load`]. + #[rustc_nounwind] pub fn atomic_load_acquire(src: *const T) -> T; /// Loads the current value of the pointer. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `load` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::load`]. + #[rustc_nounwind] pub fn atomic_load_relaxed(src: *const T) -> T; + #[rustc_nounwind] pub fn atomic_load_unordered(src: *const T) -> T; /// Stores the value at the specified memory location. @@ -315,19 +349,23 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `store` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::store`]. + #[rustc_nounwind] pub fn atomic_store_seqcst(dst: *mut T, val: T); /// Stores the value at the specified memory location. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `store` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::store`]. + #[rustc_nounwind] pub fn atomic_store_release(dst: *mut T, val: T); /// Stores the value at the specified memory location. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `store` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::store`]. + #[rustc_nounwind] pub fn atomic_store_relaxed(dst: *mut T, val: T); + #[rustc_nounwind] pub fn atomic_store_unordered(dst: *mut T, val: T); /// Stores the value at the specified memory location, returning the old value. @@ -335,30 +373,35 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `swap` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::swap`]. + #[rustc_nounwind] pub fn atomic_xchg_seqcst(dst: *mut T, src: T) -> T; /// Stores the value at the specified memory location, returning the old value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `swap` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::swap`]. + #[rustc_nounwind] pub fn atomic_xchg_acquire(dst: *mut T, src: T) -> T; /// Stores the value at the specified memory location, returning the old value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `swap` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::swap`]. + #[rustc_nounwind] pub fn atomic_xchg_release(dst: *mut T, src: T) -> T; /// Stores the value at the specified memory location, returning the old value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `swap` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::swap`]. + #[rustc_nounwind] pub fn atomic_xchg_acqrel(dst: *mut T, src: T) -> T; /// Stores the value at the specified memory location, returning the old value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `swap` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::swap`]. + #[rustc_nounwind] pub fn atomic_xchg_relaxed(dst: *mut T, src: T) -> T; /// Adds to the current value, returning the previous value. @@ -366,30 +409,35 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_add` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicIsize::fetch_add`]. + #[rustc_nounwind] pub fn atomic_xadd_seqcst(dst: *mut T, src: T) -> T; /// Adds to the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_add` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicIsize::fetch_add`]. + #[rustc_nounwind] pub fn atomic_xadd_acquire(dst: *mut T, src: T) -> T; /// Adds to the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_add` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicIsize::fetch_add`]. + #[rustc_nounwind] pub fn atomic_xadd_release(dst: *mut T, src: T) -> T; /// Adds to the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_add` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicIsize::fetch_add`]. + #[rustc_nounwind] pub fn atomic_xadd_acqrel(dst: *mut T, src: T) -> T; /// Adds to the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_add` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicIsize::fetch_add`]. + #[rustc_nounwind] pub fn atomic_xadd_relaxed(dst: *mut T, src: T) -> T; /// Subtract from the current value, returning the previous value. @@ -397,30 +445,35 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_sub` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. + #[rustc_nounwind] pub fn atomic_xsub_seqcst(dst: *mut T, src: T) -> T; /// Subtract from the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_sub` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. + #[rustc_nounwind] pub fn atomic_xsub_acquire(dst: *mut T, src: T) -> T; /// Subtract from the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_sub` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. + #[rustc_nounwind] pub fn atomic_xsub_release(dst: *mut T, src: T) -> T; /// Subtract from the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_sub` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. + #[rustc_nounwind] pub fn atomic_xsub_acqrel(dst: *mut T, src: T) -> T; /// Subtract from the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_sub` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. + #[rustc_nounwind] pub fn atomic_xsub_relaxed(dst: *mut T, src: T) -> T; /// Bitwise and with the current value, returning the previous value. @@ -428,30 +481,35 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_and` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_and`]. + #[rustc_nounwind] pub fn atomic_and_seqcst(dst: *mut T, src: T) -> T; /// Bitwise and with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_and` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_and`]. + #[rustc_nounwind] pub fn atomic_and_acquire(dst: *mut T, src: T) -> T; /// Bitwise and with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_and` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_and`]. + #[rustc_nounwind] pub fn atomic_and_release(dst: *mut T, src: T) -> T; /// Bitwise and with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_and` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_and`]. + #[rustc_nounwind] pub fn atomic_and_acqrel(dst: *mut T, src: T) -> T; /// Bitwise and with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_and` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_and`]. + #[rustc_nounwind] pub fn atomic_and_relaxed(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. @@ -459,30 +517,35 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`AtomicBool`] type via the `fetch_nand` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_nand`]. + #[rustc_nounwind] pub fn atomic_nand_seqcst(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`AtomicBool`] type via the `fetch_nand` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_nand`]. + #[rustc_nounwind] pub fn atomic_nand_acquire(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`AtomicBool`] type via the `fetch_nand` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_nand`]. + #[rustc_nounwind] pub fn atomic_nand_release(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`AtomicBool`] type via the `fetch_nand` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_nand`]. + #[rustc_nounwind] pub fn atomic_nand_acqrel(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`AtomicBool`] type via the `fetch_nand` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_nand`]. + #[rustc_nounwind] pub fn atomic_nand_relaxed(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. @@ -490,30 +553,35 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_or` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_or`]. + #[rustc_nounwind] pub fn atomic_or_seqcst(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_or` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_or`]. + #[rustc_nounwind] pub fn atomic_or_acquire(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_or` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_or`]. + #[rustc_nounwind] pub fn atomic_or_release(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_or` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_or`]. + #[rustc_nounwind] pub fn atomic_or_acqrel(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_or` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_or`]. + #[rustc_nounwind] pub fn atomic_or_relaxed(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. @@ -521,30 +589,35 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_xor` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_xor`]. + #[rustc_nounwind] pub fn atomic_xor_seqcst(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_xor` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_xor`]. + #[rustc_nounwind] pub fn atomic_xor_acquire(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_xor` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_xor`]. + #[rustc_nounwind] pub fn atomic_xor_release(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_xor` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_xor`]. + #[rustc_nounwind] pub fn atomic_xor_acqrel(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_xor` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_xor`]. + #[rustc_nounwind] pub fn atomic_xor_relaxed(dst: *mut T, src: T) -> T; /// Maximum with the current value using a signed comparison. @@ -552,30 +625,35 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_max` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicI32::fetch_max`]. + #[rustc_nounwind] pub fn atomic_max_seqcst(dst: *mut T, src: T) -> T; /// Maximum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_max` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicI32::fetch_max`]. + #[rustc_nounwind] pub fn atomic_max_acquire(dst: *mut T, src: T) -> T; /// Maximum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_max` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicI32::fetch_max`]. + #[rustc_nounwind] pub fn atomic_max_release(dst: *mut T, src: T) -> T; /// Maximum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_max` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicI32::fetch_max`]. + #[rustc_nounwind] pub fn atomic_max_acqrel(dst: *mut T, src: T) -> T; /// Maximum with the current value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_max` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicI32::fetch_max`]. + #[rustc_nounwind] pub fn atomic_max_relaxed(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. @@ -583,18 +661,21 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_min` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicI32::fetch_min`]. + #[rustc_nounwind] pub fn atomic_min_seqcst(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_min` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicI32::fetch_min`]. + #[rustc_nounwind] pub fn atomic_min_acquire(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_min` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicI32::fetch_min`]. + #[rustc_nounwind] pub fn atomic_min_release(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. /// @@ -607,6 +688,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_min` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicI32::fetch_min`]. + #[rustc_nounwind] pub fn atomic_min_relaxed(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. @@ -614,30 +696,35 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_min` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicU32::fetch_min`]. + #[rustc_nounwind] pub fn atomic_umin_seqcst(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_min` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicU32::fetch_min`]. + #[rustc_nounwind] pub fn atomic_umin_acquire(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_min` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicU32::fetch_min`]. + #[rustc_nounwind] pub fn atomic_umin_release(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_min` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicU32::fetch_min`]. + #[rustc_nounwind] pub fn atomic_umin_acqrel(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_min` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicU32::fetch_min`]. + #[rustc_nounwind] pub fn atomic_umin_relaxed(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. @@ -645,30 +732,35 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_max` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicU32::fetch_max`]. + #[rustc_nounwind] pub fn atomic_umax_seqcst(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_max` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicU32::fetch_max`]. + #[rustc_nounwind] pub fn atomic_umax_acquire(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_max` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicU32::fetch_max`]. + #[rustc_nounwind] pub fn atomic_umax_release(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_max` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicU32::fetch_max`]. + #[rustc_nounwind] pub fn atomic_umax_acqrel(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_max` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicU32::fetch_max`]. + #[rustc_nounwind] pub fn atomic_umax_relaxed(dst: *mut T, src: T) -> T; /// An atomic fence. @@ -676,24 +768,28 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available in /// [`atomic::fence`] by passing [`Ordering::SeqCst`] /// as the `order`. + #[rustc_nounwind] pub fn atomic_fence_seqcst(); /// An atomic fence. /// /// The stabilized version of this intrinsic is available in /// [`atomic::fence`] by passing [`Ordering::Acquire`] /// as the `order`. + #[rustc_nounwind] pub fn atomic_fence_acquire(); /// An atomic fence. /// /// The stabilized version of this intrinsic is available in /// [`atomic::fence`] by passing [`Ordering::Release`] /// as the `order`. + #[rustc_nounwind] pub fn atomic_fence_release(); /// An atomic fence. /// /// The stabilized version of this intrinsic is available in /// [`atomic::fence`] by passing [`Ordering::AcqRel`] /// as the `order`. + #[rustc_nounwind] pub fn atomic_fence_acqrel(); /// A compiler-only memory barrier. @@ -706,6 +802,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available in /// [`atomic::compiler_fence`] by passing [`Ordering::SeqCst`] /// as the `order`. + #[rustc_nounwind] pub fn atomic_singlethreadfence_seqcst(); /// A compiler-only memory barrier. /// @@ -717,6 +814,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available in /// [`atomic::compiler_fence`] by passing [`Ordering::Acquire`] /// as the `order`. + #[rustc_nounwind] pub fn atomic_singlethreadfence_acquire(); /// A compiler-only memory barrier. /// @@ -728,6 +826,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available in /// [`atomic::compiler_fence`] by passing [`Ordering::Release`] /// as the `order`. + #[rustc_nounwind] pub fn atomic_singlethreadfence_release(); /// A compiler-only memory barrier. /// @@ -739,6 +838,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available in /// [`atomic::compiler_fence`] by passing [`Ordering::AcqRel`] /// as the `order`. + #[rustc_nounwind] pub fn atomic_singlethreadfence_acqrel(); /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction @@ -750,6 +850,7 @@ extern "rust-intrinsic" { /// ranging from (0) - no locality, to (3) - extremely local keep in cache. /// /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] pub fn prefetch_read_data(data: *const T, locality: i32); /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction /// if supported; otherwise, it is a no-op. @@ -760,6 +861,7 @@ extern "rust-intrinsic" { /// ranging from (0) - no locality, to (3) - extremely local keep in cache. /// /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] pub fn prefetch_write_data(data: *const T, locality: i32); /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction /// if supported; otherwise, it is a no-op. @@ -770,6 +872,7 @@ extern "rust-intrinsic" { /// ranging from (0) - no locality, to (3) - extremely local keep in cache. /// /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] pub fn prefetch_read_instruction(data: *const T, locality: i32); /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction /// if supported; otherwise, it is a no-op. @@ -780,6 +883,7 @@ extern "rust-intrinsic" { /// ranging from (0) - no locality, to (3) - extremely local keep in cache. /// /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] pub fn prefetch_write_instruction(data: *const T, locality: i32); /// Magic intrinsic that derives its meaning from attributes @@ -792,6 +896,7 @@ extern "rust-intrinsic" { /// /// This intrinsic should not be used outside of the compiler. #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn rustc_peek(_: T) -> T; /// Aborts the execution of the process. @@ -810,6 +915,7 @@ extern "rust-intrinsic" { /// process will probably terminate with a signal like `SIGABRT`, `SIGILL`, `SIGTRAP`, `SIGSEGV` or /// `SIGBUS`. The precise behaviour is not guaranteed and not stable. #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn abort() -> !; /// Informs the optimizer that this point in the code is not reachable, @@ -821,6 +927,7 @@ extern "rust-intrinsic" { /// /// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`]. #[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. @@ -834,6 +941,7 @@ extern "rust-intrinsic" { /// /// This intrinsic does not have a stable counterpart. #[rustc_const_unstable(feature = "const_assume", issue = "76972")] + #[rustc_nounwind] pub fn assume(b: bool); /// Hints to the compiler that branch condition is likely to be true. @@ -849,6 +957,7 @@ extern "rust-intrinsic" { /// This intrinsic does not have a stable counterpart. #[rustc_const_unstable(feature = "const_likely", issue = "none")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn likely(b: bool) -> bool; /// Hints to the compiler that branch condition is likely to be false. @@ -864,11 +973,13 @@ extern "rust-intrinsic" { /// This intrinsic does not have a stable counterpart. #[rustc_const_unstable(feature = "const_likely", issue = "none")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn unlikely(b: bool) -> bool; /// Executes a breakpoint trap, for inspection by a debugger. /// /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] pub fn breakpoint(); /// The size of a type in bytes. @@ -884,6 +995,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is [`core::mem::size_of`]. #[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. @@ -896,23 +1008,27 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is [`core::mem::align_of`]. #[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). #[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 [`mem::size_of_val`]. #[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`]. #[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. @@ -925,6 +1041,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is [`core::any::type_name`]. #[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 @@ -939,6 +1056,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is [`core::any::TypeId::of`]. #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn type_id() -> u64; /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited: @@ -947,6 +1065,7 @@ extern "rust-intrinsic" { /// This intrinsic does not have a stable counterpart. #[rustc_const_stable(feature = "const_assert_type", since = "1.59.0")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn assert_inhabited(); /// A guard for unsafe functions that cannot ever be executed if `T` does not permit @@ -955,6 +1074,7 @@ extern "rust-intrinsic" { /// This intrinsic does not have a stable counterpart. #[rustc_const_unstable(feature = "const_assert_type2", issue = "none")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn assert_zero_valid(); /// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing. @@ -962,6 +1082,7 @@ extern "rust-intrinsic" { /// This intrinsic does not have a stable counterpart. #[rustc_const_unstable(feature = "const_assert_type2", issue = "none")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn assert_mem_uninitialized_valid(); /// Gets a reference to a static `Location` indicating where it was called. @@ -974,6 +1095,7 @@ extern "rust-intrinsic" { /// Consider using [`core::panic::Location::caller`] instead. #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn caller_location() -> &'static crate::panic::Location<'static>; /// Moves a value out of scope without running drop glue. @@ -987,6 +1109,7 @@ extern "rust-intrinsic" { /// any safety invariants. #[rustc_const_unstable(feature = "const_intrinsic_forget", issue = "none")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn forget(_: T); /// Reinterprets the bits of a value of one type as another type. @@ -1250,6 +1373,7 @@ extern "rust-intrinsic" { #[rustc_allowed_through_unstable_modules] #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] #[rustc_diagnostic_item = "transmute"] + #[rustc_nounwind] pub fn transmute(src: Src) -> Dst; /// Returns `true` if the actual type given as `T` requires drop @@ -1267,6 +1391,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop). #[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn needs_drop() -> bool; /// Calculates the offset from a pointer. @@ -1284,6 +1409,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is [`pointer::offset`]. #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[rustc_nounwind] pub fn offset(dst: *const T, offset: isize) -> *const T; /// Calculates the offset from a pointer, potentially wrapping. @@ -1301,6 +1427,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is [`pointer::wrapping_offset`]. #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[rustc_nounwind] pub fn arith_offset(dst: *const T, offset: isize) -> *const T; /// Masks out bits of the pointer according to a mask. @@ -1312,6 +1439,7 @@ extern "rust-intrinsic" { /// /// Consider using [`pointer::mask`] instead. #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn ptr_mask(ptr: *const T, mask: usize) -> *const T; /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with @@ -1322,6 +1450,7 @@ extern "rust-intrinsic" { /// unless size is equal to zero. /// /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] pub fn volatile_copy_nonoverlapping_memory(dst: *mut T, src: *const T, count: usize); /// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with /// a size of `count * size_of::()` and an alignment of @@ -1331,6 +1460,7 @@ extern "rust-intrinsic" { /// unless size is equal to zero. /// /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] pub fn volatile_copy_memory(dst: *mut T, src: *const T, count: usize); /// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a /// size of `count * size_of::()` and an alignment of @@ -1340,158 +1470,187 @@ extern "rust-intrinsic" { /// unless size is equal to zero. /// /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] pub fn volatile_set_memory(dst: *mut T, val: u8, count: usize); /// Performs a volatile load from the `src` pointer. /// /// The stabilized version of this intrinsic is [`core::ptr::read_volatile`]. + #[rustc_nounwind] pub fn volatile_load(src: *const T) -> T; /// Performs a volatile store to the `dst` pointer. /// /// The stabilized version of this intrinsic is [`core::ptr::write_volatile`]. + #[rustc_nounwind] pub fn volatile_store(dst: *mut T, val: T); /// Performs a volatile load from the `src` pointer /// The pointer is not required to be aligned. /// /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] pub fn unaligned_volatile_load(src: *const T) -> T; /// Performs a volatile store to the `dst` pointer. /// The pointer is not required to be aligned. /// /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] pub fn unaligned_volatile_store(dst: *mut T, val: T); /// Returns the square root of an `f32` /// /// The stabilized version of this intrinsic is /// [`f32::sqrt`](../../std/primitive.f32.html#method.sqrt) + #[rustc_nounwind] pub fn sqrtf32(x: f32) -> f32; /// Returns the square root of an `f64` /// /// The stabilized version of this intrinsic is /// [`f64::sqrt`](../../std/primitive.f64.html#method.sqrt) + #[rustc_nounwind] pub fn sqrtf64(x: f64) -> f64; /// Raises an `f32` to an integer power. /// /// The stabilized version of this intrinsic is /// [`f32::powi`](../../std/primitive.f32.html#method.powi) + #[rustc_nounwind] pub fn powif32(a: f32, x: i32) -> f32; /// Raises an `f64` to an integer power. /// /// The stabilized version of this intrinsic is /// [`f64::powi`](../../std/primitive.f64.html#method.powi) + #[rustc_nounwind] pub fn powif64(a: f64, x: i32) -> f64; /// Returns the sine of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::sin`](../../std/primitive.f32.html#method.sin) + #[rustc_nounwind] pub fn sinf32(x: f32) -> f32; /// Returns the sine of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::sin`](../../std/primitive.f64.html#method.sin) + #[rustc_nounwind] pub fn sinf64(x: f64) -> f64; /// Returns the cosine of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::cos`](../../std/primitive.f32.html#method.cos) + #[rustc_nounwind] pub fn cosf32(x: f32) -> f32; /// Returns the cosine of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::cos`](../../std/primitive.f64.html#method.cos) + #[rustc_nounwind] pub fn cosf64(x: f64) -> f64; /// Raises an `f32` to an `f32` power. /// /// The stabilized version of this intrinsic is /// [`f32::powf`](../../std/primitive.f32.html#method.powf) + #[rustc_nounwind] pub fn powf32(a: f32, x: f32) -> f32; /// Raises an `f64` to an `f64` power. /// /// The stabilized version of this intrinsic is /// [`f64::powf`](../../std/primitive.f64.html#method.powf) + #[rustc_nounwind] pub fn powf64(a: f64, x: f64) -> f64; /// Returns the exponential of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::exp`](../../std/primitive.f32.html#method.exp) + #[rustc_nounwind] pub fn expf32(x: f32) -> f32; /// Returns the exponential of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::exp`](../../std/primitive.f64.html#method.exp) + #[rustc_nounwind] pub fn expf64(x: f64) -> f64; /// Returns 2 raised to the power of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::exp2`](../../std/primitive.f32.html#method.exp2) + #[rustc_nounwind] pub fn exp2f32(x: f32) -> f32; /// Returns 2 raised to the power of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::exp2`](../../std/primitive.f64.html#method.exp2) + #[rustc_nounwind] pub fn exp2f64(x: f64) -> f64; /// Returns the natural logarithm of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::ln`](../../std/primitive.f32.html#method.ln) + #[rustc_nounwind] pub fn logf32(x: f32) -> f32; /// Returns the natural logarithm of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::ln`](../../std/primitive.f64.html#method.ln) + #[rustc_nounwind] pub fn logf64(x: f64) -> f64; /// Returns the base 10 logarithm of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::log10`](../../std/primitive.f32.html#method.log10) + #[rustc_nounwind] pub fn log10f32(x: f32) -> f32; /// Returns the base 10 logarithm of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::log10`](../../std/primitive.f64.html#method.log10) + #[rustc_nounwind] pub fn log10f64(x: f64) -> f64; /// Returns the base 2 logarithm of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::log2`](../../std/primitive.f32.html#method.log2) + #[rustc_nounwind] pub fn log2f32(x: f32) -> f32; /// Returns the base 2 logarithm of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::log2`](../../std/primitive.f64.html#method.log2) + #[rustc_nounwind] pub fn log2f64(x: f64) -> f64; /// Returns `a * b + c` for `f32` values. /// /// The stabilized version of this intrinsic is /// [`f32::mul_add`](../../std/primitive.f32.html#method.mul_add) + #[rustc_nounwind] pub fn fmaf32(a: f32, b: f32, c: f32) -> f32; /// Returns `a * b + c` for `f64` values. /// /// The stabilized version of this intrinsic is /// [`f64::mul_add`](../../std/primitive.f64.html#method.mul_add) + #[rustc_nounwind] pub fn fmaf64(a: f64, b: f64, c: f64) -> f64; /// Returns the absolute value of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::abs`](../../std/primitive.f32.html#method.abs) + #[rustc_nounwind] pub fn fabsf32(x: f32) -> f32; /// Returns the absolute value of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::abs`](../../std/primitive.f64.html#method.abs) + #[rustc_nounwind] pub fn fabsf64(x: f64) -> f64; /// Returns the minimum of two `f32` values. @@ -1504,6 +1663,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is /// [`f32::min`] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn minnumf32(x: f32, y: f32) -> f32; /// Returns the minimum of two `f64` values. /// @@ -1515,6 +1675,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is /// [`f64::min`] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn minnumf64(x: f64, y: f64) -> f64; /// Returns the maximum of two `f32` values. /// @@ -1526,6 +1687,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is /// [`f32::max`] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn maxnumf32(x: f32, y: f32) -> f32; /// Returns the maximum of two `f64` values. /// @@ -1537,50 +1699,59 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is /// [`f64::max`] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn maxnumf64(x: f64, y: f64) -> f64; /// Copies the sign from `y` to `x` for `f32` values. /// /// The stabilized version of this intrinsic is /// [`f32::copysign`](../../std/primitive.f32.html#method.copysign) + #[rustc_nounwind] pub fn copysignf32(x: f32, y: f32) -> f32; /// Copies the sign from `y` to `x` for `f64` values. /// /// The stabilized version of this intrinsic is /// [`f64::copysign`](../../std/primitive.f64.html#method.copysign) + #[rustc_nounwind] pub fn copysignf64(x: f64, y: f64) -> f64; /// Returns the largest integer less than or equal to an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::floor`](../../std/primitive.f32.html#method.floor) + #[rustc_nounwind] pub fn floorf32(x: f32) -> f32; /// Returns the largest integer less than or equal to an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::floor`](../../std/primitive.f64.html#method.floor) + #[rustc_nounwind] pub fn floorf64(x: f64) -> f64; /// Returns the smallest integer greater than or equal to an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::ceil`](../../std/primitive.f32.html#method.ceil) + #[rustc_nounwind] pub fn ceilf32(x: f32) -> f32; /// Returns the smallest integer greater than or equal to an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::ceil`](../../std/primitive.f64.html#method.ceil) + #[rustc_nounwind] pub fn ceilf64(x: f64) -> f64; /// Returns the integer part of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::trunc`](../../std/primitive.f32.html#method.trunc) + #[rustc_nounwind] pub fn truncf32(x: f32) -> f32; /// Returns the integer part of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::trunc`](../../std/primitive.f64.html#method.trunc) + #[rustc_nounwind] pub fn truncf64(x: f64) -> f64; /// Returns the nearest integer to an `f32`. May raise an inexact floating-point exception @@ -1588,32 +1759,38 @@ extern "rust-intrinsic" { /// /// The stabilized version of this intrinsic is /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even) + #[rustc_nounwind] pub fn rintf32(x: f32) -> f32; /// Returns the nearest integer to an `f64`. May raise an inexact floating-point exception /// if the argument is not an integer. /// /// The stabilized version of this intrinsic is /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even) + #[rustc_nounwind] pub fn rintf64(x: f64) -> f64; /// Returns the nearest integer to an `f32`. /// /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] pub fn nearbyintf32(x: f32) -> f32; /// Returns the nearest integer to an `f64`. /// /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] pub fn nearbyintf64(x: f64) -> f64; /// Returns the nearest integer to an `f32`. Rounds half-way cases away from zero. /// /// The stabilized version of this intrinsic is /// [`f32::round`](../../std/primitive.f32.html#method.round) + #[rustc_nounwind] pub fn roundf32(x: f32) -> f32; /// Returns the nearest integer to an `f64`. Rounds half-way cases away from zero. /// /// The stabilized version of this intrinsic is /// [`f64::round`](../../std/primitive.f64.html#method.round) + #[rustc_nounwind] pub fn roundf64(x: f64) -> f64; /// Returns the nearest integer to an `f32`. Rounds half-way cases to the number @@ -1621,48 +1798,56 @@ extern "rust-intrinsic" { /// /// This intrinsic does not have a stable counterpart. #[cfg(not(bootstrap))] + #[rustc_nounwind] pub fn roundevenf32(x: f32) -> f32; /// Returns the nearest integer to an `f64`. Rounds half-way cases to the number /// with an even least significant digit. /// /// This intrinsic does not have a stable counterpart. #[cfg(not(bootstrap))] + #[rustc_nounwind] pub fn roundevenf64(x: f64) -> f64; /// Float addition that allows optimizations based on algebraic rules. /// May assume inputs are finite. /// /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] pub fn fadd_fast(a: T, b: T) -> T; /// Float subtraction that allows optimizations based on algebraic rules. /// May assume inputs are finite. /// /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] pub fn fsub_fast(a: T, b: T) -> T; /// Float multiplication that allows optimizations based on algebraic rules. /// May assume inputs are finite. /// /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] pub fn fmul_fast(a: T, b: T) -> T; /// Float division that allows optimizations based on algebraic rules. /// May assume inputs are finite. /// /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] pub fn fdiv_fast(a: T, b: T) -> T; /// Float remainder that allows optimizations based on algebraic rules. /// May assume inputs are finite. /// /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] pub fn frem_fast(a: T, b: T) -> T; /// Convert with LLVM’s fptoui/fptosi, which may return undef for values out of range /// () /// /// Stabilized as [`f32::to_int_unchecked`] and [`f64::to_int_unchecked`]. + #[rustc_nounwind] pub fn float_to_int_unchecked(value: Float) -> Int; /// Returns the number of bits set in an integer type `T` @@ -1677,6 +1862,7 @@ extern "rust-intrinsic" { /// [`u32::count_ones`] #[rustc_const_stable(feature = "const_ctpop", since = "1.40.0")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn ctpop(x: T) -> T; /// Returns the number of leading unset bits (zeroes) in an integer type `T`. @@ -1715,6 +1901,7 @@ extern "rust-intrinsic" { /// ``` #[rustc_const_stable(feature = "const_ctlz", since = "1.40.0")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn ctlz(x: T) -> T; /// Like `ctlz`, but extra-unsafe as it returns `undef` when @@ -1734,6 +1921,7 @@ extern "rust-intrinsic" { /// assert_eq!(num_leading, 3); /// ``` #[rustc_const_stable(feature = "constctlz", since = "1.50.0")] + #[rustc_nounwind] pub fn ctlz_nonzero(x: T) -> T; /// Returns the number of trailing unset bits (zeroes) in an integer type `T`. @@ -1772,6 +1960,7 @@ extern "rust-intrinsic" { /// ``` #[rustc_const_stable(feature = "const_cttz", since = "1.40.0")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn cttz(x: T) -> T; /// Like `cttz`, but extra-unsafe as it returns `undef` when @@ -1791,6 +1980,7 @@ extern "rust-intrinsic" { /// assert_eq!(num_trailing, 3); /// ``` #[rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0")] + #[rustc_nounwind] pub fn cttz_nonzero(x: T) -> T; /// Reverses the bytes in an integer type `T`. @@ -1805,6 +1995,7 @@ extern "rust-intrinsic" { /// [`u32::swap_bytes`] #[rustc_const_stable(feature = "const_bswap", since = "1.40.0")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn bswap(x: T) -> T; /// Reverses the bits in an integer type `T`. @@ -1819,6 +2010,7 @@ extern "rust-intrinsic" { /// [`u32::reverse_bits`] #[rustc_const_stable(feature = "const_bitreverse", since = "1.40.0")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn bitreverse(x: T) -> T; /// Performs checked integer addition. @@ -1833,6 +2025,7 @@ extern "rust-intrinsic" { /// [`u32::overflowing_add`] #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn add_with_overflow(x: T, y: T) -> (T, bool); /// Performs checked integer subtraction @@ -1847,6 +2040,7 @@ extern "rust-intrinsic" { /// [`u32::overflowing_sub`] #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn sub_with_overflow(x: T, y: T) -> (T, bool); /// Performs checked integer multiplication @@ -1861,6 +2055,7 @@ extern "rust-intrinsic" { /// [`u32::overflowing_mul`] #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn mul_with_overflow(x: T, y: T) -> (T, bool); /// Performs an exact division, resulting in undefined behavior where @@ -1868,6 +2063,7 @@ extern "rust-intrinsic" { /// /// This intrinsic does not have a stable counterpart. #[rustc_const_unstable(feature = "const_exact_div", issue = "none")] + #[rustc_nounwind] pub fn exact_div(x: T, y: T) -> T; /// Performs an unchecked division, resulting in undefined behavior @@ -1877,6 +2073,7 @@ extern "rust-intrinsic" { /// primitives via the `checked_div` method. For example, /// [`u32::checked_div`] #[rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0")] + #[rustc_nounwind] pub fn unchecked_div(x: T, y: T) -> T; /// Returns the remainder of an unchecked division, resulting in /// undefined behavior when `y == 0` or `x == T::MIN && y == -1` @@ -1885,6 +2082,7 @@ extern "rust-intrinsic" { /// primitives via the `checked_rem` method. For example, /// [`u32::checked_rem`] #[rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0")] + #[rustc_nounwind] pub fn unchecked_rem(x: T, y: T) -> T; /// Performs an unchecked left shift, resulting in undefined behavior when @@ -1894,6 +2092,7 @@ extern "rust-intrinsic" { /// primitives via the `checked_shl` method. For example, /// [`u32::checked_shl`] #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")] + #[rustc_nounwind] pub fn unchecked_shl(x: T, y: T) -> T; /// Performs an unchecked right shift, resulting in undefined behavior when /// `y < 0` or `y >= N`, where N is the width of T in bits. @@ -1902,6 +2101,7 @@ extern "rust-intrinsic" { /// primitives via the `checked_shr` method. For example, /// [`u32::checked_shr`] #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")] + #[rustc_nounwind] pub fn unchecked_shr(x: T, y: T) -> T; /// Returns the result of an unchecked addition, resulting in @@ -1909,6 +2109,7 @@ extern "rust-intrinsic" { /// /// This intrinsic does not have a stable counterpart. #[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")] + #[rustc_nounwind] pub fn unchecked_add(x: T, y: T) -> T; /// Returns the result of an unchecked subtraction, resulting in @@ -1916,6 +2117,7 @@ extern "rust-intrinsic" { /// /// This intrinsic does not have a stable counterpart. #[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")] + #[rustc_nounwind] pub fn unchecked_sub(x: T, y: T) -> T; /// Returns the result of an unchecked multiplication, resulting in @@ -1923,6 +2125,7 @@ extern "rust-intrinsic" { /// /// This intrinsic does not have a stable counterpart. #[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")] + #[rustc_nounwind] pub fn unchecked_mul(x: T, y: T) -> T; /// Performs rotate left. @@ -1937,6 +2140,7 @@ extern "rust-intrinsic" { /// [`u32::rotate_left`] #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn rotate_left(x: T, y: T) -> T; /// Performs rotate right. @@ -1951,6 +2155,7 @@ extern "rust-intrinsic" { /// [`u32::rotate_right`] #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn rotate_right(x: T, y: T) -> T; /// Returns (a + b) mod 2N, where N is the width of T in bits. @@ -1965,6 +2170,7 @@ extern "rust-intrinsic" { /// [`u32::wrapping_add`] #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn wrapping_add(a: T, b: T) -> T; /// Returns (a - b) mod 2N, where N is the width of T in bits. /// @@ -1978,6 +2184,7 @@ extern "rust-intrinsic" { /// [`u32::wrapping_sub`] #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn wrapping_sub(a: T, b: T) -> T; /// Returns (a * b) mod 2N, where N is the width of T in bits. /// @@ -1991,6 +2198,7 @@ extern "rust-intrinsic" { /// [`u32::wrapping_mul`] #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn wrapping_mul(a: T, b: T) -> T; /// Computes `a + b`, saturating at numeric bounds. @@ -2005,6 +2213,7 @@ extern "rust-intrinsic" { /// [`u32::saturating_add`] #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn saturating_add(a: T, b: T) -> T; /// Computes `a - b`, saturating at numeric bounds. /// @@ -2018,6 +2227,7 @@ extern "rust-intrinsic" { /// [`u32::saturating_sub`] #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn saturating_sub(a: T, b: T) -> T; /// This is an implementation detail of [`crate::ptr::read`] and should @@ -2028,6 +2238,7 @@ extern "rust-intrinsic" { /// trivially obeys runtime-MIR rules about derefs in operands. #[cfg(not(bootstrap))] #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] + #[rustc_nounwind] pub fn read_via_copy(p: *const T) -> T; /// Returns the value of the discriminant for the variant in 'v'; @@ -2041,6 +2252,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is [`core::mem::discriminant`]. #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn discriminant_value(v: &T) -> ::Discriminant; /// Returns the number of variants of the type `T` cast to a `usize`; @@ -2054,6 +2266,7 @@ extern "rust-intrinsic" { /// The to-be-stabilized version of this intrinsic is [`mem::variant_count`]. #[rustc_const_unstable(feature = "variant_count", issue = "73662")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn variant_count() -> usize; /// Rust's "try catch" construct which invokes the function pointer `try_fn` @@ -2063,18 +2276,22 @@ extern "rust-intrinsic" { /// takes the data pointer and a pointer to the target-specific exception /// object that was caught. For more information see the compiler's /// source as well as std's catch implementation. + #[rustc_nounwind] pub fn r#try(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32; /// Emits a `!nontemporal` store according to LLVM (see their docs). /// Probably will never become stable. + #[rustc_nounwind] pub fn nontemporal_store(ptr: *mut T, val: T); /// See documentation of `<*const T>::offset_from` for details. #[rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0")] + #[rustc_nounwind] pub fn ptr_offset_from(ptr: *const T, base: *const T) -> isize; /// See documentation of `<*const T>::sub_ptr` for details. #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] + #[rustc_nounwind] pub fn ptr_offset_from_unsigned(ptr: *const T, base: *const T) -> usize; /// See documentation of `<*const T>::guaranteed_eq` for details. @@ -2088,6 +2305,7 @@ extern "rust-intrinsic" { /// any safety invariants. #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn ptr_guaranteed_cmp(ptr: *const T, other: *const T) -> u8; /// Allocates a block of memory at compile time. @@ -2099,6 +2317,7 @@ extern "rust-intrinsic" { /// - At compile time, a compile error occurs if this constraint is violated. /// - At runtime, it is not checked. #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + #[rustc_nounwind] pub fn const_allocate(size: usize, align: usize) -> *mut u8; /// Deallocates a memory which allocated by `intrinsics::const_allocate` at compile time. @@ -2112,6 +2331,7 @@ extern "rust-intrinsic" { /// - If the `ptr` is created in an another const, this intrinsic doesn't deallocate it. /// - If the `ptr` is pointing to a local variable, this intrinsic doesn't deallocate it. #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + #[rustc_nounwind] pub fn const_deallocate(ptr: *mut u8, size: usize, align: usize); /// Determines whether the raw bytes of the two values are equal. @@ -2136,6 +2356,7 @@ extern "rust-intrinsic" { /// (The implementation is allowed to branch on the results of comparisons, /// which is UB if any of their inputs are `undef`.) #[rustc_const_unstable(feature = "const_intrinsic_raw_eq", issue = "none")] + #[rustc_nounwind] pub fn raw_eq(a: &T, b: &T) -> bool; /// See documentation of [`std::hint::black_box`] for details. @@ -2143,14 +2364,17 @@ extern "rust-intrinsic" { /// [`std::hint::black_box`]: crate::hint::black_box #[rustc_const_unstable(feature = "const_black_box", issue = "none")] #[rustc_safe_intrinsic] + #[rustc_nounwind] pub fn black_box(dummy: T) -> T; /// `ptr` must point to a vtable. /// The intrinsic will return the size stored in that vtable. + #[rustc_nounwind] pub fn vtable_size(ptr: *const ()) -> usize; /// `ptr` must point to a vtable. /// The intrinsic will return the alignment stored in that vtable. + #[rustc_nounwind] pub fn vtable_align(ptr: *const ()) -> usize; /// Selects which function to call depending on the context. @@ -2215,10 +2439,11 @@ extern "rust-intrinsic" { G: FnOnce, F: FnOnce; - #[cfg(not(bootstrap))] /// This method creates a pointer to any `Some` value. If the argument is /// `None`, an invalid within-bounds pointer (that is still acceptable for /// constructing an empty slice) is returned. + #[cfg(not(bootstrap))] + #[rustc_nounwind] pub fn option_payload_ptr(arg: *const Option) -> *const T; } @@ -2392,6 +2617,7 @@ pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) - pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_nounwind] pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); } @@ -2482,6 +2708,7 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_nounwind] fn copy(src: *const T, dst: *mut T, count: usize); } @@ -2554,6 +2781,7 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] + #[rustc_nounwind] fn write_bytes(dst: *mut T, val: u8, count: usize); } diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 9cdfd2c21cc9..818f1a919d0d 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1371,6 +1371,7 @@ pub const unsafe fn write(dst: *mut T, src: T) { // as `intrinsics::copy_nonoverlapping` is a wrapper function. extern "rust-intrinsic" { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] + #[rustc_nounwind] fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); } From 5c9b371a2f3ef7f08e213e236c53733e2e5981c7 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 12 Apr 2023 13:57:27 +0100 Subject: [PATCH 224/272] Bless tests --- tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff | 2 +- ...er_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff | 2 +- .../lower_intrinsics.option_payload.LowerIntrinsics.diff | 4 ++-- ..._intrinsics.read_via_copy_primitive.LowerIntrinsics.diff | 2 +- ...ntrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff | 2 +- tests/mir-opt/lower_intrinsics.rs | 3 ++- .../lower_intrinsics.with_overflow.LowerIntrinsics.diff | 6 +++--- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff index 935eccfc6f4f..e95c3f9bcc70 100644 --- a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff @@ -11,7 +11,7 @@ StorageLive(_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 - _1 = std::intrinsics::assume(const true) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:105:9: 105:32 +- // + span: $DIR/lower_intrinsics.rs:106:9: 106:32 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(bool) {std::intrinsics::assume}, val: Value() } + assume(const true); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 + goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 diff --git a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff index b0c32e4b21a7..a54e9a9320ee 100644 --- a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff @@ -49,7 +49,7 @@ StorageDead(_9); // scope 3 at $DIR/lower_intrinsics.rs:+4:90: +4:91 - _3 = copy_nonoverlapping::(move _4, move _8, const 0_usize) -> [return: bb1, unwind unreachable]; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:98:9: 98:28 +- // + span: $DIR/lower_intrinsics.rs:99:9: 99:28 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {copy_nonoverlapping::}, val: Value() } + copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize); // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 + goto -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 diff --git a/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff index 93863fca344a..cc5079af7f45 100644 --- a/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff @@ -24,7 +24,7 @@ _4 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:55: +2:56 - _3 = option_payload_ptr::(move _4) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:132:18: 132:54 +- // + span: $DIR/lower_intrinsics.rs:133:18: 133:54 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option) -> *const usize {option_payload_ptr::}, val: Value() } + _3 = &raw const (((*_4) as Some).0: usize); // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57 + goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57 @@ -37,7 +37,7 @@ _6 = &raw const (*_2); // scope 2 at $DIR/lower_intrinsics.rs:+3:55: +3:56 - _5 = option_payload_ptr::(move _6) -> [return: bb2, unwind unreachable]; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:133:18: 133:54 +- // + span: $DIR/lower_intrinsics.rs:134:18: 134:54 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option) -> *const String {option_payload_ptr::}, val: Value() } + _5 = &raw const (((*_6) as Some).0: std::string::String); // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57 + goto -> bb2; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57 diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff index f816678b4b3a..5805df48f544 100644 --- a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff @@ -13,7 +13,7 @@ _2 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47 - _0 = read_via_copy::(move _2) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:118:14: 118:45 +- // + span: $DIR/lower_intrinsics.rs:119:14: 119:45 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32) -> i32 {read_via_copy::}, val: Value() } + _0 = (*_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 + goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff index f34164189220..95b2ec49d807 100644 --- a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff @@ -13,7 +13,7 @@ _2 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47 - _0 = read_via_copy::(move _2) -> unwind unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:123:14: 123:45 +- // + span: $DIR/lower_intrinsics.rs:124:14: 124:45 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Never) -> Never {read_via_copy::}, val: Value() } + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 } diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs index ec215c9a6646..33fef930ad34 100644 --- a/tests/mir-opt/lower_intrinsics.rs +++ b/tests/mir-opt/lower_intrinsics.rs @@ -1,7 +1,7 @@ // unit-test: LowerIntrinsics // ignore-wasm32 compiled with panic=abort by default -#![feature(core_intrinsics, intrinsics)] +#![feature(core_intrinsics, intrinsics, rustc_attrs)] #![crate_type = "lib"] // EMIT_MIR lower_intrinsics.wrapping.LowerIntrinsics.diff @@ -87,6 +87,7 @@ pub fn discriminant(t: T) { extern "rust-intrinsic" { // Cannot use `std::intrinsics::copy_nonoverlapping` as that is a wrapper function + #[rustc_nounwind] fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); } diff --git a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff index fb12d3dfa6e9..9cf4fbb88f38 100644 --- a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff @@ -32,7 +32,7 @@ _5 = _2; // scope 0 at $DIR/lower_intrinsics.rs:+1:53: +1:54 - _3 = add_with_overflow::(move _4, move _5) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:111:14: 111:49 +- // + span: $DIR/lower_intrinsics.rs:112:14: 112:49 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {add_with_overflow::}, val: Value() } + _3 = CheckedAdd(move _4, move _5); // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55 @@ -48,7 +48,7 @@ _8 = _2; // scope 1 at $DIR/lower_intrinsics.rs:+2:53: +2:54 - _6 = sub_with_overflow::(move _7, move _8) -> [return: bb2, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:112:14: 112:49 +- // + span: $DIR/lower_intrinsics.rs:113:14: 113:49 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {sub_with_overflow::}, val: Value() } + _6 = CheckedSub(move _7, move _8); // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55 + goto -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55 @@ -64,7 +64,7 @@ _11 = _2; // scope 2 at $DIR/lower_intrinsics.rs:+3:53: +3:54 - _9 = mul_with_overflow::(move _10, move _11) -> [return: bb3, unwind unreachable]; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:113:14: 113:49 +- // + span: $DIR/lower_intrinsics.rs:114:14: 114:49 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {mul_with_overflow::}, val: Value() } + _9 = CheckedMul(move _10, move _11); // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55 + goto -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55 From 04f20d4ac8677b13c41e54fdde319c4e13b58330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lena=20Miliz=C3=A9?= Date: Wed, 12 Apr 2023 15:43:50 +0200 Subject: [PATCH 225/272] compiler: print the suggestion only for local macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And wrap the link in the diagnostic in angle brackets. Signed-off-by: Lena Milizé --- compiler/rustc_expand/src/mbe/diagnostics.rs | 7 +++++-- tests/ui/macros/nonterminal-matching.stderr | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 00bb7b0f2a24..35572292271c 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -67,8 +67,11 @@ pub(super) fn failed_to_match_macro<'cx>( || matches!(token.kind, TokenKind::Interpolated(_))) { err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens"); - err.note("see https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment for more information"); - err.help("try using `:tt` instead in the macro definition"); + err.note("see for more information"); + + if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) { + err.help("try using `:tt` instead in the macro definition"); + } } // Check whether there's a missing comma in this macro call, like `println!("{}" a);` diff --git a/tests/ui/macros/nonterminal-matching.stderr b/tests/ui/macros/nonterminal-matching.stderr index c295eddbe47e..c2b047022ed5 100644 --- a/tests/ui/macros/nonterminal-matching.stderr +++ b/tests/ui/macros/nonterminal-matching.stderr @@ -19,7 +19,7 @@ LL | macro n(a $nt_item b) { LL | complex_nonterminal!(enum E {}); | ------------------------------- in this macro invocation = note: captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens - = note: see https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment for more information + = note: see for more information = help: try using `:tt` instead in the macro definition = note: this error originates in the macro `complex_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info) From e0ed17441f544870c1fa046f10408e93ec178b7c Mon Sep 17 00:00:00 2001 From: clubby789 Date: Wed, 12 Apr 2023 16:27:06 +0100 Subject: [PATCH 226/272] tidy: Issue an error when ui test limits are too high --- src/tools/tidy/src/ui_tests.rs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 0f08f5d0b700..7b7ee62a2474 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -9,7 +9,7 @@ use std::path::{Path, PathBuf}; // FIXME: The following limits should be reduced eventually. const ENTRY_LIMIT: usize = 885; -const ROOT_ENTRY_LIMIT: usize = 881; +const ROOT_ENTRY_LIMIT: usize = 880; const ISSUES_ENTRY_LIMIT: usize = 1978; fn check_entries(tests_path: &Path, bad: &mut bool) { @@ -22,18 +22,19 @@ fn check_entries(tests_path: &Path, bad: &mut bool) { } } + let (mut max, mut max_root, mut max_issues) = (0usize, 0usize, 0usize); for (dir_path, count) in directories { // Use special values for these dirs. let is_root = tests_path.join("ui") == dir_path; let is_issues_dir = tests_path.join("ui/issues") == dir_path; - let limit = if is_root { - ROOT_ENTRY_LIMIT + let (limit, maxcnt) = if is_root { + (ROOT_ENTRY_LIMIT, &mut max_root) } else if is_issues_dir { - ISSUES_ENTRY_LIMIT + (ISSUES_ENTRY_LIMIT, &mut max_issues) } else { - ENTRY_LIMIT + (ENTRY_LIMIT, &mut max) }; - + *maxcnt = (*maxcnt).max(count); if count > limit { tidy_error!( bad, @@ -45,6 +46,21 @@ fn check_entries(tests_path: &Path, bad: &mut bool) { ); } } + if ENTRY_LIMIT > max { + tidy_error!(bad, "`ENTRY_LIMIT` is too high (is {ENTRY_LIMIT}, should be {max})"); + } + if ROOT_ENTRY_LIMIT > max_root { + tidy_error!( + bad, + "`ROOT_ENTRY_LIMIT` is too high (is {ROOT_ENTRY_LIMIT}, should be {max_root})" + ); + } + if ISSUES_ENTRY_LIMIT > max_issues { + tidy_error!( + bad, + "`ISSUES_ENTRY_LIMIT` is too high (is {ISSUES_ENTRY_LIMIT}, should be {max_issues})" + ); + } } pub fn check(path: &Path, bad: &mut bool) { From ad9a89eef2857a24ef049b9eee2d1db5bcbf1d11 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 11 Apr 2023 12:25:36 -0700 Subject: [PATCH 227/272] rustdoc: make settings radio and checks thicker, less contrast This is very dependent on subjectivity and what screen you use, but this change makes the radio buttons' outer circle less ugly. This is because I could see the pixels very clearly, thanks to the very thin line and high contrast. This change makes both less severe, giving your browser's antialiasing algorithm more to work with. Since it's thicker, lowering the contrast shouldn't impact visibility. --- src/librustdoc/html/static/css/settings.css | 3 +- src/librustdoc/html/static/css/themes/ayu.css | 1 + .../html/static/css/themes/dark.css | 1 + .../html/static/css/themes/light.css | 1 + tests/rustdoc-gui/settings.goml | 77 +++++++++++++++++-- 5 files changed, 75 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css index 920f45c4bbad..d13c783d2e4f 100644 --- a/src/librustdoc/html/static/css/settings.css +++ b/src/librustdoc/html/static/css/settings.css @@ -8,7 +8,7 @@ height: 1.2rem; width: 1.2rem; color: inherit; - border: 1px solid currentColor; + border: 2px solid var(--settings-input-border-color); outline: none; -webkit-appearance: none; cursor: pointer; @@ -52,6 +52,7 @@ } .setting-check input:checked { background-color: var(--settings-input-color); + border-width: 1px; } .setting-radio input:focus, .setting-check input:focus { box-shadow: 0 0 1px 1px var(--settings-input-color); diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index 90cf689ad337..7145baad2567 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -7,6 +7,7 @@ Original by Dempfi (https://github.com/dempfi/ayu) --main-background-color: #0f1419; --main-color: #c5c5c5; --settings-input-color: #ffb454; + --settings-input-border-color: #999; --settings-button-color: #fff; --settings-button-border-focus: #e0e0e0; --sidebar-background-color: #14191f; diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index e8cd06931392..3c1186a5649f 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -2,6 +2,7 @@ --main-background-color: #353535; --main-color: #ddd; --settings-input-color: #2196f3; + --settings-input-border-color: #999; --settings-button-color: #000; --settings-button-border-focus: #ffb900; --sidebar-background-color: #505050; diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 5e3f14e483fa..f8c287137dea 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -2,6 +2,7 @@ --main-background-color: white; --main-color: black; --settings-input-color: #2196f3; + --settings-input-border-color: #717171; --settings-button-color: #000; --settings-button-border-focus: #717171; --sidebar-background-color: #F5F5F5; diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index a84172885780..0c360792286f 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -56,11 +56,12 @@ move-cursor-to: "#settings-menu > a" assert-css: ( "#theme-dark", { - "border-color": "rgb(221, 221, 221)", + "border-color": "rgb(153, 153, 153)", "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset", + "border-width": "2px", }, ) -assert-css: ("#theme-light", {"border-color": "rgb(221, 221, 221)", "box-shadow": "none"}) +assert-css: ("#theme-light", {"border-color": "rgb(153, 153, 153)", "box-shadow": "none"}) // Let's start with the hover for radio buttons. move-cursor-to: "#theme-dark" assert-css: ( @@ -68,26 +69,36 @@ assert-css: ( { "border-color": "rgb(33, 150, 243)", "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset", + "border-width": "2px", }, ) move-cursor-to: "#theme-light" -assert-css: ("#theme-light", {"border-color": "rgb(33, 150, 243)", "box-shadow": "none"}) +assert-css: ( + "#theme-light", + { + "border-color": "rgb(33, 150, 243)", + "box-shadow": "none", + "border-width": "2px", + } +) move-cursor-to: "#theme-ayu" // Let's now check with the focus for radio buttons. focus: "#theme-dark" assert-css: ( "#theme-dark", { - "border-color": "rgb(221, 221, 221)", + "border-color": "rgb(153, 153, 153)", "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset, rgb(33, 150, 243) 0px 0px 2px 2px", + "border-width": "2px", }, ) focus: "#theme-light" assert-css: ( "#theme-light", { - "border-color": "rgb(221, 221, 221)", + "border-color": "rgb(153, 153, 153)", "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px", + "border-width": "2px", }, ) // Now we check we both focus and hover for radio buttons. @@ -98,6 +109,7 @@ assert-css: ( { "border-color": "rgb(33, 150, 243)", "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset, rgb(33, 150, 243) 0px 0px 2px 2px", + "border-width": "2px", }, ) move-cursor-to: "#theme-light" @@ -107,6 +119,7 @@ assert-css: ( { "border-color": "rgb(33, 150, 243)", "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px", + "border-width": "2px", }, ) // Now we check the setting-radio-name is on a different line than the label. @@ -142,7 +155,18 @@ assert-css: ( "#auto-hide-large-items", { "background-color": "rgb(33, 150, 243)", - "border-color": "rgb(221, 221, 221)", + "border-color": "rgb(153, 153, 153)", + // 1px border when checked + "border-width": "1px", + }, +) +assert-css: ( + "#auto-hide-method-docs", + { + "background-color": "rgba(0, 0, 0, 0)", + "border-color": "rgb(153, 153, 153)", + // 2px border when unchecked + "border-width": "2px", }, ) // Let's start with the hover for toggles. @@ -152,6 +176,18 @@ assert-css: ( { "background-color": "rgb(33, 150, 243)", "border-color": "rgb(33, 150, 243)", + // 1px border when checked + "border-width": "1px", + }, +) +move-cursor-to: "#auto-hide-method-docs" +assert-css: ( + "#auto-hide-method-docs", + { + "background-color": "rgba(0, 0, 0, 0)", + "border-color": "rgb(33, 150, 243)", + // 2px border when unchecked + "border-width": "2px", }, ) move-cursor-to: "#settings-menu > a" @@ -161,8 +197,21 @@ assert-css: ( "#auto-hide-large-items", { "background-color": "rgb(33, 150, 243)", - "border-color": "rgb(221, 221, 221)", + "border-color": "rgb(153, 153, 153)", "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px", + // 1px border when checked + "border-width": "1px", + }, +) +focus: "#auto-hide-method-docs" +assert-css: ( + "#auto-hide-method-docs", + { + "background-color": "rgba(0, 0, 0, 0)", + "border-color": "rgb(153, 153, 153)", + "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px", + // 2px border when unchecked + "border-width": "2px", }, ) // Now we check we both focus and hover for toggles. @@ -174,6 +223,20 @@ assert-css: ( "background-color": "rgb(33, 150, 243)", "border-color": "rgb(33, 150, 243)", "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px", + // 1px border when checked + "border-width": "1px", + }, +) +move-cursor-to: "#auto-hide-method-docs" +focus: "#auto-hide-method-docs" +assert-css: ( + "#auto-hide-method-docs", + { + "background-color": "rgba(0, 0, 0, 0)", + "border-color": "rgb(33, 150, 243)", + "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px", + // 2px border when unchecked + "border-width": "2px", }, ) From f263f88beacce82ef7098dadd25e44eb349aa3c2 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 12 Apr 2023 13:32:15 +0000 Subject: [PATCH 228/272] Split out a separate feature gate for impl trait in associated types --- compiler/rustc_ast_passes/src/feature_gate.rs | 30 ++++-- compiler/rustc_feature/src/active.rs | 2 + compiler/rustc_span/src/symbol.rs | 1 + src/librustdoc/lib.rs | 1 + tests/rustdoc/auxiliary/issue-73061.rs | 2 +- tests/ui/associated-types/issue-63591.rs | 10 +- .../in-trait/async-associated-types2.rs | 6 +- .../feature-gate-impl_trait_in_assoc_type.rs | 18 ++++ ...ature-gate-impl_trait_in_assoc_type.stderr | 30 ++++++ tests/ui/generator/issue-87142.rs | 2 +- .../generic-associated-types/issue-86218-2.rs | 6 +- .../generic-associated-types/issue-86218.rs | 6 +- .../generic-associated-types/issue-87258_a.rs | 2 +- .../generic-associated-types/issue-88595.rs | 3 +- .../issue-88595.stderr | 4 +- .../generic-associated-types/issue-89008.rs | 2 +- .../generic-associated-types/issue-90014.rs | 6 +- .../issue-90014.stderr | 6 +- ...ssociated-impl-trait-type-generic-trait.rs | 2 +- .../associated-impl-trait-type-trivial.rs | 2 +- .../impl-trait/associated-impl-trait-type.rs | 2 +- tests/ui/impl-trait/issue-55872-1.rs | 2 +- tests/ui/impl-trait/issue-55872-2.rs | 2 +- tests/ui/impl-trait/issue-55872-2.stderr | 8 -- tests/ui/impl-trait/issue-55872-3.rs | 2 +- tests/ui/impl-trait/issue-55872.rs | 2 +- tests/ui/impl-trait/issues/issue-82139.rs | 2 +- tests/ui/impl-trait/issues/issue-83919.rs | 12 +-- tests/ui/impl-trait/issues/issue-86719.rs | 5 +- tests/ui/impl-trait/issues/issue-86719.stderr | 3 +- tests/ui/impl-trait/issues/issue-87340.rs | 4 +- .../ui/impl-trait/type-alias-generic-param.rs | 2 +- tests/ui/impl-trait/where-allowed.rs | 4 +- tests/ui/impl-trait/where-allowed.stderr | 98 +++++++++---------- .../ui/lint/inline-trait-and-foreign-items.rs | 2 +- tests/ui/lint/no-coverage.rs | 2 +- tests/ui/nll/issue-78561.rs | 2 +- .../ui/privacy/private-in-public-assoc-ty.rs | 2 +- ...private-in-public-type-alias-impl-trait.rs | 2 +- .../type-alias-impl-trait/assoc-type-const.rs | 2 +- .../assoc-type-lifetime-unconstrained.rs | 2 +- .../assoc-type-lifetime.rs | 2 +- .../associated-type-impl-trait-lifetime.rs | 2 +- .../auxiliary/collect_hidden_types.rs | 2 +- .../auxiliary/cross_crate_ice2.rs | 2 +- .../impl-with-unconstrained-param.rs | 2 +- .../imply_bounds_from_bounds.rs | 2 +- .../imply_bounds_from_bounds_param.rs | 6 +- .../imply_bounds_from_bounds_param.stderr | 2 +- .../incoherent-assoc-imp-trait.rs | 2 +- tests/ui/type-alias-impl-trait/issue-53598.rs | 2 +- .../issue-57188-associate-impl-capture.rs | 2 +- .../issue-57611-trait-alias.rs | 2 +- tests/ui/type-alias-impl-trait/issue-57700.rs | 2 +- .../issue-57807-associated-type.rs | 2 +- tests/ui/type-alias-impl-trait/issue-58887.rs | 2 +- tests/ui/type-alias-impl-trait/issue-60371.rs | 2 +- .../type-alias-impl-trait/issue-60371.stderr | 4 +- .../issue-60564-working.rs | 2 +- ...ue-62000-associate-impl-trait-lifetimes.rs | 2 +- .../ui/type-alias-impl-trait/issue-74761-2.rs | 2 +- tests/ui/type-alias-impl-trait/issue-74761.rs | 2 +- tests/ui/type-alias-impl-trait/issue-78450.rs | 2 +- tests/ui/type-alias-impl-trait/issue-89952.rs | 2 +- .../ui/type-alias-impl-trait/issue-90400-1.rs | 2 +- .../ui/type-alias-impl-trait/issue-90400-2.rs | 2 +- tests/ui/type-alias-impl-trait/issue-94429.rs | 4 +- ...alias-impl-trait-unconstrained-lifetime.rs | 2 +- 68 files changed, 217 insertions(+), 148 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.rs create mode 100644 tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr delete mode 100644 tests/ui/impl-trait/issue-55872-2.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 007d64f681f7..9cbc4b2e2dc5 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -121,24 +121,34 @@ impl<'a> PostExpansionVisitor<'a> { } /// Feature gate `impl Trait` inside `type Alias = $type_expr;`. - fn check_impl_trait(&self, ty: &ast::Ty) { + fn check_impl_trait(&self, ty: &ast::Ty, in_associated_ty: bool) { struct ImplTraitVisitor<'a> { vis: &'a PostExpansionVisitor<'a>, + in_associated_ty: bool, } impl Visitor<'_> for ImplTraitVisitor<'_> { fn visit_ty(&mut self, ty: &ast::Ty) { if let ast::TyKind::ImplTrait(..) = ty.kind { - gate_feature_post!( - &self.vis, - type_alias_impl_trait, - ty.span, - "`impl Trait` in type aliases is unstable" - ); + if self.in_associated_ty { + gate_feature_post!( + &self.vis, + impl_trait_in_assoc_type, + ty.span, + "`impl Trait` in associated types is unstable" + ); + } else { + gate_feature_post!( + &self.vis, + type_alias_impl_trait, + ty.span, + "`impl Trait` in type aliases is unstable" + ); + } } visit::walk_ty(self, ty); } } - ImplTraitVisitor { vis: self }.visit_ty(ty); + ImplTraitVisitor { vis: self, in_associated_ty }.visit_ty(ty); } fn check_late_bound_lifetime_defs(&self, params: &[ast::GenericParam]) { @@ -294,7 +304,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } ast::ItemKind::TyAlias(box ast::TyAlias { ty: Some(ty), .. }) => { - self.check_impl_trait(&ty) + self.check_impl_trait(&ty, false) } _ => {} @@ -517,7 +527,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ); } if let Some(ty) = ty { - self.check_impl_trait(ty); + self.check_impl_trait(ty, true); } false } diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 426c6727adca..eea185c12dd2 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -416,6 +416,8 @@ declare_features! ( (active, half_open_range_patterns_in_slices, "1.66.0", Some(67264), None), /// Allows `if let` guard in match arms. (active, if_let_guard, "1.47.0", Some(51114), None), + /// Allows `impl Trait` to be used inside associated types (RFC 2515). + (active, impl_trait_in_assoc_type, "CURRENT_RUSTC_VERSION", Some(63063), None), /// Allows `impl Trait` as output type in `Fn` traits in return position of functions. (active, impl_trait_in_fn_trait_return, "1.64.0", Some(99697), None), /// Allows referencing `Self` and projections in impl-trait. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7affad9aa017..236f85a8e08b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -800,6 +800,7 @@ symbols! { ignore, impl_header_lifetime_elision, impl_lint_pass, + impl_trait_in_assoc_type, impl_trait_in_bindings, impl_trait_in_fn_trait_return, impl_trait_projections, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 79f53ee57cc9..ed86deb26d0e 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -15,6 +15,7 @@ #![feature(type_ascription)] #![feature(iter_intersperse)] #![feature(type_alias_impl_trait)] +#![cfg_attr(not(bootstrap), feature(impl_trait_in_assoc_type))] #![recursion_limit = "256"] #![warn(rustc::internal)] #![allow(clippy::collapsible_if, clippy::collapsible_else_if)] diff --git a/tests/rustdoc/auxiliary/issue-73061.rs b/tests/rustdoc/auxiliary/issue-73061.rs index e05a3bc6d918..01e9a984d440 100644 --- a/tests/rustdoc/auxiliary/issue-73061.rs +++ b/tests/rustdoc/auxiliary/issue-73061.rs @@ -1,6 +1,6 @@ //edition:2018 -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] pub trait Foo { type X: std::future::Future; diff --git a/tests/ui/associated-types/issue-63591.rs b/tests/ui/associated-types/issue-63591.rs index 4d2e39f4da60..d07c12349989 100644 --- a/tests/ui/associated-types/issue-63591.rs +++ b/tests/ui/associated-types/issue-63591.rs @@ -1,11 +1,13 @@ // check-pass #![feature(associated_type_bounds)] -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] fn main() {} -trait Bar { type Assoc; } +trait Bar { + type Assoc; +} trait Thing { type Out; @@ -13,7 +15,9 @@ trait Thing { } struct AssocIsCopy; -impl Bar for AssocIsCopy { type Assoc = u8; } +impl Bar for AssocIsCopy { + type Assoc = u8; +} impl Thing for AssocIsCopy { type Out = impl Bar; diff --git a/tests/ui/async-await/in-trait/async-associated-types2.rs b/tests/ui/async-await/in-trait/async-associated-types2.rs index cdecb02bfad1..b889f616a031 100644 --- a/tests/ui/async-await/in-trait/async-associated-types2.rs +++ b/tests/ui/async-await/in-trait/async-associated-types2.rs @@ -4,7 +4,7 @@ // revisions: current next #![feature(async_fn_in_trait)] -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] #![allow(incomplete_features)] use std::future::Future; @@ -23,9 +23,7 @@ impl MyTrait for i32 { Self: 'a; fn foo<'a>(&'a self) -> Self::Fut<'a> { - async { - *self - } + async { *self } } } diff --git a/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.rs b/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.rs new file mode 100644 index 000000000000..de0487cdb208 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.rs @@ -0,0 +1,18 @@ +trait Foo { + type Bar; +} + +impl Foo for () { + type Bar = impl std::fmt::Debug; + //~^ ERROR: `impl Trait` in associated types is unstable +} + +struct Mop; + +impl Mop { + type Bop = impl std::fmt::Debug; + //~^ ERROR: `impl Trait` in associated types is unstable + //~| ERROR: inherent associated types are unstable +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr b/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr new file mode 100644 index 000000000000..9a1ded968225 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr @@ -0,0 +1,30 @@ +error[E0658]: `impl Trait` in associated types is unstable + --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:6:16 + | +LL | type Bar = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #63063 for more information + = help: add `#![feature(impl_trait_in_assoc_type)]` to the crate attributes to enable + +error[E0658]: `impl Trait` in associated types is unstable + --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:13:16 + | +LL | type Bop = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #63063 for more information + = help: add `#![feature(impl_trait_in_assoc_type)]` to the crate attributes to enable + +error[E0658]: inherent associated types are unstable + --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:13:5 + | +LL | type Bop = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #8995 for more information + = help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/generator/issue-87142.rs b/tests/ui/generator/issue-87142.rs index fc10d04d46cf..7f670919ed60 100644 --- a/tests/ui/generator/issue-87142.rs +++ b/tests/ui/generator/issue-87142.rs @@ -4,7 +4,7 @@ // Regression test for #87142 // This test needs the above flags and the "lib" crate type. -#![feature(type_alias_impl_trait, generator_trait, generators)] +#![feature(impl_trait_in_assoc_type, generator_trait, generators)] #![crate_type = "lib"] use std::ops::Generator; diff --git a/tests/ui/generic-associated-types/issue-86218-2.rs b/tests/ui/generic-associated-types/issue-86218-2.rs index 63c839ea8712..8a5e4a0f3cc3 100644 --- a/tests/ui/generic-associated-types/issue-86218-2.rs +++ b/tests/ui/generic-associated-types/issue-86218-2.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] pub trait Stream { type Item; @@ -17,7 +17,9 @@ trait Yay { impl Yay for () { type InnerStream<'s> = impl Stream + 's; - fn foo<'s>() -> Self::InnerStream<'s> { () } + fn foo<'s>() -> Self::InnerStream<'s> { + () + } } fn main() {} diff --git a/tests/ui/generic-associated-types/issue-86218.rs b/tests/ui/generic-associated-types/issue-86218.rs index b2c3071f06b1..61cfdd35a892 100644 --- a/tests/ui/generic-associated-types/issue-86218.rs +++ b/tests/ui/generic-associated-types/issue-86218.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] pub trait Stream { type Item; @@ -18,7 +18,9 @@ trait Yay { impl<'a> Yay<&'a ()> for () { type InnerStream<'s> = impl Stream + 's; //^ ERROR does not fulfill the required lifetime - fn foo<'s>() -> Self::InnerStream<'s> { () } + fn foo<'s>() -> Self::InnerStream<'s> { + () + } } fn main() {} diff --git a/tests/ui/generic-associated-types/issue-87258_a.rs b/tests/ui/generic-associated-types/issue-87258_a.rs index 9ab683d3dc9e..6f737b21f53c 100644 --- a/tests/ui/generic-associated-types/issue-87258_a.rs +++ b/tests/ui/generic-associated-types/issue-87258_a.rs @@ -1,4 +1,4 @@ -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] // See https://github.com/rust-lang/rust/issues/87258#issuecomment-883293367 diff --git a/tests/ui/generic-associated-types/issue-88595.rs b/tests/ui/generic-associated-types/issue-88595.rs index 24641ee1f781..5a40a6129723 100644 --- a/tests/ui/generic-associated-types/issue-88595.rs +++ b/tests/ui/generic-associated-types/issue-88595.rs @@ -1,7 +1,8 @@ -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] fn main() {} +#[rustfmt::skip] trait A<'a> { type B<'b>: Clone // FIXME(generic_associated_types): Remove one of the below bounds diff --git a/tests/ui/generic-associated-types/issue-88595.stderr b/tests/ui/generic-associated-types/issue-88595.stderr index bcefc8066851..79d3479af8c8 100644 --- a/tests/ui/generic-associated-types/issue-88595.stderr +++ b/tests/ui/generic-associated-types/issue-88595.stderr @@ -1,11 +1,11 @@ error: non-defining opaque type use in defining scope - --> $DIR/issue-88595.rs:20:35 + --> $DIR/issue-88595.rs:21:35 | LL | fn a(&'a self) -> Self::B<'a> {} | ^^ | note: lifetime used multiple times - --> $DIR/issue-88595.rs:17:6 + --> $DIR/issue-88595.rs:18:6 | LL | impl<'a> A<'a> for C { | ^^ diff --git a/tests/ui/generic-associated-types/issue-89008.rs b/tests/ui/generic-associated-types/issue-89008.rs index 669dbafb5d5d..94b07e674e82 100644 --- a/tests/ui/generic-associated-types/issue-89008.rs +++ b/tests/ui/generic-associated-types/issue-89008.rs @@ -1,7 +1,7 @@ // check-pass // edition:2021 -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] use std::future::Future; use std::marker::PhantomData; diff --git a/tests/ui/generic-associated-types/issue-90014.rs b/tests/ui/generic-associated-types/issue-90014.rs index 55db95a6d819..c4d762796e2d 100644 --- a/tests/ui/generic-associated-types/issue-90014.rs +++ b/tests/ui/generic-associated-types/issue-90014.rs @@ -1,11 +1,13 @@ // edition:2018 -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] use std::future::Future; trait MakeFut { - type Fut<'a> where Self: 'a; + type Fut<'a> + where + Self: 'a; fn make_fut<'a>(&'a self) -> Self::Fut<'a>; } diff --git a/tests/ui/generic-associated-types/issue-90014.stderr b/tests/ui/generic-associated-types/issue-90014.stderr index b4b1bc7da7f4..0d49398cac94 100644 --- a/tests/ui/generic-associated-types/issue-90014.stderr +++ b/tests/ui/generic-associated-types/issue-90014.stderr @@ -1,14 +1,14 @@ error[E0477]: the type `&mut ()` does not fulfill the required lifetime - --> $DIR/issue-90014.rs:13:20 + --> $DIR/issue-90014.rs:15:20 | -LL | type Fut<'a> where Self: 'a; +LL | type Fut<'a> | ------------ definition of `Fut` from trait ... LL | type Fut<'a> = impl Future; | ^^^^^^^^^^^^^^^^^^^^^^^^ | note: type must outlive the lifetime `'a` as defined here - --> $DIR/issue-90014.rs:13:14 + --> $DIR/issue-90014.rs:15:14 | LL | type Fut<'a> = impl Future; | ^^ diff --git a/tests/ui/impl-trait/associated-impl-trait-type-generic-trait.rs b/tests/ui/impl-trait/associated-impl-trait-type-generic-trait.rs index 6c7c46b0e3db..0908a0bf39df 100644 --- a/tests/ui/impl-trait/associated-impl-trait-type-generic-trait.rs +++ b/tests/ui/impl-trait/associated-impl-trait-type-generic-trait.rs @@ -1,4 +1,4 @@ -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] // build-pass (FIXME(62277): could be check-pass?) trait Bar {} diff --git a/tests/ui/impl-trait/associated-impl-trait-type-trivial.rs b/tests/ui/impl-trait/associated-impl-trait-type-trivial.rs index cdda341cad87..b5ea90bb0c7c 100644 --- a/tests/ui/impl-trait/associated-impl-trait-type-trivial.rs +++ b/tests/ui/impl-trait/associated-impl-trait-type-trivial.rs @@ -1,4 +1,4 @@ -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] // build-pass (FIXME(62277): could be check-pass?) trait Bar {} diff --git a/tests/ui/impl-trait/associated-impl-trait-type.rs b/tests/ui/impl-trait/associated-impl-trait-type.rs index d0661d66f4b4..f5981261c383 100644 --- a/tests/ui/impl-trait/associated-impl-trait-type.rs +++ b/tests/ui/impl-trait/associated-impl-trait-type.rs @@ -1,4 +1,4 @@ -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] // build-pass (FIXME(62277): could be check-pass?) trait Bar {} diff --git a/tests/ui/impl-trait/issue-55872-1.rs b/tests/ui/impl-trait/issue-55872-1.rs index 22ff7ffa23cb..f36a310ddf31 100644 --- a/tests/ui/impl-trait/issue-55872-1.rs +++ b/tests/ui/impl-trait/issue-55872-1.rs @@ -1,4 +1,4 @@ -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] pub trait Bar { type E: Copy; diff --git a/tests/ui/impl-trait/issue-55872-2.rs b/tests/ui/impl-trait/issue-55872-2.rs index cbc7b5d62e13..7a5cb3b3dfcb 100644 --- a/tests/ui/impl-trait/issue-55872-2.rs +++ b/tests/ui/impl-trait/issue-55872-2.rs @@ -3,7 +3,7 @@ // [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // edition:2018 -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] pub trait Bar { type E: Send; diff --git a/tests/ui/impl-trait/issue-55872-2.stderr b/tests/ui/impl-trait/issue-55872-2.stderr deleted file mode 100644 index 477c964bd40f..000000000000 --- a/tests/ui/impl-trait/issue-55872-2.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/issue-55872-2.rs:17:9 - | -LL | async {} - | ^^^^^^^^ - -error: aborting due to previous error - diff --git a/tests/ui/impl-trait/issue-55872-3.rs b/tests/ui/impl-trait/issue-55872-3.rs index 91811df93cd4..d031271ac080 100644 --- a/tests/ui/impl-trait/issue-55872-3.rs +++ b/tests/ui/impl-trait/issue-55872-3.rs @@ -1,7 +1,7 @@ // edition:2018 // ignore-compare-mode-chalk -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] pub trait Bar { type E: Copy; diff --git a/tests/ui/impl-trait/issue-55872.rs b/tests/ui/impl-trait/issue-55872.rs index c4e6f6436085..10850f0a9335 100644 --- a/tests/ui/impl-trait/issue-55872.rs +++ b/tests/ui/impl-trait/issue-55872.rs @@ -1,4 +1,4 @@ -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] pub trait Bar { type E: Copy; diff --git a/tests/ui/impl-trait/issues/issue-82139.rs b/tests/ui/impl-trait/issues/issue-82139.rs index cc9167b340ad..3f0b0f1a8dee 100644 --- a/tests/ui/impl-trait/issues/issue-82139.rs +++ b/tests/ui/impl-trait/issues/issue-82139.rs @@ -1,4 +1,4 @@ -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait Trait { type Associated; diff --git a/tests/ui/impl-trait/issues/issue-83919.rs b/tests/ui/impl-trait/issues/issue-83919.rs index e76443a65dbf..4e699e7f3026 100644 --- a/tests/ui/impl-trait/issues/issue-83919.rs +++ b/tests/ui/impl-trait/issues/issue-83919.rs @@ -1,4 +1,4 @@ -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] // edition:2021 @@ -6,8 +6,8 @@ use std::future::Future; trait Foo { type T; - type Fut2: Future; // ICE got triggered with traits other than Future here - type Fut: Future; + type Fut2: Future; // ICE got triggered with traits other than Future here + type Fut: Future; fn get_fut(&self) -> Self::Fut; } @@ -15,11 +15,11 @@ struct Implementor; impl Foo for Implementor { type T = u64; - type Fut2 = impl Future; - type Fut = impl Future; + type Fut2 = impl Future; + type Fut = impl Future; fn get_fut(&self) -> Self::Fut { - //~^ ERROR `{integer}` is not a future + //~^ ERROR `{integer}` is not a future async move { 42 // 42 does not impl Future and rustc does actually point out the error, diff --git a/tests/ui/impl-trait/issues/issue-86719.rs b/tests/ui/impl-trait/issues/issue-86719.rs index f4b0b3f33fcd..7abab5bfb75d 100644 --- a/tests/ui/impl-trait/issues/issue-86719.rs +++ b/tests/ui/impl-trait/issues/issue-86719.rs @@ -1,11 +1,12 @@ -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait Bar { type E; } impl Bar for S { type E = impl ; //~ ERROR at least one trait must be specified - fn foo() -> Self::E { //~ ERROR `foo` is not a member + fn foo() -> Self::E { + //~^ ERROR `foo` is not a member |_| true //~ ERROR type annotations needed } } diff --git a/tests/ui/impl-trait/issues/issue-86719.stderr b/tests/ui/impl-trait/issues/issue-86719.stderr index 7592418fdfd6..15893df5f945 100644 --- a/tests/ui/impl-trait/issues/issue-86719.stderr +++ b/tests/ui/impl-trait/issues/issue-86719.stderr @@ -8,12 +8,13 @@ error[E0407]: method `foo` is not a member of trait `Bar` --> $DIR/issue-86719.rs:8:5 | LL | / fn foo() -> Self::E { +LL | | LL | | |_| true LL | | } | |_____^ not a member of trait `Bar` error[E0282]: type annotations needed - --> $DIR/issue-86719.rs:9:10 + --> $DIR/issue-86719.rs:10:10 | LL | |_| true | ^ diff --git a/tests/ui/impl-trait/issues/issue-87340.rs b/tests/ui/impl-trait/issues/issue-87340.rs index f0f6d2bb61c7..705a4addcb70 100644 --- a/tests/ui/impl-trait/issues/issue-87340.rs +++ b/tests/ui/impl-trait/issues/issue-87340.rs @@ -1,4 +1,4 @@ -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait X { type I; @@ -6,7 +6,7 @@ trait X { } impl X for () { -//~^ ERROR `T` is not constrained by the impl trait, self type, or predicates + //~^ ERROR `T` is not constrained by the impl trait, self type, or predicates type I = impl Sized; fn f() -> Self::I {} } diff --git a/tests/ui/impl-trait/type-alias-generic-param.rs b/tests/ui/impl-trait/type-alias-generic-param.rs index 3499b2859267..1211625dac9c 100644 --- a/tests/ui/impl-trait/type-alias-generic-param.rs +++ b/tests/ui/impl-trait/type-alias-generic-param.rs @@ -3,7 +3,7 @@ // types in 'item' position when generic parameters are involved // // run-pass -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait Meow { type MeowType; diff --git a/tests/ui/impl-trait/where-allowed.rs b/tests/ui/impl-trait/where-allowed.rs index ff63b04c2680..509d2716649e 100644 --- a/tests/ui/impl-trait/where-allowed.rs +++ b/tests/ui/impl-trait/where-allowed.rs @@ -1,6 +1,8 @@ //! A simple test for testing many permutations of allowedness of //! impl Trait #![feature(impl_trait_in_fn_trait_return)] +#![feature(custom_inner_attributes)] +#![rustfmt::skip] use std::fmt::Debug; // Allowed @@ -116,7 +118,7 @@ trait DummyTrait { } impl DummyTrait for () { type Out = impl Debug; - //~^ ERROR `impl Trait` in type aliases is unstable + //~^ ERROR `impl Trait` in associated types is unstable fn in_trait_impl_parameter(_: impl Debug) { } // Allowed diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr index 1cae3f77cc56..3e2934379755 100644 --- a/tests/ui/impl-trait/where-allowed.stderr +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -1,5 +1,5 @@ error[E0666]: nested `impl Trait` is not allowed - --> $DIR/where-allowed.rs:47:51 + --> $DIR/where-allowed.rs:49:51 | LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } | --------^^^^^^^^^^- @@ -8,7 +8,7 @@ LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed - --> $DIR/where-allowed.rs:56:57 + --> $DIR/where-allowed.rs:58:57 | LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } | --------^^^^^^^^^^- @@ -16,17 +16,17 @@ LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic | | nested `impl Trait` here | outer `impl Trait` -error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:118:16 +error[E0658]: `impl Trait` in associated types is unstable + --> $DIR/where-allowed.rs:120:16 | LL | type Out = impl Debug; | ^^^^^^^^^^ | = note: see issue #63063 for more information - = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + = help: add `#![feature(impl_trait_in_assoc_type)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:153:23 + --> $DIR/where-allowed.rs:155:23 | LL | type InTypeAlias = impl Debug; | ^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | type InTypeAlias = impl Debug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:156:39 + --> $DIR/where-allowed.rs:158:39 | LL | type InReturnInTypeAlias = fn() -> impl Debug; | ^^^^^^^^^^ @@ -44,109 +44,109 @@ LL | type InReturnInTypeAlias = fn() -> impl Debug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer params - --> $DIR/where-allowed.rs:16:40 + --> $DIR/where-allowed.rs:18:40 | LL | fn in_fn_parameter_in_parameters(_: fn(impl Debug)) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return types - --> $DIR/where-allowed.rs:20:42 + --> $DIR/where-allowed.rs:22:42 | LL | fn in_fn_return_in_parameters(_: fn() -> impl Debug) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer params - --> $DIR/where-allowed.rs:24:38 + --> $DIR/where-allowed.rs:26:38 | LL | fn in_fn_parameter_in_return() -> fn(impl Debug) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return types - --> $DIR/where-allowed.rs:28:40 + --> $DIR/where-allowed.rs:30:40 | LL | fn in_fn_return_in_return() -> fn() -> impl Debug { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait params - --> $DIR/where-allowed.rs:32:49 + --> $DIR/where-allowed.rs:34:49 | LL | fn in_dyn_Fn_parameter_in_parameters(_: &dyn Fn(impl Debug)) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return types - --> $DIR/where-allowed.rs:36:51 + --> $DIR/where-allowed.rs:38:51 | LL | fn in_dyn_Fn_return_in_parameters(_: &dyn Fn() -> impl Debug) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait params - --> $DIR/where-allowed.rs:40:55 + --> $DIR/where-allowed.rs:42:55 | LL | fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait params - --> $DIR/where-allowed.rs:47:51 + --> $DIR/where-allowed.rs:49:51 | LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return types - --> $DIR/where-allowed.rs:52:53 + --> $DIR/where-allowed.rs:54:53 | LL | fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait params - --> $DIR/where-allowed.rs:56:57 + --> $DIR/where-allowed.rs:58:57 | LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait params - --> $DIR/where-allowed.rs:64:38 + --> $DIR/where-allowed.rs:66:38 | LL | fn in_Fn_parameter_in_generics (_: F) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return types - --> $DIR/where-allowed.rs:68:40 + --> $DIR/where-allowed.rs:70:40 | LL | fn in_Fn_return_in_generics impl Debug> (_: F) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in field types - --> $DIR/where-allowed.rs:81:32 + --> $DIR/where-allowed.rs:83:32 | LL | struct InBraceStructField { x: impl Debug } | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in field types - --> $DIR/where-allowed.rs:85:41 + --> $DIR/where-allowed.rs:87:41 | LL | struct InAdtInBraceStructField { x: Vec } | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in field types - --> $DIR/where-allowed.rs:89:27 + --> $DIR/where-allowed.rs:91:27 | LL | struct InTupleStructField(impl Debug); | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in field types - --> $DIR/where-allowed.rs:94:25 + --> $DIR/where-allowed.rs:96:25 | LL | InBraceVariant { x: impl Debug }, | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in field types - --> $DIR/where-allowed.rs:96:20 + --> $DIR/where-allowed.rs:98:20 | LL | InTupleVariant(impl Debug), | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait method return types - --> $DIR/where-allowed.rs:107:23 + --> $DIR/where-allowed.rs:109:23 | LL | fn in_return() -> impl Debug; | ^^^^^^^^^^ @@ -155,7 +155,7 @@ LL | fn in_return() -> impl Debug; = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `impl` method return types - --> $DIR/where-allowed.rs:124:34 + --> $DIR/where-allowed.rs:126:34 | LL | fn in_trait_impl_return() -> impl Debug { () } | ^^^^^^^^^^ @@ -164,127 +164,127 @@ LL | fn in_trait_impl_return() -> impl Debug { () } = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `extern fn` params - --> $DIR/where-allowed.rs:137:33 + --> $DIR/where-allowed.rs:139:33 | LL | fn in_foreign_parameters(_: impl Debug); | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `extern fn` return types - --> $DIR/where-allowed.rs:140:31 + --> $DIR/where-allowed.rs:142:31 | LL | fn in_foreign_return() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return types - --> $DIR/where-allowed.rs:156:39 + --> $DIR/where-allowed.rs:158:39 | LL | type InReturnInTypeAlias = fn() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in traits - --> $DIR/where-allowed.rs:161:16 + --> $DIR/where-allowed.rs:163:16 | LL | impl PartialEq for () { | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in impl headers - --> $DIR/where-allowed.rs:166:24 + --> $DIR/where-allowed.rs:168:24 | LL | impl PartialEq<()> for impl Debug { | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in impl headers - --> $DIR/where-allowed.rs:171:6 + --> $DIR/where-allowed.rs:173:6 | LL | impl impl Debug { | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in impl headers - --> $DIR/where-allowed.rs:177:24 + --> $DIR/where-allowed.rs:179:24 | LL | impl InInherentImplAdt { | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in bounds - --> $DIR/where-allowed.rs:183:11 + --> $DIR/where-allowed.rs:185:11 | LL | where impl Debug: Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in bounds - --> $DIR/where-allowed.rs:190:15 + --> $DIR/where-allowed.rs:192:15 | LL | where Vec: Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in bounds - --> $DIR/where-allowed.rs:197:24 + --> $DIR/where-allowed.rs:199:24 | LL | where T: PartialEq | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait params - --> $DIR/where-allowed.rs:204:17 + --> $DIR/where-allowed.rs:206:17 | LL | where T: Fn(impl Debug) | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return types - --> $DIR/where-allowed.rs:211:22 + --> $DIR/where-allowed.rs:213:22 | LL | where T: Fn() -> impl Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter defaults - --> $DIR/where-allowed.rs:217:40 + --> $DIR/where-allowed.rs:219:40 | LL | struct InStructGenericParamDefault(T); | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter defaults - --> $DIR/where-allowed.rs:221:36 + --> $DIR/where-allowed.rs:223:36 | LL | enum InEnumGenericParamDefault { Variant(T) } | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter defaults - --> $DIR/where-allowed.rs:225:38 + --> $DIR/where-allowed.rs:227:38 | LL | trait InTraitGenericParamDefault {} | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter defaults - --> $DIR/where-allowed.rs:229:41 + --> $DIR/where-allowed.rs:231:41 | LL | type InTypeAliasGenericParamDefault = T; | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter defaults - --> $DIR/where-allowed.rs:233:11 + --> $DIR/where-allowed.rs:235:11 | LL | impl T {} | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter defaults - --> $DIR/where-allowed.rs:240:40 + --> $DIR/where-allowed.rs:242:40 | LL | fn in_method_generic_param_default(_: T) {} | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable bindings - --> $DIR/where-allowed.rs:246:29 + --> $DIR/where-allowed.rs:248:29 | LL | let _in_local_variable: impl Fn() = || {}; | ^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in closure return types - --> $DIR/where-allowed.rs:248:46 + --> $DIR/where-allowed.rs:250:46 | LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; | ^^^^^^^^^ error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/where-allowed.rs:233:7 + --> $DIR/where-allowed.rs:235:7 | LL | impl T {} | ^^^^^^^^^^^^^^ @@ -294,7 +294,7 @@ LL | impl T {} = note: `#[deny(invalid_type_param_default)]` on by default error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/where-allowed.rs:240:36 + --> $DIR/where-allowed.rs:242:36 | LL | fn in_method_generic_param_default(_: T) {} | ^^^^^^^^^^^^^^ @@ -303,7 +303,7 @@ LL | fn in_method_generic_param_default(_: T) {} = note: for more information, see issue #36887 error[E0118]: no nominal type found for inherent implementation - --> $DIR/where-allowed.rs:233:1 + --> $DIR/where-allowed.rs:235:1 | LL | impl T {} | ^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type diff --git a/tests/ui/lint/inline-trait-and-foreign-items.rs b/tests/ui/lint/inline-trait-and-foreign-items.rs index 13dab7ed954f..39bc01f71b5a 100644 --- a/tests/ui/lint/inline-trait-and-foreign-items.rs +++ b/tests/ui/lint/inline-trait-and-foreign-items.rs @@ -1,5 +1,5 @@ #![feature(extern_types)] -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] #![warn(unused_attributes)] diff --git a/tests/ui/lint/no-coverage.rs b/tests/ui/lint/no-coverage.rs index ff24c12b2bcf..07906a43472c 100644 --- a/tests/ui/lint/no-coverage.rs +++ b/tests/ui/lint/no-coverage.rs @@ -1,6 +1,6 @@ #![feature(extern_types)] #![feature(no_coverage)] -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] #![warn(unused_attributes)] #![no_coverage] //~^ WARN: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly diff --git a/tests/ui/nll/issue-78561.rs b/tests/ui/nll/issue-78561.rs index 55147fcd1bd2..1a2a3ca56c8d 100644 --- a/tests/ui/nll/issue-78561.rs +++ b/tests/ui/nll/issue-78561.rs @@ -1,5 +1,5 @@ // check-pass -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] pub trait Trait { type A; diff --git a/tests/ui/privacy/private-in-public-assoc-ty.rs b/tests/ui/privacy/private-in-public-assoc-ty.rs index fba72c13170f..d4d379bdb732 100644 --- a/tests/ui/privacy/private-in-public-assoc-ty.rs +++ b/tests/ui/privacy/private-in-public-assoc-ty.rs @@ -2,7 +2,7 @@ // This test also ensures that the checks are performed even inside private modules. #![feature(associated_type_defaults)] -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] mod m { struct Priv; diff --git a/tests/ui/privacy/private-in-public-type-alias-impl-trait.rs b/tests/ui/privacy/private-in-public-type-alias-impl-trait.rs index c7df31529bcf..fe6ed46734cd 100644 --- a/tests/ui/privacy/private-in-public-type-alias-impl-trait.rs +++ b/tests/ui/privacy/private-in-public-type-alias-impl-trait.rs @@ -1,5 +1,5 @@ // build-pass (FIXME(62277): could be check-pass?) - +#![feature(impl_trait_in_assoc_type)] #![feature(type_alias_impl_trait)] #![deny(private_in_public)] diff --git a/tests/ui/type-alias-impl-trait/assoc-type-const.rs b/tests/ui/type-alias-impl-trait/assoc-type-const.rs index 0ade36dafa4f..62f66914ee33 100644 --- a/tests/ui/type-alias-impl-trait/assoc-type-const.rs +++ b/tests/ui/type-alias-impl-trait/assoc-type-const.rs @@ -2,7 +2,7 @@ // const generics in an associated opaque type // check-pass -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait UnwrapItemsExt<'a, const C: usize> { type Iter; diff --git a/tests/ui/type-alias-impl-trait/assoc-type-lifetime-unconstrained.rs b/tests/ui/type-alias-impl-trait/assoc-type-lifetime-unconstrained.rs index 3f34b00ec77e..7c7c68ad60af 100644 --- a/tests/ui/type-alias-impl-trait/assoc-type-lifetime-unconstrained.rs +++ b/tests/ui/type-alias-impl-trait/assoc-type-lifetime-unconstrained.rs @@ -1,7 +1,7 @@ // Tests that we don't allow unconstrained lifetime parameters in impls when // the lifetime is used in an associated opaque type. -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait UnwrapItemsExt { type Iter; diff --git a/tests/ui/type-alias-impl-trait/assoc-type-lifetime.rs b/tests/ui/type-alias-impl-trait/assoc-type-lifetime.rs index 39f785d8cc55..81dacbcfb7ec 100644 --- a/tests/ui/type-alias-impl-trait/assoc-type-lifetime.rs +++ b/tests/ui/type-alias-impl-trait/assoc-type-lifetime.rs @@ -2,7 +2,7 @@ // lifetimes are used in an associated opaque type // check-pass -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait UnwrapItemsExt<'a> { type Iter; diff --git a/tests/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs b/tests/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs index 962606508be7..551815d021a0 100644 --- a/tests/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs +++ b/tests/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs @@ -1,6 +1,6 @@ //check-pass -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait Trait { type Opaque1; diff --git a/tests/ui/type-alias-impl-trait/auxiliary/collect_hidden_types.rs b/tests/ui/type-alias-impl-trait/auxiliary/collect_hidden_types.rs index 75d20a6fef9f..444a4e6957fa 100644 --- a/tests/ui/type-alias-impl-trait/auxiliary/collect_hidden_types.rs +++ b/tests/ui/type-alias-impl-trait/auxiliary/collect_hidden_types.rs @@ -1,4 +1,4 @@ -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] // edition:2018 diff --git a/tests/ui/type-alias-impl-trait/auxiliary/cross_crate_ice2.rs b/tests/ui/type-alias-impl-trait/auxiliary/cross_crate_ice2.rs index 119f7df1ffda..98c9615035af 100644 --- a/tests/ui/type-alias-impl-trait/auxiliary/cross_crate_ice2.rs +++ b/tests/ui/type-alias-impl-trait/auxiliary/cross_crate_ice2.rs @@ -1,7 +1,7 @@ // Crate that exports an opaque `impl Trait` type. Used for testing cross-crate. #![crate_type = "rlib"] -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] pub trait View { type Tmp: Iterator; diff --git a/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs b/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs index 851c2f66c475..1824ff5e2fb8 100644 --- a/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs +++ b/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs @@ -1,7 +1,7 @@ // Ensure that we don't ICE if associated type impl trait is used in an impl // with an unconstrained type parameter. -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait X { type I; diff --git a/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds.rs b/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds.rs index ee9bce15d347..4f99236f4eab 100644 --- a/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds.rs +++ b/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait Callable { type Output; diff --git a/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds_param.rs b/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds_param.rs index ae21a9134a41..5d5645077c2a 100644 --- a/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds_param.rs +++ b/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds_param.rs @@ -1,4 +1,4 @@ -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait Callable { type Output; @@ -17,7 +17,9 @@ impl<'a> PlusOne for &'a mut i32 { impl Callable for T { type Output = impl PlusOne; - fn call(t: T) -> Self::Output { t } + fn call(t: T) -> Self::Output { + t + } } fn test<'a>(y: &'a mut i32) -> impl PlusOne { diff --git a/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds_param.stderr b/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds_param.stderr index e52d5f9de69e..66e4783157b7 100644 --- a/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds_param.stderr +++ b/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds_param.stderr @@ -1,5 +1,5 @@ error[E0700]: hidden type for `impl PlusOne` captures lifetime that does not appear in bounds - --> $DIR/imply_bounds_from_bounds_param.rs:24:5 + --> $DIR/imply_bounds_from_bounds_param.rs:26:5 | LL | fn test<'a>(y: &'a mut i32) -> impl PlusOne { | -- ------------ opaque type defined here diff --git a/tests/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.rs b/tests/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.rs index 685d76ee36f3..8df59c68fefc 100644 --- a/tests/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.rs +++ b/tests/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.rs @@ -1,7 +1,7 @@ // Regression test for issue 67856 #![feature(unboxed_closures)] -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] #![feature(fn_traits)] trait MyTrait {} diff --git a/tests/ui/type-alias-impl-trait/issue-53598.rs b/tests/ui/type-alias-impl-trait/issue-53598.rs index 9c1cbf926f54..e3e2787b66bb 100644 --- a/tests/ui/type-alias-impl-trait/issue-53598.rs +++ b/tests/ui/type-alias-impl-trait/issue-53598.rs @@ -1,4 +1,4 @@ -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] use std::fmt::Debug; diff --git a/tests/ui/type-alias-impl-trait/issue-57188-associate-impl-capture.rs b/tests/ui/type-alias-impl-trait/issue-57188-associate-impl-capture.rs index 3a7a5da075f1..3bdb3bf1d530 100644 --- a/tests/ui/type-alias-impl-trait/issue-57188-associate-impl-capture.rs +++ b/tests/ui/type-alias-impl-trait/issue-57188-associate-impl-capture.rs @@ -2,7 +2,7 @@ // check-pass -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] struct Baz<'a> { source: &'a str, diff --git a/tests/ui/type-alias-impl-trait/issue-57611-trait-alias.rs b/tests/ui/type-alias-impl-trait/issue-57611-trait-alias.rs index cad3e0f66774..3917bb3b6cfb 100644 --- a/tests/ui/type-alias-impl-trait/issue-57611-trait-alias.rs +++ b/tests/ui/type-alias-impl-trait/issue-57611-trait-alias.rs @@ -3,7 +3,7 @@ // Ensures that we don't ICE #![feature(trait_alias)] -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait Foo { type Bar: Baz; diff --git a/tests/ui/type-alias-impl-trait/issue-57700.rs b/tests/ui/type-alias-impl-trait/issue-57700.rs index 484589387024..8746545ecc9e 100644 --- a/tests/ui/type-alias-impl-trait/issue-57700.rs +++ b/tests/ui/type-alias-impl-trait/issue-57700.rs @@ -1,5 +1,5 @@ #![feature(arbitrary_self_types)] -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] use std::ops::Deref; diff --git a/tests/ui/type-alias-impl-trait/issue-57807-associated-type.rs b/tests/ui/type-alias-impl-trait/issue-57807-associated-type.rs index fcab2c7db260..841bac5f6a0f 100644 --- a/tests/ui/type-alias-impl-trait/issue-57807-associated-type.rs +++ b/tests/ui/type-alias-impl-trait/issue-57807-associated-type.rs @@ -2,7 +2,7 @@ // that we properly unify associated types within // a type alias impl trait // check-pass -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait Bar { type A; diff --git a/tests/ui/type-alias-impl-trait/issue-58887.rs b/tests/ui/type-alias-impl-trait/issue-58887.rs index 96ac7860283a..9675867656a9 100644 --- a/tests/ui/type-alias-impl-trait/issue-58887.rs +++ b/tests/ui/type-alias-impl-trait/issue-58887.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait UnwrapItemsExt { type Iter; diff --git a/tests/ui/type-alias-impl-trait/issue-60371.rs b/tests/ui/type-alias-impl-trait/issue-60371.rs index 9a40f3d9b64e..a6173967333c 100644 --- a/tests/ui/type-alias-impl-trait/issue-60371.rs +++ b/tests/ui/type-alias-impl-trait/issue-60371.rs @@ -5,7 +5,7 @@ trait Bug { } impl Bug for &() { - type Item = impl Bug; //~ ERROR `impl Trait` in type aliases is unstable + type Item = impl Bug; //~ ERROR `impl Trait` in associated types is unstable const FUN: fn() -> Self::Item = || (); //~^ ERROR the trait bound `(): Bug` is not satisfied diff --git a/tests/ui/type-alias-impl-trait/issue-60371.stderr b/tests/ui/type-alias-impl-trait/issue-60371.stderr index d0c04371bd79..ffc664736355 100644 --- a/tests/ui/type-alias-impl-trait/issue-60371.stderr +++ b/tests/ui/type-alias-impl-trait/issue-60371.stderr @@ -1,11 +1,11 @@ -error[E0658]: `impl Trait` in type aliases is unstable +error[E0658]: `impl Trait` in associated types is unstable --> $DIR/issue-60371.rs:8:17 | LL | type Item = impl Bug; | ^^^^^^^^ | = note: see issue #63063 for more information - = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + = help: add `#![feature(impl_trait_in_assoc_type)]` to the crate attributes to enable error[E0277]: the trait bound `(): Bug` is not satisfied --> $DIR/issue-60371.rs:10:40 diff --git a/tests/ui/type-alias-impl-trait/issue-60564-working.rs b/tests/ui/type-alias-impl-trait/issue-60564-working.rs index 38accc8241cb..c4687c29de8e 100644 --- a/tests/ui/type-alias-impl-trait/issue-60564-working.rs +++ b/tests/ui/type-alias-impl-trait/issue-60564-working.rs @@ -1,4 +1,4 @@ -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] // check-pass diff --git a/tests/ui/type-alias-impl-trait/issue-62000-associate-impl-trait-lifetimes.rs b/tests/ui/type-alias-impl-trait/issue-62000-associate-impl-trait-lifetimes.rs index 36779a0ce89c..0245eab79694 100644 --- a/tests/ui/type-alias-impl-trait/issue-62000-associate-impl-trait-lifetimes.rs +++ b/tests/ui/type-alias-impl-trait/issue-62000-associate-impl-trait-lifetimes.rs @@ -2,7 +2,7 @@ // check-pass -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait MyTrait { type AssocType: Send; diff --git a/tests/ui/type-alias-impl-trait/issue-74761-2.rs b/tests/ui/type-alias-impl-trait/issue-74761-2.rs index d26ca5c3ead3..f582592e9bcc 100644 --- a/tests/ui/type-alias-impl-trait/issue-74761-2.rs +++ b/tests/ui/type-alias-impl-trait/issue-74761-2.rs @@ -1,4 +1,4 @@ -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] pub trait A { type B; diff --git a/tests/ui/type-alias-impl-trait/issue-74761.rs b/tests/ui/type-alias-impl-trait/issue-74761.rs index d26ca5c3ead3..f582592e9bcc 100644 --- a/tests/ui/type-alias-impl-trait/issue-74761.rs +++ b/tests/ui/type-alias-impl-trait/issue-74761.rs @@ -1,4 +1,4 @@ -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] pub trait A { type B; diff --git a/tests/ui/type-alias-impl-trait/issue-78450.rs b/tests/ui/type-alias-impl-trait/issue-78450.rs index fccbfb74fa2c..2a984c1ed713 100644 --- a/tests/ui/type-alias-impl-trait/issue-78450.rs +++ b/tests/ui/type-alias-impl-trait/issue-78450.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] pub trait AssociatedImpl { type ImplTrait; diff --git a/tests/ui/type-alias-impl-trait/issue-89952.rs b/tests/ui/type-alias-impl-trait/issue-89952.rs index dc0f19c042af..f0ba9fa7cec2 100644 --- a/tests/ui/type-alias-impl-trait/issue-89952.rs +++ b/tests/ui/type-alias-impl-trait/issue-89952.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait SomeTrait {} impl SomeTrait for () {} diff --git a/tests/ui/type-alias-impl-trait/issue-90400-1.rs b/tests/ui/type-alias-impl-trait/issue-90400-1.rs index 15aead2f6411..50207605748c 100644 --- a/tests/ui/type-alias-impl-trait/issue-90400-1.rs +++ b/tests/ui/type-alias-impl-trait/issue-90400-1.rs @@ -1,7 +1,7 @@ // Regression test for #90400, // taken from https://github.com/rust-lang/rust/issues/90400#issuecomment-954927836 -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait Bar { fn bar(&self); diff --git a/tests/ui/type-alias-impl-trait/issue-90400-2.rs b/tests/ui/type-alias-impl-trait/issue-90400-2.rs index 4c6e893c1729..60ff962ea2e3 100644 --- a/tests/ui/type-alias-impl-trait/issue-90400-2.rs +++ b/tests/ui/type-alias-impl-trait/issue-90400-2.rs @@ -1,7 +1,7 @@ // Regression test for #90400, // taken from https://github.com/rust-lang/rust/issues/90400#issuecomment-954927836 -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait Bar { fn bar(&self); diff --git a/tests/ui/type-alias-impl-trait/issue-94429.rs b/tests/ui/type-alias-impl-trait/issue-94429.rs index 2c965b875a00..d764545f906f 100644 --- a/tests/ui/type-alias-impl-trait/issue-94429.rs +++ b/tests/ui/type-alias-impl-trait/issue-94429.rs @@ -1,4 +1,4 @@ -#![feature(type_alias_impl_trait, generator_trait, generators)] +#![feature(impl_trait_in_assoc_type, generator_trait, generators)] use std::ops::Generator; trait Runnable { @@ -13,7 +13,7 @@ impl Runnable for Implementor { type Gen = impl Generator; fn run(&mut self) -> Self::Gen { - //~^ ERROR: type mismatch resolving + //~^ ERROR: type mismatch resolving move || { yield 1; } diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.rs index efbf4f1e351f..296a3f3e3007 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.rs +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.rs @@ -1,6 +1,6 @@ // regression test for #74018 -#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] trait Trait { type Associated; From cdd982955623f697f759f548ce11f886a413f4f6 Mon Sep 17 00:00:00 2001 From: marc0246 <40955683+marc0246@users.noreply.github.com> Date: Wed, 12 Apr 2023 19:21:40 +0200 Subject: [PATCH 229/272] Fix btree `CursorMut::insert_after` check --- library/alloc/src/collections/btree/map.rs | 2 +- .../alloc/src/collections/btree/map/tests.rs | 64 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 61db46314b78..da675379cd58 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -3183,7 +3183,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { panic!("key must be ordered above the current element"); } } - if let Some((next, _)) = self.peek_prev() { + if let Some((next, _)) = self.peek_next() { if &key >= next { panic!("key must be ordered below the next element"); } diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 76c2f27b4663..4311f21c925c 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -2385,3 +2385,67 @@ fn test_cursor_mut() { assert_eq!(cur.key(), Some(&4)); assert_eq!(map, BTreeMap::from([(0, '?'), (1, 'a'), (3, 'c'), (4, 'd')])); } + +#[should_panic(expected = "key must be ordered above the previous element")] +#[test] +fn test_cursor_mut_insert_before_1() { + let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); + let mut cur = map.upper_bound_mut(Bound::Included(&2)); + cur.insert_before(0, 'd'); +} + +#[should_panic(expected = "key must be ordered above the previous element")] +#[test] +fn test_cursor_mut_insert_before_2() { + let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); + let mut cur = map.upper_bound_mut(Bound::Included(&2)); + cur.insert_before(1, 'd'); +} + +#[should_panic(expected = "key must be ordered below the current element")] +#[test] +fn test_cursor_mut_insert_before_3() { + let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); + let mut cur = map.upper_bound_mut(Bound::Included(&2)); + cur.insert_before(2, 'd'); +} + +#[should_panic(expected = "key must be ordered below the current element")] +#[test] +fn test_cursor_mut_insert_before_4() { + let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); + let mut cur = map.upper_bound_mut(Bound::Included(&2)); + cur.insert_before(3, 'd'); +} + +#[should_panic(expected = "key must be ordered above the current element")] +#[test] +fn test_cursor_mut_insert_after_1() { + let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); + let mut cur = map.upper_bound_mut(Bound::Included(&2)); + cur.insert_after(1, 'd'); +} + +#[should_panic(expected = "key must be ordered above the current element")] +#[test] +fn test_cursor_mut_insert_after_2() { + let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); + let mut cur = map.upper_bound_mut(Bound::Included(&2)); + cur.insert_after(2, 'd'); +} + +#[should_panic(expected = "key must be ordered below the next element")] +#[test] +fn test_cursor_mut_insert_after_3() { + let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); + let mut cur = map.upper_bound_mut(Bound::Included(&2)); + cur.insert_after(3, 'd'); +} + +#[should_panic(expected = "key must be ordered below the next element")] +#[test] +fn test_cursor_mut_insert_after_4() { + let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); + let mut cur = map.upper_bound_mut(Bound::Included(&2)); + cur.insert_after(4, 'd'); +} From bb7ed64f457be500a74d53c9d12f1d0a8f7badf6 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 10 Apr 2023 16:15:51 -0700 Subject: [PATCH 230/272] rustdoc: use CSS `overscroll-behavior` instead of JavaScript Fixes the desktop scrolling weirdness mentioned in https://github.com/rust-lang/rust/pull/98775#issuecomment-1182575603 As described in the MDN page for this property: * The current Firefox ESR is 102, and the first Firefox version to support this feature is 59. * The current Chrome version 112, and the first version to support this is 63. * Edge is described as having a minor bug in `none` mode, but we use `contain` mode anyway, so it doesn't matter. * Safari 16, released September 2022, is the last browser to add this feature, and is also the oldest version we officially support. --- src/librustdoc/html/static/css/rustdoc.css | 3 +- src/librustdoc/html/static/js/main.js | 52 ------------------- .../html/static/js/source-script.js | 9 ++-- tests/rustdoc-gui/sidebar-mobile-scroll.goml | 39 ++++---------- .../sidebar-source-code-display.goml | 12 +---- 5 files changed, 19 insertions(+), 96 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 9df193525673..6fbb4508662c 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -384,6 +384,7 @@ img { font-size: 0.875rem; flex: 0 0 200px; overflow-y: scroll; + overscroll-behavior: contain; position: sticky; height: 100vh; top: 0; @@ -1531,7 +1532,7 @@ However, it's not needed with smaller screen width because the doc/code block is /* WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY If you update this line, then you also need to update the line with the same warning -in main.js +in source-script.js */ @media (max-width: 700px) { /* When linking to an item with an `id` (for instance, by clicking a link in the sidebar, diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index a6655663b82f..6f5987e68bf1 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -4,11 +4,6 @@ "use strict"; -// WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY -// If you update this line, then you also need to update the media query with the same -// warning in rustdoc.css -window.RUSTDOC_MOBILE_BREAKPOINT = 700; - // Given a basename (e.g. "storage") and an extension (e.g. ".js"), return a URL // for a resource under the root-path, with the resource-suffix. function resourcePath(basename, extension) { @@ -730,65 +725,18 @@ function preLoadCss(cssUrl) { window.rustdoc_add_line_numbers_to_examples(); } - let oldSidebarScrollPosition = null; - - // Scroll locking used both here and in source-script.js - - window.rustdocMobileScrollLock = function() { - const mobile_topbar = document.querySelector(".mobile-topbar"); - if (window.innerWidth <= window.RUSTDOC_MOBILE_BREAKPOINT) { - // This is to keep the scroll position on mobile. - oldSidebarScrollPosition = window.scrollY; - document.body.style.width = `${document.body.offsetWidth}px`; - document.body.style.position = "fixed"; - document.body.style.top = `-${oldSidebarScrollPosition}px`; - if (mobile_topbar) { - mobile_topbar.style.top = `${oldSidebarScrollPosition}px`; - mobile_topbar.style.position = "relative"; - } - } else { - oldSidebarScrollPosition = null; - } - }; - - window.rustdocMobileScrollUnlock = function() { - const mobile_topbar = document.querySelector(".mobile-topbar"); - if (oldSidebarScrollPosition !== null) { - // This is to keep the scroll position on mobile. - document.body.style.width = ""; - document.body.style.position = ""; - document.body.style.top = ""; - if (mobile_topbar) { - mobile_topbar.style.top = ""; - mobile_topbar.style.position = ""; - } - // The scroll position is lost when resetting the style, hence why we store it in - // `oldSidebarScrollPosition`. - window.scrollTo(0, oldSidebarScrollPosition); - oldSidebarScrollPosition = null; - } - }; - function showSidebar() { window.hideAllModals(false); - window.rustdocMobileScrollLock(); const sidebar = document.getElementsByClassName("sidebar")[0]; addClass(sidebar, "shown"); } function hideSidebar() { - window.rustdocMobileScrollUnlock(); const sidebar = document.getElementsByClassName("sidebar")[0]; removeClass(sidebar, "shown"); } window.addEventListener("resize", () => { - if (window.innerWidth > window.RUSTDOC_MOBILE_BREAKPOINT && - oldSidebarScrollPosition !== null) { - // If the user opens the sidebar in "mobile" mode, and then grows the browser window, - // we need to switch away from mobile mode and make the main content area scrollable. - hideSidebar(); - } if (window.CURRENT_TOOLTIP_ELEMENT) { // As a workaround to the behavior of `contains: layout` used in doc togglers, // tooltip popovers are positioned using javascript. diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js index 6c0f03b5bb07..9aa75517330c 100644 --- a/src/librustdoc/html/static/js/source-script.js +++ b/src/librustdoc/html/static/js/source-script.js @@ -15,8 +15,13 @@ const NAME_OFFSET = 0; const DIRS_OFFSET = 1; const FILES_OFFSET = 2; +// WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY +// If you update this line, then you also need to update the media query with the same +// warning in rustdoc.css +const RUSTDOC_MOBILE_BREAKPOINT = 700; + function closeSidebarIfMobile() { - if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) { + if (window.innerWidth < RUSTDOC_MOBILE_BREAKPOINT) { updateLocalStorage("source-sidebar-show", "false"); } } @@ -69,12 +74,10 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) { function toggleSidebar() { const child = this.parentNode.children[0]; if (child.innerText === ">") { - window.rustdocMobileScrollLock(); addClass(document.documentElement, "source-sidebar-expanded"); child.innerText = "<"; updateLocalStorage("source-sidebar-show", "true"); } else { - window.rustdocMobileScrollUnlock(); removeClass(document.documentElement, "source-sidebar-expanded"); child.innerText = ">"; updateLocalStorage("source-sidebar-show", "false"); diff --git a/tests/rustdoc-gui/sidebar-mobile-scroll.goml b/tests/rustdoc-gui/sidebar-mobile-scroll.goml index 84811437eb2c..d58d1d48726e 100644 --- a/tests/rustdoc-gui/sidebar-mobile-scroll.goml +++ b/tests/rustdoc-gui/sidebar-mobile-scroll.goml @@ -1,31 +1,12 @@ -// This test ensures that the mobile sidebar preserves scroll position. +// This test ensures that the mobile disables scrolling the page. go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" -// Switching to "mobile view" by reducing the width to 600px. -set-window-size: (700, 600) -assert-css: (".sidebar", {"display": "block", "left": "-1000px"}) +set-window-size: (1280, 800) // desktop +assert-css: (".sidebar", {"overscroll-behavior": "contain"}) +set-window-size: (700, 600) // mobile +assert-css: (".sidebar", {"overscroll-behavior": "contain"}) -// Scroll down. -scroll-to: "//h2[@id='blanket-implementations']" -assert-window-property: {"pageYOffset": "622"} - -// Open the sidebar menu. -click: ".sidebar-menu-toggle" -wait-for-css: (".sidebar", {"left": "0px"}) - -// We are no longer "scrolled". It's important that the user can't -// scroll the body at all, but these test scripts are run only in Chrome, -// and we need to use a more complicated solution to this problem because -// of Mobile Safari... -assert-window-property: {"pageYOffset": "0"} - -// Close the sidebar menu. Make sure the scroll position gets restored. -click: ".sidebar-menu-toggle" -wait-for-css: (".sidebar", {"left": "-1000px"}) -assert-window-property: {"pageYOffset": "622"} - -// Now test that scrollability returns when the browser window is just resized. -click: ".sidebar-menu-toggle" -wait-for-css: (".sidebar", {"left": "0px"}) -assert-window-property: {"pageYOffset": "0"} -set-window-size: (900, 600) -assert-window-property: {"pageYOffset": "622"} +go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" +set-window-size: (1280, 800) // desktop +assert-css: (".sidebar", {"overscroll-behavior": "contain"}) +set-window-size: (700, 600) // mobile +assert-css: (".sidebar", {"overscroll-behavior": "contain"}) diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml index f34e30b724da..20bf0596f958 100644 --- a/tests/rustdoc-gui/sidebar-source-code-display.goml +++ b/tests/rustdoc-gui/sidebar-source-code-display.goml @@ -183,22 +183,12 @@ wait-for-css: (".sidebar", {"left": "-1000px"}) // The "scrollTop" property should be the same. assert-window-property: {"pageYOffset": "2542"} -// We now check that the scroll position is restored if the window is resized. -set-window-size: (500, 700) -click: "#src-sidebar-toggle" -wait-for-css: ("#source-sidebar", {"visibility": "visible"}) -assert-window-property: {"pageYOffset": "0"} -set-window-size: (900, 900) -assert-window-property: {"pageYOffset": "2542"} -set-window-size: (500, 700) -click: "#src-sidebar-toggle" -wait-for-css: ("#source-sidebar", {"visibility": "hidden"}) - // We now check that opening the sidebar and clicking a link will close it. // The behavior here on mobile is different than the behavior on desktop, // but common sense dictates that if you have a list of files that fills the entire screen, and // you click one of them, you probably want to actually see the file's contents, and not just // make it the current selection. +set-window-size: (500, 700) click: "#src-sidebar-toggle" wait-for-css: ("#source-sidebar", {"visibility": "visible"}) assert-local-storage: {"rustdoc-source-sidebar-show": "true"} From bf6582e0cc9c1fbeb274bd496c8077e94d26adc4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 12 Apr 2023 14:56:08 +0200 Subject: [PATCH 231/272] Move creation of `theme.css` file from `--extend-css` command into the `static.files` folder --- src/librustdoc/html/templates/page.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 532660e3d33c..9133f899af60 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -64,7 +64,7 @@ {# #} {% if layout.css_file_extension.is_some() %} {# #} + href="{{page.root_path|safe}}theme{{page.resource_suffix}}.css"> {# #} {% endif %} {% if !layout.favicon.is_empty() %} {# #} From 6bc6ea7a3e21b7cb33cb24c5c63c7d1125a3f1e9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 12 Apr 2023 15:17:33 +0200 Subject: [PATCH 232/272] Add/update tests for `--extend-css` option --- src/bootstrap/test.rs | 2 ++ tests/rustdoc-gui/extend-css.goml | 5 +++++ tests/rustdoc-gui/search-filter.goml | 2 ++ tests/rustdoc-gui/sidebar-source-code.goml | 2 +- tests/rustdoc-gui/source-code-page.goml | 2 +- tests/rustdoc-gui/src/extend_css/Cargo.lock | 7 +++++++ tests/rustdoc-gui/src/extend_css/Cargo.toml | 7 +++++++ tests/rustdoc-gui/src/extend_css/extra.css | 3 +++ tests/rustdoc-gui/src/extend_css/lib.rs | 1 + 9 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 tests/rustdoc-gui/extend-css.goml create mode 100644 tests/rustdoc-gui/src/extend_css/Cargo.lock create mode 100644 tests/rustdoc-gui/src/extend_css/Cargo.toml create mode 100644 tests/rustdoc-gui/src/extend_css/extra.css create mode 100644 tests/rustdoc-gui/src/extend_css/lib.rs diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index f9c5837b7d61..e4e4f938528d 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1064,6 +1064,8 @@ impl Step for RustdocGUI { cargo.env("RUSTDOCFLAGS", "-Zunstable-options --generate-link-to-definition"); } else if entry.file_name() == "scrape_examples" { cargo.arg("-Zrustdoc-scrape-examples"); + } else if entry.file_name() == "extend_css" { + cargo.env("RUSTDOCFLAGS", &format!("--extend-css extra.css")); } builder.run(&mut cargo); } diff --git a/tests/rustdoc-gui/extend-css.goml b/tests/rustdoc-gui/extend-css.goml new file mode 100644 index 000000000000..fb34469df6c5 --- /dev/null +++ b/tests/rustdoc-gui/extend-css.goml @@ -0,0 +1,5 @@ +// Test to ensure that the `--extend-css` option is working as expected. +go-to: "file://" + |DOC_PATH| + "/extend_css/index.html" +show-text: true +// The text from the `.extend` element should be red. +assert-css: (".extend", {"color": "rgb(255, 0, 0)"}) diff --git a/tests/rustdoc-gui/search-filter.goml b/tests/rustdoc-gui/search-filter.goml index f114c57ff21e..d739471a625a 100644 --- a/tests/rustdoc-gui/search-filter.goml +++ b/tests/rustdoc-gui/search-filter.goml @@ -16,6 +16,7 @@ press-key: "ArrowDown" press-key: "ArrowDown" press-key: "ArrowDown" press-key: "ArrowDown" +press-key: "ArrowDown" press-key: "Enter" // Waiting for the search results to appear... wait-for: "#search-tabs" @@ -41,6 +42,7 @@ press-key: "ArrowUp" press-key: "ArrowUp" press-key: "ArrowUp" press-key: "ArrowUp" +press-key: "ArrowUp" press-key: "Enter" // Waiting for the search results to appear... wait-for: "#search-tabs" diff --git a/tests/rustdoc-gui/sidebar-source-code.goml b/tests/rustdoc-gui/sidebar-source-code.goml index 96ea7202433c..520b2c59b0f8 100644 --- a/tests/rustdoc-gui/sidebar-source-code.goml +++ b/tests/rustdoc-gui/sidebar-source-code.goml @@ -73,7 +73,7 @@ assert: "//*[@class='dir-entry' and @open]/*[text()='sub_mod']" // Only "another_folder" should be "open" in "lib2". assert: "//*[@class='dir-entry' and not(@open)]/*[text()='another_mod']" // All other trees should be collapsed. -assert-count: ("//*[@id='source-sidebar']/details[not(text()='lib2') and not(@open)]", 8) +assert-count: ("//*[@id='source-sidebar']/details[not(text()='lib2') and not(@open)]", 9) // We now switch to mobile mode. set-window-size: (600, 600) diff --git a/tests/rustdoc-gui/source-code-page.goml b/tests/rustdoc-gui/source-code-page.goml index 1ac403308eb9..42f3200e9679 100644 --- a/tests/rustdoc-gui/source-code-page.goml +++ b/tests/rustdoc-gui/source-code-page.goml @@ -102,7 +102,7 @@ assert: ".source-sidebar-expanded" // We check that the first entry of the sidebar is collapsed assert-property: ("#source-sidebar details:first-of-type", {"open": "false"}) -assert-text: ("#source-sidebar details:first-of-type > summary", "http") +assert-text: ("#source-sidebar details:first-of-type > summary", "extend_css") // We now click on it. click: "#source-sidebar details:first-of-type > summary" assert-property: ("#source-sidebar details:first-of-type", {"open": "true"}) diff --git a/tests/rustdoc-gui/src/extend_css/Cargo.lock b/tests/rustdoc-gui/src/extend_css/Cargo.lock new file mode 100644 index 000000000000..7101a6f0ffbb --- /dev/null +++ b/tests/rustdoc-gui/src/extend_css/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "extend_css" +version = "0.1.0" diff --git a/tests/rustdoc-gui/src/extend_css/Cargo.toml b/tests/rustdoc-gui/src/extend_css/Cargo.toml new file mode 100644 index 000000000000..91683fe89648 --- /dev/null +++ b/tests/rustdoc-gui/src/extend_css/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "extend_css" +version = "0.1.0" +edition = "2018" + +[lib] +path = "lib.rs" diff --git a/tests/rustdoc-gui/src/extend_css/extra.css b/tests/rustdoc-gui/src/extend_css/extra.css new file mode 100644 index 000000000000..ee7062d9621a --- /dev/null +++ b/tests/rustdoc-gui/src/extend_css/extra.css @@ -0,0 +1,3 @@ +.extend { + color: red !important; +} diff --git a/tests/rustdoc-gui/src/extend_css/lib.rs b/tests/rustdoc-gui/src/extend_css/lib.rs new file mode 100644 index 000000000000..3a3babf89840 --- /dev/null +++ b/tests/rustdoc-gui/src/extend_css/lib.rs @@ -0,0 +1 @@ +//!
text in red
From b76821b4de51fa79c4f593079679f63b7476f737 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 12 Apr 2023 15:21:41 +0200 Subject: [PATCH 233/272] Update rustdoc book content about `--extend-css` option --- src/doc/rustdoc/src/command-line-arguments.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md index 2a2e51b2f633..dfc804263723 100644 --- a/src/doc/rustdoc/src/command-line-arguments.md +++ b/src/doc/rustdoc/src/command-line-arguments.md @@ -320,10 +320,7 @@ $ rustdoc src/lib.rs --extend-css extra.css ``` With this flag, the contents of the files you pass are included at the bottom -of Rustdoc's `theme.css` file. - -While this flag is stable, the contents of `theme.css` are not, so be careful! -Updates may break your theme extensions. +of the `theme.css` file. ## `--sysroot`: override the system root From c0d3d32922d308088dd176d216d6c7409374c70b Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 12 Apr 2023 22:07:07 +0200 Subject: [PATCH 234/272] fix comment --- .../rustc_trait_selection/src/traits/error_reporting/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 6790d7b76a3a..81ab5b9f0576 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1764,7 +1764,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // constrain inference variables a bit more to nested obligations from normalize so // we can have more helpful errors. // - // we intentionally errors from normalization here. + // we intentionally drop errors from normalization here, + // since the normalization is just done to improve the error message. let _ = ocx.select_where_possible(); if let Err(new_err) = ocx.eq_exp( From 9e0e4c31aa88e5d510fdd0742808ec95329470e4 Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Wed, 12 Apr 2023 18:03:11 -0400 Subject: [PATCH 235/272] Added diagnostic for pin! macro in addition to Box::pin if Unpin isn't implemented --- library/core/src/marker.rs | 2 +- .../async-await/pin-needed-to-poll-2.stderr | 3 ++- tests/ui/generator/static-not-unpin.stderr | 3 ++- .../expected-boxed-future-isnt-pinned.stderr | 6 +++-- .../suggestions/issue-84973-blacklist.stderr | 3 ++- tests/ui/suggestions/suggest-pin-macro.rs | 23 +++++++++++++++++++ tests/ui/suggestions/suggest-pin-macro.stderr | 19 +++++++++++++++ tests/ui/typeck/issue-90164.stderr | 3 ++- 8 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 tests/ui/suggestions/suggest-pin-macro.rs create mode 100644 tests/ui/suggestions/suggest-pin-macro.stderr diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 62064f1aa6cb..3cd4f5104ce7 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -823,7 +823,7 @@ unsafe impl Freeze for &mut T {} /// [`pin` module]: crate::pin #[stable(feature = "pin", since = "1.33.0")] #[rustc_on_unimplemented( - note = "consider using `Box::pin`", + note = "consider using the `pin!` macro\nconsider using `Box::pin` if you need to access the pinned value outside of the current scope", message = "`{Self}` cannot be unpinned" )] #[lang = "unpin"] diff --git a/tests/ui/async-await/pin-needed-to-poll-2.stderr b/tests/ui/async-await/pin-needed-to-poll-2.stderr index 0a6f705e255a..61126faf8992 100644 --- a/tests/ui/async-await/pin-needed-to-poll-2.stderr +++ b/tests/ui/async-await/pin-needed-to-poll-2.stderr @@ -6,7 +6,8 @@ LL | Pin::new(&mut self.sleep).poll(cx) | | | required by a bound introduced by this call | - = note: consider using `Box::pin` + = note: consider using the `pin!` macro + consider using `Box::pin` if you need to access the pinned value outside of the current scope note: required because it appears within the type `Sleep` --> $DIR/pin-needed-to-poll-2.rs:8:8 | diff --git a/tests/ui/generator/static-not-unpin.stderr b/tests/ui/generator/static-not-unpin.stderr index e3859595fd2c..7376116b3380 100644 --- a/tests/ui/generator/static-not-unpin.stderr +++ b/tests/ui/generator/static-not-unpin.stderr @@ -6,7 +6,8 @@ LL | assert_unpin(generator); | | | required by a bound introduced by this call | - = note: consider using `Box::pin` + = note: consider using the `pin!` macro + consider using `Box::pin` if you need to access the pinned value outside of the current scope note: required by a bound in `assert_unpin` --> $DIR/static-not-unpin.rs:7:20 | diff --git a/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr b/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr index b827beb504d5..0232d4c8db69 100644 --- a/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr +++ b/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -50,7 +50,8 @@ LL | Pin::new(x) | | | required by a bound introduced by this call | - = note: consider using `Box::pin` + = note: consider using the `pin!` macro + consider using `Box::pin` if you need to access the pinned value outside of the current scope note: required by a bound in `Pin::

::new` --> $SRC_DIR/core/src/pin.rs:LL:COL @@ -62,7 +63,8 @@ LL | Pin::new(Box::new(x)) | | | required by a bound introduced by this call | - = note: consider using `Box::pin` + = note: consider using the `pin!` macro + consider using `Box::pin` if you need to access the pinned value outside of the current scope note: required by a bound in `Pin::

::new` --> $SRC_DIR/core/src/pin.rs:LL:COL diff --git a/tests/ui/suggestions/issue-84973-blacklist.stderr b/tests/ui/suggestions/issue-84973-blacklist.stderr index c20cc816484b..b9473d43b016 100644 --- a/tests/ui/suggestions/issue-84973-blacklist.stderr +++ b/tests/ui/suggestions/issue-84973-blacklist.stderr @@ -38,7 +38,8 @@ LL | f_unpin(static || { yield; }); | | | required by a bound introduced by this call | - = note: consider using `Box::pin` + = note: consider using the `pin!` macro + consider using `Box::pin` if you need to access the pinned value outside of the current scope note: required by a bound in `f_unpin` --> $DIR/issue-84973-blacklist.rs:8:15 | diff --git a/tests/ui/suggestions/suggest-pin-macro.rs b/tests/ui/suggestions/suggest-pin-macro.rs new file mode 100644 index 000000000000..f5b96215925b --- /dev/null +++ b/tests/ui/suggestions/suggest-pin-macro.rs @@ -0,0 +1,23 @@ +use std::pin::Pin; +use std::marker::PhantomPinned; + +#[derive(Debug)] +struct Test { + _marker: PhantomPinned, +} +impl Test { + fn new() -> Self { + Test { + _marker: PhantomPinned, // This makes our type `!Unpin` + } + } +} + +fn dummy(_: &mut Test) {} + +pub fn main() { + let mut test1 = Test::new(); + let mut test1 = unsafe { Pin::new_unchecked(&mut test1) }; + + dummy(test1.get_mut()); //~ ERROR E0277 +} diff --git a/tests/ui/suggestions/suggest-pin-macro.stderr b/tests/ui/suggestions/suggest-pin-macro.stderr new file mode 100644 index 000000000000..1220cf650cc3 --- /dev/null +++ b/tests/ui/suggestions/suggest-pin-macro.stderr @@ -0,0 +1,19 @@ +error[E0277]: `PhantomPinned` cannot be unpinned + --> $DIR/suggest-pin-macro.rs:22:17 + | +LL | dummy(test1.get_mut()); + | ^^^^^^^ within `Test`, the trait `Unpin` is not implemented for `PhantomPinned` + | + = note: consider using the `pin!` macro + consider using `Box::pin` if you need to access the pinned value outside of the current scope +note: required because it appears within the type `Test` + --> $DIR/suggest-pin-macro.rs:5:8 + | +LL | struct Test { + | ^^^^ +note: required by a bound in `Pin::<&'a mut T>::get_mut` + --> $SRC_DIR/core/src/pin.rs:LL:COL + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/typeck/issue-90164.stderr b/tests/ui/typeck/issue-90164.stderr index 1e2f1bae3bd8..8586f522291b 100644 --- a/tests/ui/typeck/issue-90164.stderr +++ b/tests/ui/typeck/issue-90164.stderr @@ -6,7 +6,8 @@ LL | copy(r, w); | | | required by a bound introduced by this call | - = note: consider using `Box::pin` + = note: consider using the `pin!` macro + consider using `Box::pin` if you need to access the pinned value outside of the current scope note: required by a bound in `copy` --> $DIR/issue-90164.rs:1:12 | From 5b40aa5eb484b31c9a82c1b1a0f414840477b9ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 18 Mar 2023 02:18:39 +0000 Subject: [PATCH 236/272] Tweak output for 'add line' suggestion --- compiler/rustc_errors/src/emitter.rs | 41 ++++++++++++++++- .../clippy/tests/ui/crashes/ice-6252.stderr | 9 ++-- .../clippy/tests/ui/derivable_impls.stderr | 24 ++++++---- .../tests/ui/new_without_default.stderr | 6 +++ .../ui/array-slice-vec/repeat_empty_ok.stderr | 6 ++- .../defaults-suitability.stderr | 6 ++- tests/ui/binop/issue-28837.stderr | 18 +++++--- tests/ui/box/unit/unique-pinned-nocopy.stderr | 3 +- tests/ui/coherence/coherence_inherent.stderr | 3 +- .../ui/coherence/coherence_inherent_cc.stderr | 3 +- .../generic_const_exprs/issue-94287.stderr | 1 + .../const-generics/issues/issue-82956.stderr | 12 +++-- .../const-blocks/fn-call-in-non-const.stderr | 3 +- .../consts/const-blocks/migrate-fail.stderr | 6 ++- tests/ui/consts/const-blocks/nll-fail.stderr | 6 ++- .../min_const_fn_libstd_stability.stderr | 6 ++- ...in_const_unsafe_fn_libstd_stability.stderr | 6 ++- tests/ui/derived-errors/issue-31997-1.stderr | 3 +- .../derives/derive-assoc-type-not-impl.stderr | 3 +- ...ives-span-Clone-enum-struct-variant.stderr | 3 +- .../ui/derives/derives-span-Clone-enum.stderr | 3 +- .../derives/derives-span-Clone-struct.stderr | 3 +- .../derives-span-Clone-tuple-struct.stderr | 3 +- ...ives-span-Debug-enum-struct-variant.stderr | 3 +- .../ui/derives/derives-span-Debug-enum.stderr | 3 +- .../derives/derives-span-Debug-struct.stderr | 3 +- .../derives-span-Debug-tuple-struct.stderr | 3 +- .../derives-span-Default-struct.stderr | 3 +- .../derives-span-Default-tuple-struct.stderr | 3 +- ...derives-span-Eq-enum-struct-variant.stderr | 3 +- tests/ui/derives/derives-span-Eq-enum.stderr | 3 +- .../ui/derives/derives-span-Eq-struct.stderr | 3 +- .../derives-span-Eq-tuple-struct.stderr | 3 +- ...rives-span-Hash-enum-struct-variant.stderr | 3 +- .../ui/derives/derives-span-Hash-enum.stderr | 3 +- .../derives/derives-span-Hash-struct.stderr | 3 +- .../derives-span-Hash-tuple-struct.stderr | 3 +- ...erives-span-Ord-enum-struct-variant.stderr | 3 +- tests/ui/derives/derives-span-Ord-enum.stderr | 3 +- .../ui/derives/derives-span-Ord-struct.stderr | 3 +- .../derives-span-Ord-tuple-struct.stderr | 3 +- ...-span-PartialEq-enum-struct-variant.stderr | 3 +- .../derives-span-PartialEq-enum.stderr | 3 +- .../derives-span-PartialEq-struct.stderr | 3 +- ...derives-span-PartialEq-tuple-struct.stderr | 3 +- ...span-PartialOrd-enum-struct-variant.stderr | 3 +- .../derives-span-PartialOrd-enum.stderr | 3 +- .../derives-span-PartialOrd-struct.stderr | 3 +- ...erives-span-PartialOrd-tuple-struct.stderr | 3 +- ...eriving-no-inner-impl-error-message.stderr | 6 ++- .../deriving-with-repr-packed-2.stderr | 3 +- tests/ui/derives/issue-91492.stderr | 9 ++-- tests/ui/derives/issue-91550.stderr | 12 +++-- ...ssue-56028-there-is-an-enum-variant.stderr | 12 +++-- tests/ui/error-codes/E0277-3.stderr | 3 +- tests/ui/fmt/format-args-argument-span.stderr | 6 ++- tests/ui/generator/clone-impl.stderr | 6 ++- ...issue-87429-associated-type-default.stderr | 3 +- .../issue-87429-specialization.stderr | 3 +- tests/ui/hygiene/globs.stderr | 6 ++- tests/ui/hygiene/no_implicit_prelude.stderr | 6 ++- tests/ui/hygiene/trait_items.stderr | 3 +- .../no-method-suggested-traits.stderr | 36 ++++++++++----- .../impl-trait/universal_wrong_bounds.stderr | 6 ++- tests/ui/imports/glob-resolve1.stderr | 3 +- tests/ui/imports/issue-38293.stderr | 3 +- tests/ui/imports/issue-4366-2.stderr | 3 +- tests/ui/imports/issue-4366.stderr | 3 +- tests/ui/imports/overlapping_pub_trait.stderr | 3 +- tests/ui/imports/unnamed_pub_trait.stderr | 3 +- .../internal/internal-unstable-const.stderr | 6 ++- tests/ui/issues/issue-10465.stderr | 3 +- tests/ui/issues/issue-17546.stderr | 24 ++++++---- tests/ui/issues/issue-20162.stderr | 3 +- tests/ui/issues/issue-21160.stderr | 3 +- tests/ui/issues/issue-35976.unimported.stderr | 3 +- tests/ui/issues/issue-37534.stderr | 3 +- tests/ui/issues/issue-39175.stderr | 3 +- tests/ui/issues/issue-56175.stderr | 6 ++- tests/ui/issues/issue-62375.stderr | 3 +- tests/ui/issues/issue-77919.stderr | 3 +- .../ui/kindck/kindck-impl-type-params.stderr | 3 +- tests/ui/layout/issue-84108.stderr | 6 ++- tests/ui/macros/issue-100199.stderr | 3 +- tests/ui/macros/macro-outer-attributes.stderr | 3 +- .../malformed/malformed-derive-entry.stderr | 6 ++- .../method-help-unsatisfied-bound.stderr | 3 +- tests/ui/modules/issue-107649.stderr | 3 +- tests/ui/namespace/namespace-mix.stderr | 24 ++++++---- tests/ui/not-clone-closure.stderr | 3 +- tests/ui/on-unimplemented/no-debug.stderr | 3 +- tests/ui/parser/circular_modules_main.stderr | 3 +- tests/ui/privacy/privacy-ns1.stderr | 9 ++-- tests/ui/privacy/privacy-ns2.stderr | 9 ++-- tests/ui/proc-macro/amputate-span.stderr | 6 ++- .../attributes-on-modules-fail.stderr | 6 ++- .../repeat-to-run-dtor-twice.stderr | 3 +- tests/ui/resolve/crate-in-paths.stderr | 3 +- .../ui/resolve/enums-are-namespaced-xc.stderr | 9 ++-- tests/ui/resolve/filter-intrinsics.stderr | 6 ++- tests/ui/resolve/issue-102946.stderr | 3 +- tests/ui/resolve/issue-16058.stderr | 9 ++-- tests/ui/resolve/issue-17518.stderr | 3 +- tests/ui/resolve/issue-21221-1.stderr | 21 ++++++--- tests/ui/resolve/issue-21221-2.stderr | 6 ++- tests/ui/resolve/issue-21221-3.stderr | 3 +- tests/ui/resolve/issue-21221-4.stderr | 3 +- tests/ui/resolve/issue-2356.stderr | 3 +- tests/ui/resolve/issue-26545.stderr | 3 +- tests/ui/resolve/issue-35675.stderr | 6 ++- tests/ui/resolve/issue-3907.stderr | 3 +- tests/ui/resolve/issue-50599.stderr | 6 ++- tests/ui/resolve/issue-73427.stderr | 6 ++- tests/ui/resolve/issue-90113.stderr | 3 +- tests/ui/resolve/missing-in-namespace.stderr | 3 +- .../resolve/no-implicit-prelude-nested.stderr | 45 ++++++++++++------- tests/ui/resolve/no-implicit-prelude.stderr | 15 ++++--- tests/ui/resolve/privacy-enum-ctor.stderr | 12 +++-- .../resolve/resolve-primitive-fallback.stderr | 3 +- tests/ui/resolve/use_suggestion.stderr | 6 ++- .../resolve/use_suggestion_placement.stderr | 9 ++-- .../dbg-macro-requires-debug.stderr | 3 +- .../derive-const-non-const-type.stderr | 3 +- .../issue-52202-use-suggestions.stderr | 12 +++-- .../rust-2018/trait-import-suggestions.stderr | 9 ++-- .../uniform-paths/issue-87932.stderr | 3 +- .../future-prelude-collision-shadow.stderr | 6 ++- tests/ui/self/class-missing-self.stderr | 3 +- .../ui/shadowed/shadowed-trait-methods.stderr | 3 +- ...incompatible-closure-captures-96258.stderr | 3 +- tests/ui/span/issue-35987.stderr | 1 + tests/ui/span/issue-71363.stderr | 3 +- tests/ui/specialization/issue-59435.stderr | 3 +- .../structs/struct-path-alias-bounds.stderr | 3 +- ...n-unconstrained-borrowed-type-param.stderr | 3 +- .../core-std-import-order-issue-83564.stderr | 6 ++- .../derive-macro-missing-bounds.stderr | 3 +- .../derive-trait-for-method-call.stderr | 9 ++-- .../dont-wrap-ambiguous-receivers.stderr | 6 ++- .../import-trait-for-method-call.stderr | 3 +- tests/ui/suggestions/invalid-bin-op.stderr | 3 +- .../suggestions/issue-84973-blacklist.stderr | 3 +- .../no-extern-crate-in-type.stderr | 3 +- .../raw-name-use-suggestion.stderr | 3 +- .../suggest-tryinto-edition-change.stderr | 21 ++++++--- .../suggestions/use-placement-resolve.stderr | 3 +- .../suggestions/use-placement-typeck.stderr | 3 +- .../impl-bound-with-references-error.stderr | 3 +- ...owed-path-in-trait-bound-suggestion.stderr | 3 +- .../supertrait-auto-trait.stderr | 3 +- tests/ui/traits/issue-71136.stderr | 3 +- tests/ui/traits/issue-78372.stderr | 3 +- tests/ui/traits/item-privacy.stderr | 9 ++-- tests/ui/traits/method-private.stderr | 3 +- tests/ui/typeck/explain_clone_autoref.stderr | 3 +- tests/ui/typeck/issue-43189.stderr | 3 +- tests/ui/underscore-imports/shadow.stderr | 3 +- .../union-derive-clone.mirunsafeck.stderr | 6 ++- .../union-derive-clone.thirunsafeck.stderr | 6 ++- .../union/union-derive-eq.mirunsafeck.stderr | 3 +- .../union/union-derive-eq.thirunsafeck.stderr | 3 +- .../unresolved/unresolved-candidates.stderr | 3 +- tests/ui/wf/wf-const-type.stderr | 3 +- tests/ui/wf/wf-static-type.stderr | 3 +- .../where-clauses-method-unsatisfied.stderr | 3 +- .../where-clauses-unsatisfied.stderr | 3 +- 166 files changed, 634 insertions(+), 294 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 81e8bcbf7cd5..7b6d65511c15 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1832,6 +1832,12 @@ impl EmitterWriter { } let show_code_change = if has_deletion && !is_multiline { DisplaySuggestion::Diff + } else if let [part] = &parts[..] + && part.snippet.ends_with('\n') + && part.snippet.trim() == complete.trim() + { + // We are adding a line(s) of code before code that was already there. + DisplaySuggestion::Add } else if (parts.len() != 1 || parts[0].snippet.trim() != complete.trim()) && !is_multiline { @@ -1879,7 +1885,9 @@ impl EmitterWriter { row_num += line_end - line_start; } let mut unhighlighted_lines = Vec::new(); + let mut last_pos = 0; for (line_pos, (line, highlight_parts)) in lines.by_ref().zip(highlights).enumerate() { + last_pos = line_pos; debug!(%line_pos, %line, ?highlight_parts); // Remember lines that are not highlighted to hide them if needed @@ -1963,13 +1971,39 @@ impl EmitterWriter { is_multiline, ) } + if let DisplaySuggestion::Add = show_code_change { + // The suggestion adds an entire line of code, ending on a newline, so we'll also + // print the *following* line, to provide context of what we're advicing people to + // do. Otherwise you would only see contextless code that can be confused for + // already existing code, despite the colors and UI elements. + let file_lines = sm + .span_to_lines(span.primary_span().unwrap().shrink_to_hi()) + .expect("span_to_lines failed when emitting suggestion"); + let line_num = sm.lookup_char_pos(parts[0].span.lo()).line; + if let Some(line) = file_lines.file.get_line(line_num - 1) { + let line = normalize_whitespace(&line); + self.draw_code_line( + &mut buffer, + &mut row_num, + &[], + line_num + last_pos + 1, + &line, + DisplaySuggestion::None, + max_line_num_len, + &file_lines, + is_multiline, + ) + } + } // This offset and the ones below need to be signed to account for replacement code // that is shorter than the original code. let mut offsets: Vec<(usize, isize)> = Vec::new(); // Only show an underline in the suggestions if the suggestion is not the // entirety of the code being shown and the displayed code is not multiline. - if let DisplaySuggestion::Diff | DisplaySuggestion::Underline = show_code_change { + if let DisplaySuggestion::Diff | DisplaySuggestion::Underline | DisplaySuggestion::Add = + show_code_change + { draw_col_separator_no_space(&mut buffer, row_num, max_line_num_len + 1); for part in parts { let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display; @@ -2247,6 +2281,10 @@ impl EmitterWriter { } } buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle); + } else if let DisplaySuggestion::Add = show_code_change { + buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber); + buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); + buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle); } else { buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber); draw_col_separator(buffer, *row_num, max_line_num_len + 1); @@ -2281,6 +2319,7 @@ enum DisplaySuggestion { Underline, Diff, None, + Add, } impl FileWithAnnotatedLines { diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr index efdd56dd47d3..3c7e08ebeae8 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr @@ -6,11 +6,14 @@ LL | _n: PhantomData, | help: consider importing one of these items | -LL | use core::marker::PhantomData; +LL + use core::marker::PhantomData; +LL | trait TypeVal { | -LL | use serde::__private::PhantomData; +LL + use serde::__private::PhantomData; +LL | trait TypeVal { | -LL | use std::marker::PhantomData; +LL + use std::marker::PhantomData; +LL | trait TypeVal { | error[E0412]: cannot find type `VAL` in this scope diff --git a/src/tools/clippy/tests/ui/derivable_impls.stderr b/src/tools/clippy/tests/ui/derivable_impls.stderr index 81963c3be5b5..8089f5ea0fcb 100644 --- a/src/tools/clippy/tests/ui/derivable_impls.stderr +++ b/src/tools/clippy/tests/ui/derivable_impls.stderr @@ -14,7 +14,8 @@ LL | | } = help: remove the manual implementation... help: ...and instead derive it | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | struct FooDefault<'a> { | error: this `impl` can be derived @@ -30,7 +31,8 @@ LL | | } = help: remove the manual implementation... help: ...and instead derive it | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | struct TupleDefault(bool, i32, u64); | error: this `impl` can be derived @@ -46,7 +48,8 @@ LL | | } = help: remove the manual implementation... help: ...and instead derive it | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | struct StrDefault<'a>(&'a str); | error: this `impl` can be derived @@ -62,7 +65,8 @@ LL | | } = help: remove the manual implementation... help: ...and instead derive it | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | struct Y(u32); | error: this `impl` can be derived @@ -78,7 +82,8 @@ LL | | } = help: remove the manual implementation... help: ...and instead derive it | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | struct WithoutSelfCurly { | error: this `impl` can be derived @@ -94,7 +99,8 @@ LL | | } = help: remove the manual implementation... help: ...and instead derive it | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | struct WithoutSelfParan(bool); | error: this `impl` can be derived @@ -110,7 +116,8 @@ LL | | } = help: remove the manual implementation... help: ...and instead derive it | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | pub struct RepeatDefault1 { | error: this `impl` can be derived @@ -126,7 +133,8 @@ LL | | } = help: remove the manual implementation... help: ...and instead derive it... | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | pub enum SimpleEnum { | help: ...and mark the default variant | diff --git a/src/tools/clippy/tests/ui/new_without_default.stderr b/src/tools/clippy/tests/ui/new_without_default.stderr index 583dd327d6a5..9b0a2f6ca5bf 100644 --- a/src/tools/clippy/tests/ui/new_without_default.stderr +++ b/src/tools/clippy/tests/ui/new_without_default.stderr @@ -14,6 +14,7 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } +LL | impl Foo { | error: you should consider adding a `Default` implementation for `Bar` @@ -31,6 +32,7 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } +LL | impl Bar { | error: you should consider adding a `Default` implementation for `LtKo<'c>` @@ -48,6 +50,7 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } +LL | impl<'c> LtKo<'c> { | error: you should consider adding a `Default` implementation for `NewNotEqualToDerive` @@ -65,6 +68,7 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } +LL | impl NewNotEqualToDerive { | error: you should consider adding a `Default` implementation for `FooGenerics` @@ -82,6 +86,7 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } +LL | impl FooGenerics { | error: you should consider adding a `Default` implementation for `BarGenerics` @@ -99,6 +104,7 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } +LL | impl BarGenerics { | error: you should consider adding a `Default` implementation for `Foo` diff --git a/tests/ui/array-slice-vec/repeat_empty_ok.stderr b/tests/ui/array-slice-vec/repeat_empty_ok.stderr index 724bdcd920ab..e8bac04ac450 100644 --- a/tests/ui/array-slice-vec/repeat_empty_ok.stderr +++ b/tests/ui/array-slice-vec/repeat_empty_ok.stderr @@ -7,7 +7,8 @@ LL | let headers = [Header{value: &[]}; 128]; = note: the `Copy` trait is required because this value will be copied for each element of the array help: consider annotating `Header<'_>` with `#[derive(Copy)]` | -LL | #[derive(Copy)] +LL + #[derive(Copy)] +LL | pub struct Header<'a> { | error[E0277]: the trait bound `Header<'_>: Copy` is not satisfied @@ -19,7 +20,8 @@ LL | let headers = [Header{value: &[0]}; 128]; = note: the `Copy` trait is required because this value will be copied for each element of the array help: consider annotating `Header<'_>` with `#[derive(Copy)]` | -LL | #[derive(Copy)] +LL + #[derive(Copy)] +LL | pub struct Header<'a> { | error: aborting due to 2 previous errors diff --git a/tests/ui/associated-types/defaults-suitability.stderr b/tests/ui/associated-types/defaults-suitability.stderr index 2485758757b9..4b2094691f8c 100644 --- a/tests/ui/associated-types/defaults-suitability.stderr +++ b/tests/ui/associated-types/defaults-suitability.stderr @@ -11,7 +11,8 @@ LL | type Ty: Clone = NotClone; | ^^^^^ required by this bound in `Tr::Ty` help: consider annotating `NotClone` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | struct NotClone; | error[E0277]: the trait bound `NotClone: Clone` is not satisfied @@ -30,7 +31,8 @@ LL | type Ty = NotClone; | -- required by a bound in this associated type help: consider annotating `NotClone` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | struct NotClone; | error[E0277]: the trait bound `T: Clone` is not satisfied diff --git a/tests/ui/binop/issue-28837.stderr b/tests/ui/binop/issue-28837.stderr index cca1da3b6ac4..bb9f3b8af0ff 100644 --- a/tests/ui/binop/issue-28837.stderr +++ b/tests/ui/binop/issue-28837.stderr @@ -157,7 +157,8 @@ LL | struct A; | ^^^^^^^^ must implement `PartialEq<_>` help: consider annotating `A` with `#[derive(PartialEq)]` | -LL | #[derive(PartialEq)] +LL + #[derive(PartialEq)] +LL | struct A; | error[E0369]: binary operation `!=` cannot be applied to type `A` @@ -175,7 +176,8 @@ LL | struct A; | ^^^^^^^^ must implement `PartialEq<_>` help: consider annotating `A` with `#[derive(PartialEq)]` | -LL | #[derive(PartialEq)] +LL + #[derive(PartialEq)] +LL | struct A; | error[E0369]: binary operation `<` cannot be applied to type `A` @@ -193,7 +195,8 @@ LL | struct A; | ^^^^^^^^ must implement `PartialOrd<_>` help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | -LL | #[derive(PartialEq, PartialOrd)] +LL + #[derive(PartialEq, PartialOrd)] +LL | struct A; | error[E0369]: binary operation `<=` cannot be applied to type `A` @@ -211,7 +214,8 @@ LL | struct A; | ^^^^^^^^ must implement `PartialOrd<_>` help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | -LL | #[derive(PartialEq, PartialOrd)] +LL + #[derive(PartialEq, PartialOrd)] +LL | struct A; | error[E0369]: binary operation `>` cannot be applied to type `A` @@ -229,7 +233,8 @@ LL | struct A; | ^^^^^^^^ must implement `PartialOrd<_>` help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | -LL | #[derive(PartialEq, PartialOrd)] +LL + #[derive(PartialEq, PartialOrd)] +LL | struct A; | error[E0369]: binary operation `>=` cannot be applied to type `A` @@ -247,7 +252,8 @@ LL | struct A; | ^^^^^^^^ must implement `PartialOrd<_>` help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | -LL | #[derive(PartialEq, PartialOrd)] +LL + #[derive(PartialEq, PartialOrd)] +LL | struct A; | error: aborting due to 15 previous errors diff --git a/tests/ui/box/unit/unique-pinned-nocopy.stderr b/tests/ui/box/unit/unique-pinned-nocopy.stderr index de6611324cac..2fd5b0d82e8f 100644 --- a/tests/ui/box/unit/unique-pinned-nocopy.stderr +++ b/tests/ui/box/unit/unique-pinned-nocopy.stderr @@ -19,7 +19,8 @@ LL | let _j = i.clone(); candidate #1: `Clone` help: consider annotating `R` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | struct R { | error: aborting due to previous error diff --git a/tests/ui/coherence/coherence_inherent.stderr b/tests/ui/coherence/coherence_inherent.stderr index 46b128c08fef..48f70700046f 100644 --- a/tests/ui/coherence/coherence_inherent.stderr +++ b/tests/ui/coherence/coherence_inherent.stderr @@ -7,7 +7,8 @@ LL | s.the_fn(); = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use Lib::TheTrait; +LL + use Lib::TheTrait; +LL | use Lib::TheStruct; | error: aborting due to previous error diff --git a/tests/ui/coherence/coherence_inherent_cc.stderr b/tests/ui/coherence/coherence_inherent_cc.stderr index af0ef3b69326..58254740f82e 100644 --- a/tests/ui/coherence/coherence_inherent_cc.stderr +++ b/tests/ui/coherence/coherence_inherent_cc.stderr @@ -7,7 +7,8 @@ LL | s.the_fn(); = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use coherence_inherent_cc_lib::TheTrait; +LL + use coherence_inherent_cc_lib::TheTrait; +LL | use coherence_inherent_cc_lib::TheStruct; | error: aborting due to previous error diff --git a/tests/ui/const-generics/generic_const_exprs/issue-94287.stderr b/tests/ui/const-generics/generic_const_exprs/issue-94287.stderr index 7390a007742f..1e4e4edb596b 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-94287.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-94287.stderr @@ -8,6 +8,7 @@ LL | If<{ FRAC <= 32 }>: True, help: consider enabling this feature --> $DIR/issue-94287.rs:1:1 | +LL + #![feature(generic_const_exprs)] LL | #![feature(generic_const_exprs)] | diff --git a/tests/ui/const-generics/issues/issue-82956.stderr b/tests/ui/const-generics/issues/issue-82956.stderr index d2320293e857..d1d507325510 100644 --- a/tests/ui/const-generics/issues/issue-82956.stderr +++ b/tests/ui/const-generics/issues/issue-82956.stderr @@ -6,13 +6,17 @@ LL | let mut iter = IntoIter::new(self); | help: consider importing one of these items | -LL | use std::array::IntoIter; +LL + use std::array::IntoIter; +LL | pub struct ConstCheck; | -LL | use std::collections::binary_heap::IntoIter; +LL + use std::collections::binary_heap::IntoIter; +LL | pub struct ConstCheck; | -LL | use std::collections::btree_map::IntoIter; +LL + use std::collections::btree_map::IntoIter; +LL | pub struct ConstCheck; | -LL | use std::collections::btree_set::IntoIter; +LL + use std::collections::btree_set::IntoIter; +LL | pub struct ConstCheck; | and 8 other candidates diff --git a/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr b/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr index ee352700c307..174103eeba4c 100644 --- a/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr +++ b/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr @@ -10,7 +10,8 @@ LL | let _: [Option; 2] = [no_copy(); 2]; = help: create an inline `const` block, see RFC #2920 for more information help: consider annotating `Bar` with `#[derive(Copy)]` | -LL | #[derive(Copy)] +LL + #[derive(Copy)] +LL | struct Bar; | error: aborting due to previous error diff --git a/tests/ui/consts/const-blocks/migrate-fail.stderr b/tests/ui/consts/const-blocks/migrate-fail.stderr index 928ffd0839db..d1896f755d53 100644 --- a/tests/ui/consts/const-blocks/migrate-fail.stderr +++ b/tests/ui/consts/const-blocks/migrate-fail.stderr @@ -8,7 +8,8 @@ LL | let arr: [Option; 2] = [x; 2]; = note: the `Copy` trait is required because this value will be copied for each element of the array help: consider annotating `Bar` with `#[derive(Copy)]` | -LL | #[derive(Copy)] +LL + #[derive(Copy)] +LL | struct Bar; | error[E0277]: the trait bound `Bar: Copy` is not satisfied @@ -21,7 +22,8 @@ LL | let arr: [Option; 2] = [x; 2]; = note: the `Copy` trait is required because this value will be copied for each element of the array help: consider annotating `Bar` with `#[derive(Copy)]` | -LL | #[derive(Copy)] +LL + #[derive(Copy)] +LL | struct Bar; | error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-blocks/nll-fail.stderr b/tests/ui/consts/const-blocks/nll-fail.stderr index fede0084547c..807c964a51d6 100644 --- a/tests/ui/consts/const-blocks/nll-fail.stderr +++ b/tests/ui/consts/const-blocks/nll-fail.stderr @@ -8,7 +8,8 @@ LL | let arr: [Option; 2] = [x; 2]; = note: the `Copy` trait is required because this value will be copied for each element of the array help: consider annotating `Bar` with `#[derive(Copy)]` | -LL | #[derive(Copy)] +LL + #[derive(Copy)] +LL | struct Bar; | error[E0277]: the trait bound `Bar: Copy` is not satisfied @@ -21,7 +22,8 @@ LL | let arr: [Option; 2] = [x; 2]; = note: the `Copy` trait is required because this value will be copied for each element of the array help: consider annotating `Bar` with `#[derive(Copy)]` | -LL | #[derive(Copy)] +LL + #[derive(Copy)] +LL | struct Bar; | error: aborting due to 2 previous errors diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr index 778b0e55f662..7ec2508ca93a 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr +++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -22,11 +22,13 @@ LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } | help: if it is not part of the public API, make this function unstably const | -LL | #[rustc_const_unstable(feature = "...", issue = "...")] +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } | help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks | -LL | #[rustc_allow_const_fn_unstable(const_fn_floating_point_arithmetic)] +LL + #[rustc_allow_const_fn_unstable(const_fn_floating_point_arithmetic)] +LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } | error: `foo2_gated` is not yet stable as a const fn diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr index 0174cb77f332..72c1f175d1d6 100644 --- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -22,11 +22,13 @@ LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } | help: if it is not part of the public API, make this function unstably const | -LL | #[rustc_const_unstable(feature = "...", issue = "...")] +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } | help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks | -LL | #[rustc_allow_const_fn_unstable(const_fn_floating_point_arithmetic)] +LL + #[rustc_allow_const_fn_unstable(const_fn_floating_point_arithmetic)] +LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } | error: `foo2_gated` is not yet stable as a const fn diff --git a/tests/ui/derived-errors/issue-31997-1.stderr b/tests/ui/derived-errors/issue-31997-1.stderr index 2f4aabf84531..2ea3d910dbfa 100644 --- a/tests/ui/derived-errors/issue-31997-1.stderr +++ b/tests/ui/derived-errors/issue-31997-1.stderr @@ -6,7 +6,8 @@ LL | let mut map = HashMap::new(); | help: consider importing this struct | -LL | use std::collections::HashMap; +LL + use std::collections::HashMap; +LL | use std::io::prelude::*; | error: aborting due to previous error diff --git a/tests/ui/derives/derive-assoc-type-not-impl.stderr b/tests/ui/derives/derive-assoc-type-not-impl.stderr index 91b334b412bc..9f17c76c2ec6 100644 --- a/tests/ui/derives/derive-assoc-type-not-impl.stderr +++ b/tests/ui/derives/derive-assoc-type-not-impl.stderr @@ -23,7 +23,8 @@ LL | #[derive(Clone)] candidate #1: `Clone` help: consider annotating `NotClone` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | struct NotClone; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Clone-enum-struct-variant.stderr b/tests/ui/derives/derives-span-Clone-enum-struct-variant.stderr index 7326324b03cc..31ab589cf385 100644 --- a/tests/ui/derives/derives-span-Clone-enum-struct-variant.stderr +++ b/tests/ui/derives/derives-span-Clone-enum-struct-variant.stderr @@ -10,7 +10,8 @@ LL | x: Error = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Clone-enum.stderr b/tests/ui/derives/derives-span-Clone-enum.stderr index 229a4f7d9ff9..b5580c02f38f 100644 --- a/tests/ui/derives/derives-span-Clone-enum.stderr +++ b/tests/ui/derives/derives-span-Clone-enum.stderr @@ -10,7 +10,8 @@ LL | Error = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Clone-struct.stderr b/tests/ui/derives/derives-span-Clone-struct.stderr index 96bad9edad94..fbe7e3f8479d 100644 --- a/tests/ui/derives/derives-span-Clone-struct.stderr +++ b/tests/ui/derives/derives-span-Clone-struct.stderr @@ -10,7 +10,8 @@ LL | x: Error = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Clone-tuple-struct.stderr b/tests/ui/derives/derives-span-Clone-tuple-struct.stderr index b61341e57e67..639f4d542547 100644 --- a/tests/ui/derives/derives-span-Clone-tuple-struct.stderr +++ b/tests/ui/derives/derives-span-Clone-tuple-struct.stderr @@ -10,7 +10,8 @@ LL | Error = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr b/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr index 58a64a4f53bf..7ff6851f6555 100644 --- a/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr +++ b/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr @@ -12,7 +12,8 @@ LL | x: Error = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Debug)]` | -LL | #[derive(Debug)] +LL + #[derive(Debug)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Debug-enum.stderr b/tests/ui/derives/derives-span-Debug-enum.stderr index e9bb5f960b04..346cbec90a94 100644 --- a/tests/ui/derives/derives-span-Debug-enum.stderr +++ b/tests/ui/derives/derives-span-Debug-enum.stderr @@ -12,7 +12,8 @@ LL | Error = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Debug)]` | -LL | #[derive(Debug)] +LL + #[derive(Debug)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Debug-struct.stderr b/tests/ui/derives/derives-span-Debug-struct.stderr index 0a117c060ff3..4b39eeb09ee8 100644 --- a/tests/ui/derives/derives-span-Debug-struct.stderr +++ b/tests/ui/derives/derives-span-Debug-struct.stderr @@ -12,7 +12,8 @@ LL | x: Error = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Debug)]` | -LL | #[derive(Debug)] +LL + #[derive(Debug)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Debug-tuple-struct.stderr b/tests/ui/derives/derives-span-Debug-tuple-struct.stderr index f2e90a418455..f3043abcadd2 100644 --- a/tests/ui/derives/derives-span-Debug-tuple-struct.stderr +++ b/tests/ui/derives/derives-span-Debug-tuple-struct.stderr @@ -12,7 +12,8 @@ LL | Error = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Debug)]` | -LL | #[derive(Debug)] +LL + #[derive(Debug)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Default-struct.stderr b/tests/ui/derives/derives-span-Default-struct.stderr index d4affd535eef..4844b6359240 100644 --- a/tests/ui/derives/derives-span-Default-struct.stderr +++ b/tests/ui/derives/derives-span-Default-struct.stderr @@ -10,7 +10,8 @@ LL | x: Error = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Default)]` | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Default-tuple-struct.stderr b/tests/ui/derives/derives-span-Default-tuple-struct.stderr index 129351f59989..9cac7f10780f 100644 --- a/tests/ui/derives/derives-span-Default-tuple-struct.stderr +++ b/tests/ui/derives/derives-span-Default-tuple-struct.stderr @@ -10,7 +10,8 @@ LL | Error = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Default)]` | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Eq-enum-struct-variant.stderr b/tests/ui/derives/derives-span-Eq-enum-struct-variant.stderr index 2be69a30b1c1..1a9ff9832557 100644 --- a/tests/ui/derives/derives-span-Eq-enum-struct-variant.stderr +++ b/tests/ui/derives/derives-span-Eq-enum-struct-variant.stderr @@ -12,7 +12,8 @@ note: required by a bound in `AssertParamIsEq` = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Eq)]` | -LL | #[derive(Eq)] +LL + #[derive(Eq)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Eq-enum.stderr b/tests/ui/derives/derives-span-Eq-enum.stderr index 4f4f821cca3e..8205657bb710 100644 --- a/tests/ui/derives/derives-span-Eq-enum.stderr +++ b/tests/ui/derives/derives-span-Eq-enum.stderr @@ -12,7 +12,8 @@ note: required by a bound in `AssertParamIsEq` = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Eq)]` | -LL | #[derive(Eq)] +LL + #[derive(Eq)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Eq-struct.stderr b/tests/ui/derives/derives-span-Eq-struct.stderr index f15659c3e166..af510181df7d 100644 --- a/tests/ui/derives/derives-span-Eq-struct.stderr +++ b/tests/ui/derives/derives-span-Eq-struct.stderr @@ -12,7 +12,8 @@ note: required by a bound in `AssertParamIsEq` = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Eq)]` | -LL | #[derive(Eq)] +LL + #[derive(Eq)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Eq-tuple-struct.stderr b/tests/ui/derives/derives-span-Eq-tuple-struct.stderr index 4e5659b35f47..f7c371d7d05a 100644 --- a/tests/ui/derives/derives-span-Eq-tuple-struct.stderr +++ b/tests/ui/derives/derives-span-Eq-tuple-struct.stderr @@ -12,7 +12,8 @@ note: required by a bound in `AssertParamIsEq` = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Eq)]` | -LL | #[derive(Eq)] +LL + #[derive(Eq)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Hash-enum-struct-variant.stderr b/tests/ui/derives/derives-span-Hash-enum-struct-variant.stderr index fe5e0e96ac7a..311edade0f3d 100644 --- a/tests/ui/derives/derives-span-Hash-enum-struct-variant.stderr +++ b/tests/ui/derives/derives-span-Hash-enum-struct-variant.stderr @@ -10,7 +10,8 @@ LL | x: Error = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Hash)]` | -LL | #[derive(Hash)] +LL + #[derive(Hash)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Hash-enum.stderr b/tests/ui/derives/derives-span-Hash-enum.stderr index 99785b87ca83..043aa954bfa1 100644 --- a/tests/ui/derives/derives-span-Hash-enum.stderr +++ b/tests/ui/derives/derives-span-Hash-enum.stderr @@ -10,7 +10,8 @@ LL | Error = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Hash)]` | -LL | #[derive(Hash)] +LL + #[derive(Hash)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Hash-struct.stderr b/tests/ui/derives/derives-span-Hash-struct.stderr index 4db83dd13001..26d31b6613fe 100644 --- a/tests/ui/derives/derives-span-Hash-struct.stderr +++ b/tests/ui/derives/derives-span-Hash-struct.stderr @@ -10,7 +10,8 @@ LL | x: Error = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Hash)]` | -LL | #[derive(Hash)] +LL + #[derive(Hash)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Hash-tuple-struct.stderr b/tests/ui/derives/derives-span-Hash-tuple-struct.stderr index 8660c97e69e1..3155a023ce8a 100644 --- a/tests/ui/derives/derives-span-Hash-tuple-struct.stderr +++ b/tests/ui/derives/derives-span-Hash-tuple-struct.stderr @@ -10,7 +10,8 @@ LL | Error = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Hash)]` | -LL | #[derive(Hash)] +LL + #[derive(Hash)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Ord-enum-struct-variant.stderr b/tests/ui/derives/derives-span-Ord-enum-struct-variant.stderr index 6e48332c2506..1a06aee5235a 100644 --- a/tests/ui/derives/derives-span-Ord-enum-struct-variant.stderr +++ b/tests/ui/derives/derives-span-Ord-enum-struct-variant.stderr @@ -10,7 +10,8 @@ LL | x: Error = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Ord)]` | -LL | #[derive(Ord)] +LL + #[derive(Ord)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Ord-enum.stderr b/tests/ui/derives/derives-span-Ord-enum.stderr index b05cf0a057b2..377728e8a7f6 100644 --- a/tests/ui/derives/derives-span-Ord-enum.stderr +++ b/tests/ui/derives/derives-span-Ord-enum.stderr @@ -10,7 +10,8 @@ LL | Error = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Ord)]` | -LL | #[derive(Ord)] +LL + #[derive(Ord)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Ord-struct.stderr b/tests/ui/derives/derives-span-Ord-struct.stderr index c4def34a83da..e00e990da2a5 100644 --- a/tests/ui/derives/derives-span-Ord-struct.stderr +++ b/tests/ui/derives/derives-span-Ord-struct.stderr @@ -10,7 +10,8 @@ LL | x: Error = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Ord)]` | -LL | #[derive(Ord)] +LL + #[derive(Ord)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-Ord-tuple-struct.stderr b/tests/ui/derives/derives-span-Ord-tuple-struct.stderr index a3b288d0fb9c..959d0b964040 100644 --- a/tests/ui/derives/derives-span-Ord-tuple-struct.stderr +++ b/tests/ui/derives/derives-span-Ord-tuple-struct.stderr @@ -10,7 +10,8 @@ LL | Error = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(Ord)]` | -LL | #[derive(Ord)] +LL + #[derive(Ord)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr b/tests/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr index 9953154fd4b7..9fc25f2ade42 100644 --- a/tests/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr +++ b/tests/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr @@ -15,7 +15,8 @@ LL | struct Error; = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(PartialEq)]` | -LL | #[derive(PartialEq)] +LL + #[derive(PartialEq)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-PartialEq-enum.stderr b/tests/ui/derives/derives-span-PartialEq-enum.stderr index 7c130452301d..f56e784478d5 100644 --- a/tests/ui/derives/derives-span-PartialEq-enum.stderr +++ b/tests/ui/derives/derives-span-PartialEq-enum.stderr @@ -15,7 +15,8 @@ LL | struct Error; = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(PartialEq)]` | -LL | #[derive(PartialEq)] +LL + #[derive(PartialEq)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-PartialEq-struct.stderr b/tests/ui/derives/derives-span-PartialEq-struct.stderr index ba3d6ced3f49..76c0b0104afb 100644 --- a/tests/ui/derives/derives-span-PartialEq-struct.stderr +++ b/tests/ui/derives/derives-span-PartialEq-struct.stderr @@ -15,7 +15,8 @@ LL | struct Error; = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(PartialEq)]` | -LL | #[derive(PartialEq)] +LL + #[derive(PartialEq)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-PartialEq-tuple-struct.stderr b/tests/ui/derives/derives-span-PartialEq-tuple-struct.stderr index ab0b56a9eefb..7dae01dbb991 100644 --- a/tests/ui/derives/derives-span-PartialEq-tuple-struct.stderr +++ b/tests/ui/derives/derives-span-PartialEq-tuple-struct.stderr @@ -15,7 +15,8 @@ LL | struct Error; = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(PartialEq)]` | -LL | #[derive(PartialEq)] +LL + #[derive(PartialEq)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr b/tests/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr index 2d19aaf68afb..746c1d5d21fd 100644 --- a/tests/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr +++ b/tests/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr @@ -11,7 +11,8 @@ LL | x: Error = note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(PartialOrd)]` | -LL | #[derive(PartialOrd)] +LL + #[derive(PartialOrd)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-PartialOrd-enum.stderr b/tests/ui/derives/derives-span-PartialOrd-enum.stderr index dfbb8060ffa1..8af1776dac87 100644 --- a/tests/ui/derives/derives-span-PartialOrd-enum.stderr +++ b/tests/ui/derives/derives-span-PartialOrd-enum.stderr @@ -11,7 +11,8 @@ LL | Error = note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(PartialOrd)]` | -LL | #[derive(PartialOrd)] +LL + #[derive(PartialOrd)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-PartialOrd-struct.stderr b/tests/ui/derives/derives-span-PartialOrd-struct.stderr index ba63d86e8e46..11ea7f9dc31b 100644 --- a/tests/ui/derives/derives-span-PartialOrd-struct.stderr +++ b/tests/ui/derives/derives-span-PartialOrd-struct.stderr @@ -11,7 +11,8 @@ LL | x: Error = note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(PartialOrd)]` | -LL | #[derive(PartialOrd)] +LL + #[derive(PartialOrd)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/derives-span-PartialOrd-tuple-struct.stderr b/tests/ui/derives/derives-span-PartialOrd-tuple-struct.stderr index 7686ed8064e7..0a41a3db31ea 100644 --- a/tests/ui/derives/derives-span-PartialOrd-tuple-struct.stderr +++ b/tests/ui/derives/derives-span-PartialOrd-tuple-struct.stderr @@ -11,7 +11,8 @@ LL | Error = note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(PartialOrd)]` | -LL | #[derive(PartialOrd)] +LL + #[derive(PartialOrd)] +LL | struct Error; | error: aborting due to previous error diff --git a/tests/ui/derives/deriving-no-inner-impl-error-message.stderr b/tests/ui/derives/deriving-no-inner-impl-error-message.stderr index ef8c44caacfa..10af5d36ed93 100644 --- a/tests/ui/derives/deriving-no-inner-impl-error-message.stderr +++ b/tests/ui/derives/deriving-no-inner-impl-error-message.stderr @@ -15,7 +15,8 @@ LL | struct NoCloneOrEq; = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `NoCloneOrEq` with `#[derive(PartialEq)]` | -LL | #[derive(PartialEq)] +LL + #[derive(PartialEq)] +LL | struct NoCloneOrEq; | error[E0277]: the trait bound `NoCloneOrEq: Clone` is not satisfied @@ -30,7 +31,8 @@ LL | x: NoCloneOrEq = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `NoCloneOrEq` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | struct NoCloneOrEq; | error: aborting due to 2 previous errors diff --git a/tests/ui/derives/deriving-with-repr-packed-2.stderr b/tests/ui/derives/deriving-with-repr-packed-2.stderr index ab3646057a55..afeca9fec2b8 100644 --- a/tests/ui/derives/deriving-with-repr-packed-2.stderr +++ b/tests/ui/derives/deriving-with-repr-packed-2.stderr @@ -25,7 +25,8 @@ LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] | ^^^^^ unsatisfied trait bound introduced in this `derive` macro help: consider annotating `NonCopy` with `#[derive(Clone, Copy)]` | -LL | #[derive(Clone, Copy)] +LL + #[derive(Clone, Copy)] +LL | struct NonCopy; | error: aborting due to previous error diff --git a/tests/ui/derives/issue-91492.stderr b/tests/ui/derives/issue-91492.stderr index cee30ac50a6a..fc64828b1533 100644 --- a/tests/ui/derives/issue-91492.stderr +++ b/tests/ui/derives/issue-91492.stderr @@ -11,7 +11,8 @@ LL | foo.extend_from_slice(bar); `NoDerives: Clone` help: consider annotating `NoDerives` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | pub struct NoDerives; | error[E0599]: the method `extend_from_slice` exists for mutable reference `&mut Vec`, but its trait bounds were not satisfied @@ -27,7 +28,8 @@ LL | foo.extend_from_slice(bar); `SomeDerives: Clone` help: consider annotating `SomeDerives` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | pub struct SomeDerives; | error[E0599]: the method `use_clone` exists for struct `Object`, but its trait bounds were not satisfied @@ -51,7 +53,8 @@ LL | impl Object { | unsatisfied trait bound introduced here help: consider annotating `NoDerives` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | pub struct NoDerives; | error: aborting due to 3 previous errors diff --git a/tests/ui/derives/issue-91550.stderr b/tests/ui/derives/issue-91550.stderr index af03f0e5e5f4..1324b80b5fcd 100644 --- a/tests/ui/derives/issue-91550.stderr +++ b/tests/ui/derives/issue-91550.stderr @@ -18,7 +18,8 @@ LL | hs.insert(Value(0)); `Value: Hash` help: consider annotating `Value` with `#[derive(Eq, Hash, PartialEq)]` | -LL | #[derive(Eq, Hash, PartialEq)] +LL + #[derive(Eq, Hash, PartialEq)] +LL | struct Value(u32); | error[E0599]: the method `use_eq` exists for struct `Object`, but its trait bounds were not satisfied @@ -48,7 +49,8 @@ LL | impl Object { which is required by `NoDerives: Eq` help: consider annotating `NoDerives` with `#[derive(Eq, PartialEq)]` | -LL | #[derive(Eq, PartialEq)] +LL + #[derive(Eq, PartialEq)] +LL | pub struct NoDerives; | error[E0599]: the method `use_ord` exists for struct `Object`, but its trait bounds were not satisfied @@ -84,7 +86,8 @@ LL | impl Object { which is required by `NoDerives: Ord` help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]` | -LL | #[derive(Eq, Ord, PartialEq, PartialOrd)] +LL + #[derive(Eq, Ord, PartialEq, PartialOrd)] +LL | pub struct NoDerives; | error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object`, but its trait bounds were not satisfied @@ -123,7 +126,8 @@ LL | impl Object { which is required by `NoDerives: PartialOrd` help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]` | -LL | #[derive(Eq, Ord, PartialEq, PartialOrd)] +LL + #[derive(Eq, Ord, PartialEq, PartialOrd)] +LL | pub struct NoDerives; | error: aborting due to 4 previous errors diff --git a/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr b/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr index abc040c0546b..11cdcfadef36 100644 --- a/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr +++ b/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr @@ -24,13 +24,17 @@ LL | fn setup() -> Set { Set } | help: consider importing one of these items | -LL | use AffixHeart::Set; +LL + use AffixHeart::Set; +LL | enum PutDown { Set } | -LL | use CauseToBe::Set; +LL + use CauseToBe::Set; +LL | enum PutDown { Set } | -LL | use Determine::Set; +LL + use Determine::Set; +LL | enum PutDown { Set } | -LL | use PutDown::Set; +LL + use PutDown::Set; +LL | enum PutDown { Set } | and 3 other candidates diff --git a/tests/ui/error-codes/E0277-3.stderr b/tests/ui/error-codes/E0277-3.stderr index 0127e1ccc81e..0d4782935df4 100644 --- a/tests/ui/error-codes/E0277-3.stderr +++ b/tests/ui/error-codes/E0277-3.stderr @@ -14,7 +14,8 @@ LL | fn foo(_: T) {} | ^^^^^^^^^ required by this bound in `foo` help: consider annotating `S` with `#[derive(PartialEq)]` | -LL | #[derive(PartialEq)] +LL + #[derive(PartialEq)] +LL | struct S; | error: aborting due to previous error diff --git a/tests/ui/fmt/format-args-argument-span.stderr b/tests/ui/fmt/format-args-argument-span.stderr index b060b2cd3393..4e2702383d6c 100644 --- a/tests/ui/fmt/format-args-argument-span.stderr +++ b/tests/ui/fmt/format-args-argument-span.stderr @@ -29,7 +29,8 @@ LL | println!("{x} {x:?} {x}"); = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `DisplayOnly` with `#[derive(Debug)]` | -LL | #[derive(Debug)] +LL + #[derive(Debug)] +LL | struct DisplayOnly; | error[E0277]: `DisplayOnly` doesn't implement `Debug` @@ -43,7 +44,8 @@ LL | println!("{x} {x:?} {x}", x = DisplayOnly); = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `DisplayOnly` with `#[derive(Debug)]` | -LL | #[derive(Debug)] +LL + #[derive(Debug)] +LL | struct DisplayOnly; | error: aborting due to 4 previous errors diff --git a/tests/ui/generator/clone-impl.stderr b/tests/ui/generator/clone-impl.stderr index a92646b198cf..64eb47c1a5a0 100644 --- a/tests/ui/generator/clone-impl.stderr +++ b/tests/ui/generator/clone-impl.stderr @@ -110,7 +110,8 @@ LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` help: consider annotating `NonClone` with `#[derive(Copy)]` | -LL | #[derive(Copy)] +LL + #[derive(Copy)] +LL | struct NonClone; | error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `[generator@$DIR/clone-impl.rs:62:25: 62:32]` @@ -134,7 +135,8 @@ LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` help: consider annotating `NonClone` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | struct NonClone; | error: aborting due to 6 previous errors diff --git a/tests/ui/generic-associated-types/issue-87429-associated-type-default.stderr b/tests/ui/generic-associated-types/issue-87429-associated-type-default.stderr index b1abe012be23..a44bb6993d49 100644 --- a/tests/ui/generic-associated-types/issue-87429-associated-type-default.stderr +++ b/tests/ui/generic-associated-types/issue-87429-associated-type-default.stderr @@ -12,7 +12,8 @@ LL | type Member<'a>: for<'b> PartialEq> = Foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Family2::Member` help: consider annotating `Foo` with `#[derive(PartialEq)]` | -LL | #[derive(PartialEq)] +LL + #[derive(PartialEq)] +LL | struct Foo; | error: aborting due to previous error diff --git a/tests/ui/generic-associated-types/issue-87429-specialization.stderr b/tests/ui/generic-associated-types/issue-87429-specialization.stderr index 11c4ebf604e7..c259c89a712e 100644 --- a/tests/ui/generic-associated-types/issue-87429-specialization.stderr +++ b/tests/ui/generic-associated-types/issue-87429-specialization.stderr @@ -22,7 +22,8 @@ LL | type Member<'a>: for<'b> PartialEq>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Family::Member` help: consider annotating `Foo` with `#[derive(PartialEq)]` | -LL | #[derive(PartialEq)] +LL + #[derive(PartialEq)] +LL | struct Foo; | error: aborting due to previous error; 1 warning emitted diff --git a/tests/ui/hygiene/globs.stderr b/tests/ui/hygiene/globs.stderr index c01901be5fe7..b68950b66dba 100644 --- a/tests/ui/hygiene/globs.stderr +++ b/tests/ui/hygiene/globs.stderr @@ -13,7 +13,8 @@ LL | g(); | ~ help: consider importing this function | -LL | use foo::f; +LL + use foo::f; +LL | mod foo { | error[E0425]: cannot find function `g` in this scope @@ -39,7 +40,8 @@ LL | f(); | ~ help: consider importing this function | -LL | use bar::g; +LL + use bar::g; +LL | mod foo { | error[E0425]: cannot find function `f` in this scope diff --git a/tests/ui/hygiene/no_implicit_prelude.stderr b/tests/ui/hygiene/no_implicit_prelude.stderr index c48c840352fa..21cecfefd349 100644 --- a/tests/ui/hygiene/no_implicit_prelude.stderr +++ b/tests/ui/hygiene/no_implicit_prelude.stderr @@ -10,7 +10,8 @@ LL | Vec::new(); = note: this error originates in the macro `::bar::m` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this struct | -LL | use std::vec::Vec; +LL + use std::vec::Vec; +LL | pub macro m() { Vec::::new(); ().clone() } | error[E0599]: no method named `clone` found for unit type `()` in the current scope @@ -26,7 +27,8 @@ LL | ().clone() = note: this error originates in the macro `::bar::m` (in Nightly builds, run with -Z macro-backtrace for more info) help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use std::clone::Clone; +LL + use std::clone::Clone; +LL | pub macro m() { Vec::::new(); ().clone() } | error: aborting due to 2 previous errors diff --git a/tests/ui/hygiene/trait_items.stderr b/tests/ui/hygiene/trait_items.stderr index 80bdbe0e21e0..60cf6787f82f 100644 --- a/tests/ui/hygiene/trait_items.stderr +++ b/tests/ui/hygiene/trait_items.stderr @@ -14,7 +14,8 @@ LL | pub macro m() { ().f() } = note: this error originates in the macro `::baz::m` (in Nightly builds, run with -Z macro-backtrace for more info) help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use foo::T; +LL + use foo::T; +LL | use foo::*; | error: aborting due to previous error diff --git a/tests/ui/impl-trait/no-method-suggested-traits.stderr b/tests/ui/impl-trait/no-method-suggested-traits.stderr index 3c2c01dc227b..0d37ea38b58c 100644 --- a/tests/ui/impl-trait/no-method-suggested-traits.stderr +++ b/tests/ui/impl-trait/no-method-suggested-traits.stderr @@ -7,13 +7,17 @@ LL | 1u32.method(); = help: items from traits can only be used if the trait is in scope help: the following traits are implemented but not in scope; perhaps add a `use` for one of them: | -LL | use foo::Bar; +LL + use foo::Bar; +LL | extern crate no_method_suggested_traits; | -LL | use no_method_suggested_traits::Reexported; +LL + use no_method_suggested_traits::Reexported; +LL | extern crate no_method_suggested_traits; | -LL | use no_method_suggested_traits::foo::PubPub; +LL + use no_method_suggested_traits::foo::PubPub; +LL | extern crate no_method_suggested_traits; | -LL | use no_method_suggested_traits::qux::PrivPub; +LL + use no_method_suggested_traits::qux::PrivPub; +LL | extern crate no_method_suggested_traits; | error[E0599]: no method named `method` found for struct `Rc<&mut Box<&u32>>` in the current scope @@ -25,13 +29,17 @@ LL | std::rc::Rc::new(&mut Box::new(&1u32)).method(); = help: items from traits can only be used if the trait is in scope help: the following traits are implemented but not in scope; perhaps add a `use` for one of them: | -LL | use foo::Bar; +LL + use foo::Bar; +LL | extern crate no_method_suggested_traits; | -LL | use no_method_suggested_traits::Reexported; +LL + use no_method_suggested_traits::Reexported; +LL | extern crate no_method_suggested_traits; | -LL | use no_method_suggested_traits::foo::PubPub; +LL + use no_method_suggested_traits::foo::PubPub; +LL | extern crate no_method_suggested_traits; | -LL | use no_method_suggested_traits::qux::PrivPub; +LL + use no_method_suggested_traits::qux::PrivPub; +LL | extern crate no_method_suggested_traits; | error[E0599]: no method named `method` found for type `char` in the current scope @@ -46,7 +54,8 @@ LL | 'a'.method(); = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use foo::Bar; +LL + use foo::Bar; +LL | extern crate no_method_suggested_traits; | error[E0599]: no method named `method` found for struct `Rc<&mut Box<&char>>` in the current scope @@ -58,7 +67,8 @@ LL | std::rc::Rc::new(&mut Box::new(&'a')).method(); = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use foo::Bar; +LL + use foo::Bar; +LL | extern crate no_method_suggested_traits; | error[E0599]: no method named `method` found for type `i32` in the current scope @@ -75,7 +85,8 @@ LL | fn method(&self) {} = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use no_method_suggested_traits::foo::PubPub; +LL + use no_method_suggested_traits::foo::PubPub; +LL | extern crate no_method_suggested_traits; | error[E0599]: no method named `method` found for struct `Rc<&mut Box<&i32>>` in the current scope @@ -87,7 +98,8 @@ LL | std::rc::Rc::new(&mut Box::new(&1i32)).method(); = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use no_method_suggested_traits::foo::PubPub; +LL + use no_method_suggested_traits::foo::PubPub; +LL | extern crate no_method_suggested_traits; | error[E0599]: no method named `method` found for struct `Foo` in the current scope diff --git a/tests/ui/impl-trait/universal_wrong_bounds.stderr b/tests/ui/impl-trait/universal_wrong_bounds.stderr index 3b1a5e5f4ad0..1561708efba3 100644 --- a/tests/ui/impl-trait/universal_wrong_bounds.stderr +++ b/tests/ui/impl-trait/universal_wrong_bounds.stderr @@ -6,7 +6,8 @@ LL | fn wants_debug(g: impl Debug) { } | help: consider importing this trait instead | -LL | use std::fmt::Debug; +LL + use std::fmt::Debug; +LL | use std::fmt::Display; | error[E0404]: expected trait, found derive macro `Debug` @@ -17,7 +18,8 @@ LL | fn wants_display(g: impl Debug) { } | help: consider importing this trait instead | -LL | use std::fmt::Debug; +LL + use std::fmt::Debug; +LL | use std::fmt::Display; | error: aborting due to 2 previous errors diff --git a/tests/ui/imports/glob-resolve1.stderr b/tests/ui/imports/glob-resolve1.stderr index 3b66a5e31505..6d7ceb25a8fd 100644 --- a/tests/ui/imports/glob-resolve1.stderr +++ b/tests/ui/imports/glob-resolve1.stderr @@ -60,7 +60,8 @@ LL | import(); | help: consider importing this function | -LL | use other::import; +LL + use other::import; +LL | use bar::*; | error[E0412]: cannot find type `A` in this scope diff --git a/tests/ui/imports/issue-38293.stderr b/tests/ui/imports/issue-38293.stderr index d2450ab12506..7a3b405a7822 100644 --- a/tests/ui/imports/issue-38293.stderr +++ b/tests/ui/imports/issue-38293.stderr @@ -12,7 +12,8 @@ LL | baz(); | help: consider importing this function instead | -LL | use bar::baz; +LL + use bar::baz; +LL | use foo::f::{self}; | error: aborting due to 2 previous errors diff --git a/tests/ui/imports/issue-4366-2.stderr b/tests/ui/imports/issue-4366-2.stderr index 4c94634ee60f..d8539f9a9d4f 100644 --- a/tests/ui/imports/issue-4366-2.stderr +++ b/tests/ui/imports/issue-4366-2.stderr @@ -18,7 +18,8 @@ LL | foo(); | help: consider importing this function instead | -LL | use foo::foo; +LL + use foo::foo; +LL | use m1::*; | error: aborting due to 2 previous errors diff --git a/tests/ui/imports/issue-4366.stderr b/tests/ui/imports/issue-4366.stderr index 469ea93e9046..724db83e99ad 100644 --- a/tests/ui/imports/issue-4366.stderr +++ b/tests/ui/imports/issue-4366.stderr @@ -6,7 +6,8 @@ LL | fn sub() -> isize { foo(); 1 } | help: consider importing this function | -LL | use foo::foo; +LL + use foo::foo; +LL | use a::b::*; | error: aborting due to previous error diff --git a/tests/ui/imports/overlapping_pub_trait.stderr b/tests/ui/imports/overlapping_pub_trait.stderr index d0c845a5e523..268709e11b67 100644 --- a/tests/ui/imports/overlapping_pub_trait.stderr +++ b/tests/ui/imports/overlapping_pub_trait.stderr @@ -12,7 +12,8 @@ LL | pub trait Tr { fn method(&self); } = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use overlapping_pub_trait_source::m::Tr; +LL + use overlapping_pub_trait_source::m::Tr; +LL | extern crate overlapping_pub_trait_source; | error: aborting due to previous error diff --git a/tests/ui/imports/unnamed_pub_trait.stderr b/tests/ui/imports/unnamed_pub_trait.stderr index 319dfd7e1b28..47fa6d3a3988 100644 --- a/tests/ui/imports/unnamed_pub_trait.stderr +++ b/tests/ui/imports/unnamed_pub_trait.stderr @@ -12,7 +12,8 @@ LL | pub trait Tr { fn method(&self); } = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use unnamed_pub_trait_source::prelude::*; // trait Tr +LL + use unnamed_pub_trait_source::prelude::*; // trait Tr +LL | extern crate unnamed_pub_trait_source; | error: aborting due to previous error diff --git a/tests/ui/internal/internal-unstable-const.stderr b/tests/ui/internal/internal-unstable-const.stderr index 37d2ea6d2dc4..5c63992d8198 100644 --- a/tests/ui/internal/internal-unstable-const.stderr +++ b/tests/ui/internal/internal-unstable-const.stderr @@ -6,11 +6,13 @@ LL | 1.0 + 1.0 | help: if it is not part of the public API, make this function unstably const | -LL | #[rustc_const_unstable(feature = "...", issue = "...")] +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | pub const fn foo() -> f32 { | help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks | -LL | #[rustc_allow_const_fn_unstable(const_fn_floating_point_arithmetic)] +LL + #[rustc_allow_const_fn_unstable(const_fn_floating_point_arithmetic)] +LL | pub const fn foo() -> f32 { | error: aborting due to previous error diff --git a/tests/ui/issues/issue-10465.stderr b/tests/ui/issues/issue-10465.stderr index 0ccf69dc0607..9941e14a94e0 100644 --- a/tests/ui/issues/issue-10465.stderr +++ b/tests/ui/issues/issue-10465.stderr @@ -7,7 +7,8 @@ LL | b.foo(); = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use a::A; +LL + use a::A; +LL | use b::B; | error: aborting due to previous error diff --git a/tests/ui/issues/issue-17546.stderr b/tests/ui/issues/issue-17546.stderr index 81592320a279..23a12fa167b7 100644 --- a/tests/ui/issues/issue-17546.stderr +++ b/tests/ui/issues/issue-17546.stderr @@ -24,13 +24,17 @@ LL | fn new() -> Result { | help: consider importing one of these items instead | -LL | use std::fmt::Result; +LL + use std::fmt::Result; +LL | use foo::MyEnum::Result; | -LL | use std::io::Result; +LL + use std::io::Result; +LL | use foo::MyEnum::Result; | -LL | use std::result::Result; +LL + use std::result::Result; +LL | use foo::MyEnum::Result; | -LL | use std::thread::Result; +LL + use std::thread::Result; +LL | use foo::MyEnum::Result; | error[E0573]: expected type, found variant `Result` @@ -41,13 +45,17 @@ LL | fn new() -> Result { | help: consider importing one of these items instead | -LL | use std::fmt::Result; +LL + use std::fmt::Result; +LL | use foo::MyEnum::Result; | -LL | use std::io::Result; +LL + use std::io::Result; +LL | use foo::MyEnum::Result; | -LL | use std::result::Result; +LL + use std::result::Result; +LL | use foo::MyEnum::Result; | -LL | use std::thread::Result; +LL + use std::thread::Result; +LL | use foo::MyEnum::Result; | error[E0573]: expected type, found variant `NoResult` diff --git a/tests/ui/issues/issue-20162.stderr b/tests/ui/issues/issue-20162.stderr index 1c5b76fbfc10..ebdf2528fe1f 100644 --- a/tests/ui/issues/issue-20162.stderr +++ b/tests/ui/issues/issue-20162.stderr @@ -8,7 +8,8 @@ note: required by a bound in `slice::::sort` --> $SRC_DIR/alloc/src/slice.rs:LL:COL help: consider annotating `X` with `#[derive(Ord)]` | -LL | #[derive(Ord)] +LL + #[derive(Ord)] +LL | struct X { x: i32 } | error: aborting due to previous error diff --git a/tests/ui/issues/issue-21160.stderr b/tests/ui/issues/issue-21160.stderr index 266749376eb0..b39a3aad3719 100644 --- a/tests/ui/issues/issue-21160.stderr +++ b/tests/ui/issues/issue-21160.stderr @@ -9,7 +9,8 @@ LL | struct Foo(Bar); = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Bar` with `#[derive(Hash)]` | -LL | #[derive(Hash)] +LL + #[derive(Hash)] +LL | struct Bar; | error: aborting due to previous error diff --git a/tests/ui/issues/issue-35976.unimported.stderr b/tests/ui/issues/issue-35976.unimported.stderr index 5d61bb8ea379..8a3e2fcd0833 100644 --- a/tests/ui/issues/issue-35976.unimported.stderr +++ b/tests/ui/issues/issue-35976.unimported.stderr @@ -9,7 +9,8 @@ LL | arg.wait(); | help: another candidate was found in the following trait, perhaps add a `use` for it: | -LL | use private::Future; +LL + use private::Future; +LL | mod private { | error: aborting due to previous error diff --git a/tests/ui/issues/issue-37534.stderr b/tests/ui/issues/issue-37534.stderr index 895479986f1d..8449eb9c6925 100644 --- a/tests/ui/issues/issue-37534.stderr +++ b/tests/ui/issues/issue-37534.stderr @@ -6,7 +6,8 @@ LL | struct Foo { } | help: consider importing this trait instead | -LL | use std::hash::Hash; +LL + use std::hash::Hash; +LL | struct Foo { } | warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported diff --git a/tests/ui/issues/issue-39175.stderr b/tests/ui/issues/issue-39175.stderr index afceae82e68b..19e7f5162a77 100644 --- a/tests/ui/issues/issue-39175.stderr +++ b/tests/ui/issues/issue-39175.stderr @@ -7,7 +7,8 @@ LL | Command::new("echo").arg("hello").exec(); = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use std::os::unix::process::CommandExt; +LL + use std::os::unix::process::CommandExt; +LL | use std::process::Command; | error: aborting due to previous error diff --git a/tests/ui/issues/issue-56175.stderr b/tests/ui/issues/issue-56175.stderr index 013a440ed045..bedbaef29b9c 100644 --- a/tests/ui/issues/issue-56175.stderr +++ b/tests/ui/issues/issue-56175.stderr @@ -12,7 +12,8 @@ LL | fn trait_method(&self) { = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use reexported_trait::Trait; +LL + use reexported_trait::Trait; +LL | fn main() { | error[E0599]: no method named `trait_method_b` found for struct `FooStruct` in the current scope @@ -29,7 +30,8 @@ LL | fn trait_method_b(&self) { = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use reexported_trait::TraitBRename; +LL + use reexported_trait::TraitBRename; +LL | fn main() { | error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-62375.stderr b/tests/ui/issues/issue-62375.stderr index 478e025bed23..a6fd3700edda 100644 --- a/tests/ui/issues/issue-62375.stderr +++ b/tests/ui/issues/issue-62375.stderr @@ -13,7 +13,8 @@ LL | enum A { | ^^^^^^ must implement `PartialEq<_>` help: consider annotating `A` with `#[derive(PartialEq)]` | -LL | #[derive(PartialEq)] +LL + #[derive(PartialEq)] +LL | enum A { | error: aborting due to previous error diff --git a/tests/ui/issues/issue-77919.stderr b/tests/ui/issues/issue-77919.stderr index d154bfe0cb55..1f3f6cb33c7f 100644 --- a/tests/ui/issues/issue-77919.stderr +++ b/tests/ui/issues/issue-77919.stderr @@ -6,7 +6,8 @@ LL | _n: PhantomData, | help: consider importing this struct | -LL | use std::marker::PhantomData; +LL + use std::marker::PhantomData; +LL | fn main() { | error[E0412]: cannot find type `VAL` in this scope diff --git a/tests/ui/kindck/kindck-impl-type-params.stderr b/tests/ui/kindck/kindck-impl-type-params.stderr index 6fd1fc3f7a1a..efb25bf83e1d 100644 --- a/tests/ui/kindck/kindck-impl-type-params.stderr +++ b/tests/ui/kindck/kindck-impl-type-params.stderr @@ -107,7 +107,8 @@ LL | impl Gettable for S {} = note: required for the cast from `S` to the object type `dyn Gettable` help: consider annotating `Foo` with `#[derive(Copy)]` | -LL | #[derive(Copy)] +LL + #[derive(Copy)] +LL | struct Foo; // does not impl Copy | error: aborting due to 6 previous errors diff --git a/tests/ui/layout/issue-84108.stderr b/tests/ui/layout/issue-84108.stderr index 36be64241100..cdc21df79a7e 100644 --- a/tests/ui/layout/issue-84108.stderr +++ b/tests/ui/layout/issue-84108.stderr @@ -6,7 +6,8 @@ LL | static FOO: (dyn AsRef, u8) = ("hello", 42); | help: consider importing this struct | -LL | use std::ffi::OsStr; +LL + use std::ffi::OsStr; +LL | static FOO: (dyn AsRef, u8) = ("hello", 42); | error[E0412]: cannot find type `Path` in this scope @@ -17,7 +18,8 @@ LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42); | help: consider importing this struct | -LL | use std::path::Path; +LL + use std::path::Path; +LL | static FOO: (dyn AsRef, u8) = ("hello", 42); | error[E0277]: the size for values of type `[u8]` cannot be known at compilation time diff --git a/tests/ui/macros/issue-100199.stderr b/tests/ui/macros/issue-100199.stderr index 2cb45dc12473..ab6bc08b5f7c 100644 --- a/tests/ui/macros/issue-100199.stderr +++ b/tests/ui/macros/issue-100199.stderr @@ -7,7 +7,8 @@ LL | #[issue_100199::struct_with_bound] = note: this error originates in the attribute macro `issue_100199::struct_with_bound` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this trait | -LL | use traits::MyTrait; +LL + use traits::MyTrait; +LL | #[issue_100199::struct_with_bound] | error: aborting due to previous error diff --git a/tests/ui/macros/macro-outer-attributes.stderr b/tests/ui/macros/macro-outer-attributes.stderr index 4ea760ab82b9..cfd1c7739ba4 100644 --- a/tests/ui/macros/macro-outer-attributes.stderr +++ b/tests/ui/macros/macro-outer-attributes.stderr @@ -6,7 +6,8 @@ LL | a::bar(); | help: consider importing this function | -LL | use b::bar; +LL + use b::bar; +LL | macro_rules! test { ($nm:ident, | help: if you import `bar`, refer to it directly | diff --git a/tests/ui/malformed/malformed-derive-entry.stderr b/tests/ui/malformed/malformed-derive-entry.stderr index 6ff6fbabb4a5..3059d75d718a 100644 --- a/tests/ui/malformed/malformed-derive-entry.stderr +++ b/tests/ui/malformed/malformed-derive-entry.stderr @@ -27,7 +27,8 @@ note: required by a bound in `Copy` = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Test1` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | struct Test1; | error[E0277]: the trait bound `Test2: Clone` is not satisfied @@ -41,7 +42,8 @@ note: required by a bound in `Copy` = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Test2` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | struct Test2; | error: aborting due to 5 previous errors diff --git a/tests/ui/mismatched_types/method-help-unsatisfied-bound.stderr b/tests/ui/mismatched_types/method-help-unsatisfied-bound.stderr index d3b7525072ff..9dab3e522557 100644 --- a/tests/ui/mismatched_types/method-help-unsatisfied-bound.stderr +++ b/tests/ui/mismatched_types/method-help-unsatisfied-bound.stderr @@ -10,7 +10,8 @@ note: required by a bound in `Result::::unwrap` --> $SRC_DIR/core/src/result.rs:LL:COL help: consider annotating `Foo` with `#[derive(Debug)]` | -LL | #[derive(Debug)] +LL + #[derive(Debug)] +LL | struct Foo; | error: aborting due to previous error diff --git a/tests/ui/modules/issue-107649.stderr b/tests/ui/modules/issue-107649.stderr index 1cea71f2829f..38a910b57b47 100644 --- a/tests/ui/modules/issue-107649.stderr +++ b/tests/ui/modules/issue-107649.stderr @@ -10,7 +10,8 @@ error[E0277]: `Dummy` doesn't implement `Debug` help: consider annotating `Dummy` with `#[derive(Debug)]` --> $DIR/auxiliary/dummy_lib.rs:2:1 | -2 | #[derive(Debug)] +2 + #[derive(Debug)] +3 | #[path = "auxiliary/dummy_lib.rs"] | error: aborting due to previous error diff --git a/tests/ui/namespace/namespace-mix.stderr b/tests/ui/namespace/namespace-mix.stderr index cb72d4a1c429..216548180bc5 100644 --- a/tests/ui/namespace/namespace-mix.stderr +++ b/tests/ui/namespace/namespace-mix.stderr @@ -14,9 +14,11 @@ LL | check(m1::TS); | ~~ help: consider importing one of these items instead | -LL | use m2::S; +LL + use m2::S; +LL | use namespace_mix::*; | -LL | use xm2::S; +LL + use xm2::S; +LL | use namespace_mix::*; | help: if you import `S`, refer to it directly | @@ -42,9 +44,11 @@ LL | check(xm1::TS); | ~~ help: consider importing one of these items instead | -LL | use m2::S; +LL + use m2::S; +LL | use namespace_mix::*; | -LL | use xm2::S; +LL + use xm2::S; +LL | use namespace_mix::*; | help: if you import `S`, refer to it directly | @@ -68,9 +72,11 @@ LL | check(m7::TV); | ~~ help: consider importing one of these items instead | -LL | use m8::V; +LL + use m8::V; +LL | use namespace_mix::*; | -LL | use xm8::V; +LL + use xm8::V; +LL | use namespace_mix::*; | help: if you import `V`, refer to it directly | @@ -96,9 +102,11 @@ LL | check(xm7::TV); | ~~ help: consider importing one of these items instead | -LL | use m8::V; +LL + use m8::V; +LL | use namespace_mix::*; | -LL | use xm8::V; +LL + use xm8::V; +LL | use namespace_mix::*; | help: if you import `V`, refer to it directly | diff --git a/tests/ui/not-clone-closure.stderr b/tests/ui/not-clone-closure.stderr index 37d94cf0ebd8..db9307c61853 100644 --- a/tests/ui/not-clone-closure.stderr +++ b/tests/ui/not-clone-closure.stderr @@ -14,7 +14,8 @@ LL | let hello = move || { | ^^^^^^^ help: consider annotating `S` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | struct S(i32); | error: aborting due to previous error diff --git a/tests/ui/on-unimplemented/no-debug.stderr b/tests/ui/on-unimplemented/no-debug.stderr index 1035da54d8a7..97d67dbd82e7 100644 --- a/tests/ui/on-unimplemented/no-debug.stderr +++ b/tests/ui/on-unimplemented/no-debug.stderr @@ -9,7 +9,8 @@ LL | println!("{:?} {:?}", Foo, Bar); = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Foo` with `#[derive(Debug)]` | -LL | #[derive(Debug)] +LL + #[derive(Debug)] +LL | struct Foo; | error[E0277]: `Bar` doesn't implement `Debug` diff --git a/tests/ui/parser/circular_modules_main.stderr b/tests/ui/parser/circular_modules_main.stderr index 1094def6014a..2804c6ebf509 100644 --- a/tests/ui/parser/circular_modules_main.stderr +++ b/tests/ui/parser/circular_modules_main.stderr @@ -12,7 +12,8 @@ LL | println!("{}", circular_modules_main::hi_str()); | help: consider importing this function | -LL | use hi_str; +LL + use hi_str; +LL | #[path = "circular_modules_main.rs"] | help: if you import `hi_str`, refer to it directly | diff --git a/tests/ui/privacy/privacy-ns1.stderr b/tests/ui/privacy/privacy-ns1.stderr index 91bc84e70ac5..fe3e4a78a84b 100644 --- a/tests/ui/privacy/privacy-ns1.stderr +++ b/tests/ui/privacy/privacy-ns1.stderr @@ -13,7 +13,8 @@ LL | Baz(); | ~~~ help: consider importing this function instead | -LL | use foo2::Bar; +LL + use foo2::Bar; +LL | pub mod foo1 { | error[E0425]: cannot find function, tuple struct or tuple variant `Bar` in this scope @@ -31,7 +32,8 @@ LL | Baz(); | ~~~ help: consider importing this function | -LL | use foo2::Bar; +LL + use foo2::Bar; +LL | pub mod foo1 { | error[E0412]: cannot find type `Bar` in this scope @@ -49,7 +51,8 @@ LL | let _x: Box; | ~~~ help: consider importing this trait | -LL | use foo1::Bar; +LL + use foo1::Bar; +LL | pub mod foo1 { | error[E0747]: constant provided when a type was expected diff --git a/tests/ui/privacy/privacy-ns2.stderr b/tests/ui/privacy/privacy-ns2.stderr index 904e9013f94a..73a24bd20f33 100644 --- a/tests/ui/privacy/privacy-ns2.stderr +++ b/tests/ui/privacy/privacy-ns2.stderr @@ -6,7 +6,8 @@ LL | Bar(); | help: consider importing this function instead | -LL | use foo2::Bar; +LL + use foo2::Bar; +LL | pub mod foo1 { | error[E0423]: expected function, tuple struct or tuple variant, found trait `Bar` @@ -24,7 +25,8 @@ LL | Baz(); | ~~~ help: consider importing this function instead | -LL | use foo2::Bar; +LL + use foo2::Bar; +LL | pub mod foo1 { | error[E0573]: expected type, found function `Bar` @@ -39,7 +41,8 @@ LL | let _x = Bar(); | ~ help: consider importing this trait instead | -LL | use foo1::Bar; +LL + use foo1::Bar; +LL | pub mod foo1 { | error[E0603]: trait `Bar` is private diff --git a/tests/ui/proc-macro/amputate-span.stderr b/tests/ui/proc-macro/amputate-span.stderr index ab4670411446..fa83707e79d5 100644 --- a/tests/ui/proc-macro/amputate-span.stderr +++ b/tests/ui/proc-macro/amputate-span.stderr @@ -6,7 +6,8 @@ LL | Command::new("git"); | help: consider importing this struct | -LL | use std::process::Command; +LL + use std::process::Command; +LL | #[amputate_span::drop_first_token] | error[E0433]: failed to resolve: use of undeclared type `Command` @@ -17,7 +18,8 @@ LL | Command::new("git"); | help: consider importing this struct | -LL | use std::process::Command; +LL + use std::process::Command; +LL | #[amputate_span::drop_first_token] | error: aborting due to 2 previous errors diff --git a/tests/ui/proc-macro/attributes-on-modules-fail.stderr b/tests/ui/proc-macro/attributes-on-modules-fail.stderr index bb6cbb6984d7..a0ab9999c088 100644 --- a/tests/ui/proc-macro/attributes-on-modules-fail.stderr +++ b/tests/ui/proc-macro/attributes-on-modules-fail.stderr @@ -50,7 +50,8 @@ LL | type A = Y; | help: consider importing this struct | -LL | use Y; +LL + use Y; +LL | pub struct X; | error[E0412]: cannot find type `X` in this scope @@ -61,7 +62,8 @@ LL | type A = X; | help: consider importing this struct | -LL | use m::X; +LL + use m::X; +LL | #[macro_use] | error: aborting due to 7 previous errors diff --git a/tests/ui/repeat-expr/repeat-to-run-dtor-twice.stderr b/tests/ui/repeat-expr/repeat-to-run-dtor-twice.stderr index 36b93616375e..1bf8e6e062f2 100644 --- a/tests/ui/repeat-expr/repeat-to-run-dtor-twice.stderr +++ b/tests/ui/repeat-expr/repeat-to-run-dtor-twice.stderr @@ -7,7 +7,8 @@ LL | let _ = [ a; 5 ]; = note: the `Copy` trait is required because this value will be copied for each element of the array help: consider annotating `Foo` with `#[derive(Copy)]` | -LL | #[derive(Copy)] +LL + #[derive(Copy)] +LL | struct Foo { | error: aborting due to previous error diff --git a/tests/ui/resolve/crate-in-paths.stderr b/tests/ui/resolve/crate-in-paths.stderr index b7cf4950759e..45ecf5a59adf 100644 --- a/tests/ui/resolve/crate-in-paths.stderr +++ b/tests/ui/resolve/crate-in-paths.stderr @@ -6,7 +6,8 @@ LL | Foo; | help: consider importing this unit struct | -LL | use crate::bar::Foo; +LL + use crate::bar::Foo; +LL | mod bar { | error: aborting due to previous error diff --git a/tests/ui/resolve/enums-are-namespaced-xc.stderr b/tests/ui/resolve/enums-are-namespaced-xc.stderr index 6448e596d56c..efebf15684b9 100644 --- a/tests/ui/resolve/enums-are-namespaced-xc.stderr +++ b/tests/ui/resolve/enums-are-namespaced-xc.stderr @@ -6,7 +6,8 @@ LL | let _ = namespaced_enums::A; | help: consider importing this unit variant | -LL | use namespaced_enums::Foo::A; +LL + use namespaced_enums::Foo::A; +LL | extern crate namespaced_enums; | help: if you import `A`, refer to it directly | @@ -22,7 +23,8 @@ LL | let _ = namespaced_enums::B(10); | help: consider importing this tuple variant | -LL | use namespaced_enums::Foo::B; +LL + use namespaced_enums::Foo::B; +LL | extern crate namespaced_enums; | help: if you import `B`, refer to it directly | @@ -38,7 +40,8 @@ LL | let _ = namespaced_enums::C { a: 10 }; | help: consider importing this variant | -LL | use namespaced_enums::Foo::C; +LL + use namespaced_enums::Foo::C; +LL | extern crate namespaced_enums; | help: if you import `C`, refer to it directly | diff --git a/tests/ui/resolve/filter-intrinsics.stderr b/tests/ui/resolve/filter-intrinsics.stderr index 955070891fbb..3b4a09a25e7f 100644 --- a/tests/ui/resolve/filter-intrinsics.stderr +++ b/tests/ui/resolve/filter-intrinsics.stderr @@ -6,7 +6,8 @@ LL | let _ = size_of::(); | help: consider importing this function | -LL | use std::mem::size_of; +LL + use std::mem::size_of; +LL | fn main() { | error[E0425]: cannot find function `fabsf64` in this scope @@ -17,7 +18,8 @@ LL | let _ = fabsf64(1.0); | help: consider importing this function | -LL | use std::intrinsics::fabsf64; +LL + use std::intrinsics::fabsf64; +LL | fn main() { | error: aborting due to 2 previous errors diff --git a/tests/ui/resolve/issue-102946.stderr b/tests/ui/resolve/issue-102946.stderr index 65be0258e6db..738438492140 100644 --- a/tests/ui/resolve/issue-102946.stderr +++ b/tests/ui/resolve/issue-102946.stderr @@ -6,7 +6,8 @@ LL | impl Error for str::Utf8Error { | help: consider importing this trait | -LL | use std::error::Error; +LL + use std::error::Error; +LL | impl Error for str::Utf8Error { | error[E0223]: ambiguous associated type diff --git a/tests/ui/resolve/issue-16058.stderr b/tests/ui/resolve/issue-16058.stderr index c47d22cef5f6..65dba047234a 100644 --- a/tests/ui/resolve/issue-16058.stderr +++ b/tests/ui/resolve/issue-16058.stderr @@ -6,11 +6,14 @@ LL | Result { | help: consider importing one of these items instead | -LL | use std::fmt::Result; +LL + use std::fmt::Result; +LL | pub struct GslResult { | -LL | use std::io::Result; +LL + use std::io::Result; +LL | pub struct GslResult { | -LL | use std::thread::Result; +LL + use std::thread::Result; +LL | pub struct GslResult { | error: aborting due to previous error diff --git a/tests/ui/resolve/issue-17518.stderr b/tests/ui/resolve/issue-17518.stderr index 034d0d01bfb8..19b59b841e04 100644 --- a/tests/ui/resolve/issue-17518.stderr +++ b/tests/ui/resolve/issue-17518.stderr @@ -6,7 +6,8 @@ LL | E { name: "foobar" }; | help: consider importing this variant | -LL | use SomeEnum::E; +LL + use SomeEnum::E; +LL | enum SomeEnum { | error: aborting due to previous error diff --git a/tests/ui/resolve/issue-21221-1.stderr b/tests/ui/resolve/issue-21221-1.stderr index 538eeead9fc9..836ea564f4ee 100644 --- a/tests/ui/resolve/issue-21221-1.stderr +++ b/tests/ui/resolve/issue-21221-1.stderr @@ -6,11 +6,14 @@ LL | impl Mul for Foo { | help: consider importing one of these items | -LL | use mul1::Mul; +LL + use mul1::Mul; +LL | mod mul1 { | -LL | use mul2::Mul; +LL + use mul2::Mul; +LL | mod mul1 { | -LL | use std::ops::Mul; +LL + use std::ops::Mul; +LL | mod mul1 { | error[E0412]: cannot find type `Mul` in this scope @@ -21,11 +24,14 @@ LL | fn getMul() -> Mul { | help: consider importing one of these items | -LL | use mul1::Mul; +LL + use mul1::Mul; +LL | mod mul1 { | -LL | use mul2::Mul; +LL + use mul2::Mul; +LL | mod mul1 { | -LL | use std::ops::Mul; +LL + use std::ops::Mul; +LL | mod mul1 { | error[E0405]: cannot find trait `ThisTraitReallyDoesntExistInAnyModuleReally` in this scope @@ -42,7 +48,8 @@ LL | impl Div for Foo { | help: consider importing this trait | -LL | use std::ops::Div; +LL + use std::ops::Div; +LL | mod mul1 { | error: aborting due to 4 previous errors diff --git a/tests/ui/resolve/issue-21221-2.stderr b/tests/ui/resolve/issue-21221-2.stderr index d4fd7cb1257e..e88274e6c60b 100644 --- a/tests/ui/resolve/issue-21221-2.stderr +++ b/tests/ui/resolve/issue-21221-2.stderr @@ -6,9 +6,11 @@ LL | impl T for Foo { } | help: consider importing one of these items | -LL | use baz::T; +LL + use baz::T; +LL | pub mod foo { | -LL | use foo::bar::T; +LL + use foo::bar::T; +LL | pub mod foo { | error: aborting due to previous error diff --git a/tests/ui/resolve/issue-21221-3.stderr b/tests/ui/resolve/issue-21221-3.stderr index f12e5b09bacd..e02eaec05e3e 100644 --- a/tests/ui/resolve/issue-21221-3.stderr +++ b/tests/ui/resolve/issue-21221-3.stderr @@ -6,7 +6,8 @@ LL | impl OuterTrait for Foo {} | help: consider importing this trait | -LL | use issue_21221_3::outer::OuterTrait; +LL + use issue_21221_3::outer::OuterTrait; +LL | extern crate issue_21221_3; | error: aborting due to previous error diff --git a/tests/ui/resolve/issue-21221-4.stderr b/tests/ui/resolve/issue-21221-4.stderr index fc15444d0c0f..e8c38ed6acf0 100644 --- a/tests/ui/resolve/issue-21221-4.stderr +++ b/tests/ui/resolve/issue-21221-4.stderr @@ -6,7 +6,8 @@ LL | impl T for Foo {} | help: consider importing this trait | -LL | use issue_21221_4::T; +LL + use issue_21221_4::T; +LL | extern crate issue_21221_4; | error: aborting due to previous error diff --git a/tests/ui/resolve/issue-2356.stderr b/tests/ui/resolve/issue-2356.stderr index 36f3da7c9553..ed820f15c83e 100644 --- a/tests/ui/resolve/issue-2356.stderr +++ b/tests/ui/resolve/issue-2356.stderr @@ -10,7 +10,8 @@ LL | Self::default(); | ~~~~~~~~~~~~~ help: consider importing this function | -LL | use std::default::default; +LL + use std::default::default; +LL | trait Groom { | error[E0425]: cannot find value `whiskers` in this scope diff --git a/tests/ui/resolve/issue-26545.stderr b/tests/ui/resolve/issue-26545.stderr index d3c86692501d..2b98b5b8a7bf 100644 --- a/tests/ui/resolve/issue-26545.stderr +++ b/tests/ui/resolve/issue-26545.stderr @@ -6,7 +6,8 @@ LL | B(()); | help: consider importing this tuple struct | -LL | use foo::B; +LL + use foo::B; +LL | fn foo() { | error: aborting due to previous error diff --git a/tests/ui/resolve/issue-35675.stderr b/tests/ui/resolve/issue-35675.stderr index 4a06196d548e..d28561453715 100644 --- a/tests/ui/resolve/issue-35675.stderr +++ b/tests/ui/resolve/issue-35675.stderr @@ -17,7 +17,8 @@ LL | Apple(5) | help: consider importing this tuple variant | -LL | use Fruit::Apple; +LL + use Fruit::Apple; +LL | enum Fruit { | error[E0573]: expected type, found variant `Fruit::Apple` @@ -37,7 +38,8 @@ LL | Apple(5) | help: consider importing this tuple variant | -LL | use Fruit::Apple; +LL + use Fruit::Apple; +LL | enum Fruit { | error[E0573]: expected type, found variant `Ok` diff --git a/tests/ui/resolve/issue-3907.stderr b/tests/ui/resolve/issue-3907.stderr index 6fc61cae8433..50ad668f8dbf 100644 --- a/tests/ui/resolve/issue-3907.stderr +++ b/tests/ui/resolve/issue-3907.stderr @@ -10,7 +10,8 @@ LL | trait Foo = dyn issue_3907::Foo; | help: consider importing this trait instead | -LL | use issue_3907::Foo; +LL + use issue_3907::Foo; +LL | extern crate issue_3907; | error: aborting due to previous error diff --git a/tests/ui/resolve/issue-50599.stderr b/tests/ui/resolve/issue-50599.stderr index b07482c83ccc..548d215b00ac 100644 --- a/tests/ui/resolve/issue-50599.stderr +++ b/tests/ui/resolve/issue-50599.stderr @@ -6,9 +6,11 @@ LL | const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize; | help: consider importing one of these items | -LL | use std::f32::consts::LOG10_2; +LL + use std::f32::consts::LOG10_2; +LL | fn main() { | -LL | use std::f64::consts::LOG10_2; +LL + use std::f64::consts::LOG10_2; +LL | fn main() { | help: if you import `LOG10_2`, refer to it directly | diff --git a/tests/ui/resolve/issue-73427.stderr b/tests/ui/resolve/issue-73427.stderr index 4af5f29d8093..5a663ae79bcb 100644 --- a/tests/ui/resolve/issue-73427.stderr +++ b/tests/ui/resolve/issue-73427.stderr @@ -107,9 +107,11 @@ LL | (E::TupleWithFields(/* fields */)).foo(); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ help: consider importing one of these items instead | -LL | use std::f32::consts::E; +LL + use std::f32::consts::E; +LL | enum A { | -LL | use std::f64::consts::E; +LL + use std::f64::consts::E; +LL | enum A { | error[E0532]: expected tuple struct or tuple variant, found enum `A` diff --git a/tests/ui/resolve/issue-90113.stderr b/tests/ui/resolve/issue-90113.stderr index 1b78720571c6..a9d4b573f110 100644 --- a/tests/ui/resolve/issue-90113.stderr +++ b/tests/ui/resolve/issue-90113.stderr @@ -6,7 +6,8 @@ LL | Cons(..) => {} | help: consider importing this tuple variant | -LL | use list::List::Cons; +LL + use list::List::Cons; +LL | mod list { | error: aborting due to previous error diff --git a/tests/ui/resolve/missing-in-namespace.stderr b/tests/ui/resolve/missing-in-namespace.stderr index fc925ba3b6a8..66f40102a3ed 100644 --- a/tests/ui/resolve/missing-in-namespace.stderr +++ b/tests/ui/resolve/missing-in-namespace.stderr @@ -6,7 +6,8 @@ LL | let _map = std::hahmap::HashMap::new(); | help: consider importing this struct | -LL | use std::collections::HashMap; +LL + use std::collections::HashMap; +LL | fn main() { | help: if you import `HashMap`, refer to it directly | diff --git a/tests/ui/resolve/no-implicit-prelude-nested.stderr b/tests/ui/resolve/no-implicit-prelude-nested.stderr index 198b630c52c8..4df6c31d3164 100644 --- a/tests/ui/resolve/no-implicit-prelude-nested.stderr +++ b/tests/ui/resolve/no-implicit-prelude-nested.stderr @@ -6,7 +6,8 @@ LL | impl Add for Test {} | help: consider importing this trait | -LL | use std::ops::Add; +LL + use std::ops::Add; +LL | struct Test; | error[E0404]: expected trait, found derive macro `Clone` @@ -17,7 +18,8 @@ LL | impl Clone for Test {} | help: consider importing this trait instead | -LL | use std::clone::Clone; +LL + use std::clone::Clone; +LL | struct Test; | error[E0405]: cannot find trait `Iterator` in this scope @@ -28,7 +30,8 @@ LL | impl Iterator for Test {} | help: consider importing this trait | -LL | use std::iter::Iterator; +LL + use std::iter::Iterator; +LL | struct Test; | error[E0405]: cannot find trait `ToString` in this scope @@ -39,7 +42,8 @@ LL | impl ToString for Test {} | help: consider importing this trait | -LL | use std::string::ToString; +LL + use std::string::ToString; +LL | struct Test; | error[E0405]: cannot find trait `Writer` in this scope @@ -56,7 +60,8 @@ LL | drop(2) | help: consider importing this function | -LL | use std::mem::drop; +LL + use std::mem::drop; +LL | struct Test; | error[E0405]: cannot find trait `Add` in this scope @@ -67,7 +72,8 @@ LL | impl Add for Test {} | help: consider importing this trait | -LL | use std::ops::Add; +LL + use std::ops::Add; +LL | mod baz { | error[E0404]: expected trait, found derive macro `Clone` @@ -78,7 +84,8 @@ LL | impl Clone for Test {} | help: consider importing this trait instead | -LL | use std::clone::Clone; +LL + use std::clone::Clone; +LL | mod baz { | error[E0405]: cannot find trait `Iterator` in this scope @@ -89,7 +96,8 @@ LL | impl Iterator for Test {} | help: consider importing this trait | -LL | use std::iter::Iterator; +LL + use std::iter::Iterator; +LL | mod baz { | error[E0405]: cannot find trait `ToString` in this scope @@ -100,7 +108,8 @@ LL | impl ToString for Test {} | help: consider importing this trait | -LL | use std::string::ToString; +LL + use std::string::ToString; +LL | mod baz { | error[E0405]: cannot find trait `Writer` in this scope @@ -117,7 +126,8 @@ LL | drop(2) | help: consider importing this function | -LL | use std::mem::drop; +LL + use std::mem::drop; +LL | mod baz { | error[E0405]: cannot find trait `Add` in this scope @@ -128,7 +138,8 @@ LL | impl Add for Test {} | help: consider importing this trait | -LL | use std::ops::Add; +LL + use std::ops::Add; +LL | struct Test; | error[E0404]: expected trait, found derive macro `Clone` @@ -139,7 +150,8 @@ LL | impl Clone for Test {} | help: consider importing this trait instead | -LL | use std::clone::Clone; +LL + use std::clone::Clone; +LL | struct Test; | error[E0405]: cannot find trait `Iterator` in this scope @@ -150,7 +162,8 @@ LL | impl Iterator for Test {} | help: consider importing this trait | -LL | use std::iter::Iterator; +LL + use std::iter::Iterator; +LL | struct Test; | error[E0405]: cannot find trait `ToString` in this scope @@ -161,7 +174,8 @@ LL | impl ToString for Test {} | help: consider importing this trait | -LL | use std::string::ToString; +LL + use std::string::ToString; +LL | struct Test; | error[E0405]: cannot find trait `Writer` in this scope @@ -178,7 +192,8 @@ LL | drop(2) | help: consider importing this function | -LL | use std::mem::drop; +LL + use std::mem::drop; +LL | struct Test; | error: aborting due to 18 previous errors diff --git a/tests/ui/resolve/no-implicit-prelude.stderr b/tests/ui/resolve/no-implicit-prelude.stderr index 36a9b65b7d16..a8e5f1b69e23 100644 --- a/tests/ui/resolve/no-implicit-prelude.stderr +++ b/tests/ui/resolve/no-implicit-prelude.stderr @@ -6,7 +6,8 @@ LL | impl Add for Test {} | help: consider importing this trait | -LL | use std::ops::Add; +LL + use std::ops::Add; +LL | struct Test; | error[E0404]: expected trait, found derive macro `Clone` @@ -17,7 +18,8 @@ LL | impl Clone for Test {} | help: consider importing this trait instead | -LL | use std::clone::Clone; +LL + use std::clone::Clone; +LL | struct Test; | error[E0405]: cannot find trait `Iterator` in this scope @@ -28,7 +30,8 @@ LL | impl Iterator for Test {} | help: consider importing this trait | -LL | use std::iter::Iterator; +LL + use std::iter::Iterator; +LL | struct Test; | error[E0405]: cannot find trait `ToString` in this scope @@ -39,7 +42,8 @@ LL | impl ToString for Test {} | help: consider importing this trait | -LL | use std::string::ToString; +LL + use std::string::ToString; +LL | struct Test; | error[E0405]: cannot find trait `Writer` in this scope @@ -56,7 +60,8 @@ LL | drop(2) | help: consider importing this function | -LL | use std::mem::drop; +LL + use std::mem::drop; +LL | struct Test; | error: aborting due to 6 previous errors diff --git a/tests/ui/resolve/privacy-enum-ctor.stderr b/tests/ui/resolve/privacy-enum-ctor.stderr index 3c051429fd0e..76dc25539d07 100644 --- a/tests/ui/resolve/privacy-enum-ctor.stderr +++ b/tests/ui/resolve/privacy-enum-ctor.stderr @@ -84,9 +84,11 @@ LL | let _: E = m::f; | ~ help: consider importing one of these items instead | -LL | use std::f32::consts::E; +LL + use std::f32::consts::E; +LL | use m::E; // OK, only the type is imported | -LL | use std::f64::consts::E; +LL + use std::f64::consts::E; +LL | use m::E; // OK, only the type is imported | help: if you import `E`, refer to it directly | @@ -121,9 +123,11 @@ LL | let _: E = (E::Fn(/* fields */)); | ~~~~~~~~~~~~~~~~~~~~~ help: consider importing one of these items instead | -LL | use std::f32::consts::E; +LL + use std::f32::consts::E; +LL | use m::E; // OK, only the type is imported | -LL | use std::f64::consts::E; +LL + use std::f64::consts::E; +LL | use m::E; // OK, only the type is imported | error[E0412]: cannot find type `Z` in this scope diff --git a/tests/ui/resolve/resolve-primitive-fallback.stderr b/tests/ui/resolve/resolve-primitive-fallback.stderr index f803f9da2af1..2227522d6eab 100644 --- a/tests/ui/resolve/resolve-primitive-fallback.stderr +++ b/tests/ui/resolve/resolve-primitive-fallback.stderr @@ -12,7 +12,8 @@ LL | let _: ::u8; | help: consider importing this builtin type | -LL | use std::primitive::u8; +LL + use std::primitive::u8; +LL | fn main() { | help: if you import `u8`, refer to it directly | diff --git a/tests/ui/resolve/use_suggestion.stderr b/tests/ui/resolve/use_suggestion.stderr index 54ad853831f3..a30dbd954e12 100644 --- a/tests/ui/resolve/use_suggestion.stderr +++ b/tests/ui/resolve/use_suggestion.stderr @@ -6,7 +6,8 @@ LL | let x1 = HashMap::new(); | help: consider importing this struct | -LL | use std::collections::HashMap; +LL + use std::collections::HashMap; +LL | fn main() { | error[E0412]: cannot find type `HashMap` in this scope @@ -17,7 +18,8 @@ LL | let y1: HashMap; | help: consider importing this struct | -LL | use std::collections::HashMap; +LL + use std::collections::HashMap; +LL | fn main() { | error[E0412]: cannot find type `GooMap` in this scope diff --git a/tests/ui/resolve/use_suggestion_placement.stderr b/tests/ui/resolve/use_suggestion_placement.stderr index 0aadd82f6c29..9288530ad2e8 100644 --- a/tests/ui/resolve/use_suggestion_placement.stderr +++ b/tests/ui/resolve/use_suggestion_placement.stderr @@ -6,7 +6,8 @@ LL | type Bar = Path; | help: consider importing this struct | -LL | use std::path::Path; +LL + use std::path::Path; +LL | #[derive(Debug)] | error[E0425]: cannot find value `A` in this scope @@ -17,7 +18,8 @@ LL | let _ = A; | help: consider importing this constant | -LL | use m::A; +LL + use m::A; +LL | macro_rules! y { | error[E0412]: cannot find type `HashMap` in this scope @@ -28,7 +30,8 @@ LL | type Dict = HashMap; | help: consider importing this struct | -LL | use std::collections::HashMap; +LL + use std::collections::HashMap; +LL | macro_rules! y { | error: aborting due to 3 previous errors diff --git a/tests/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr b/tests/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr index d8b5a9e63643..ce165e646329 100644 --- a/tests/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr +++ b/tests/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr @@ -9,7 +9,8 @@ LL | let _: NotDebug = dbg!(NotDebug); = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `NotDebug` with `#[derive(Debug)]` | -LL | #[derive(Debug)] +LL + #[derive(Debug)] +LL | struct NotDebug; | error: aborting due to previous error diff --git a/tests/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr b/tests/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr index 6b6c578bff8a..653037ef3989 100644 --- a/tests/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr +++ b/tests/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr @@ -16,7 +16,8 @@ LL | pub struct S(A); = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `A` with `#[derive(Default)]` | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | pub struct A; | error[E0015]: cannot call non-const fn `::default` in constant functions diff --git a/tests/ui/rust-2018/issue-52202-use-suggestions.stderr b/tests/ui/rust-2018/issue-52202-use-suggestions.stderr index 38cd9713d1a1..5450ede82230 100644 --- a/tests/ui/rust-2018/issue-52202-use-suggestions.stderr +++ b/tests/ui/rust-2018/issue-52202-use-suggestions.stderr @@ -6,13 +6,17 @@ LL | let _d = Drain {}; | help: consider importing one of these items | -LL | use crate::plumbing::Drain; +LL + use crate::plumbing::Drain; +LL | mod plumbing { | -LL | use std::collections::binary_heap::Drain; +LL + use std::collections::binary_heap::Drain; +LL | mod plumbing { | -LL | use std::collections::hash_map::Drain; +LL + use std::collections::hash_map::Drain; +LL | mod plumbing { | -LL | use std::collections::hash_set::Drain; +LL + use std::collections::hash_set::Drain; +LL | mod plumbing { | and 3 other candidates diff --git a/tests/ui/rust-2018/trait-import-suggestions.stderr b/tests/ui/rust-2018/trait-import-suggestions.stderr index 6454b6045e46..4be5c7b0d0c4 100644 --- a/tests/ui/rust-2018/trait-import-suggestions.stderr +++ b/tests/ui/rust-2018/trait-import-suggestions.stderr @@ -10,7 +10,8 @@ LL | x.foobar(); = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use crate::foo::foobar::Foobar; +LL + use crate::foo::foobar::Foobar; +LL | mod foobar { | error[E0599]: no method named `bar` found for type `u32` in the current scope @@ -25,7 +26,8 @@ LL | x.bar(); = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use crate::foo::Bar; +LL + use crate::foo::Bar; +LL | mod foo { | error[E0599]: no method named `baz` found for type `u32` in the current scope @@ -43,7 +45,8 @@ LL | let y = u32::from_str("33"); = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use std::str::FromStr; +LL + use std::str::FromStr; +LL | mod foo { | help: there is an associated function with a similar name | diff --git a/tests/ui/rust-2018/uniform-paths/issue-87932.stderr b/tests/ui/rust-2018/uniform-paths/issue-87932.stderr index b52720ae3d9d..e5e17f22c5f1 100644 --- a/tests/ui/rust-2018/uniform-paths/issue-87932.stderr +++ b/tests/ui/rust-2018/uniform-paths/issue-87932.stderr @@ -10,7 +10,8 @@ LL | A::deserialize(); = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use ::deserialize::_a::Deserialize; +LL + use ::deserialize::_a::Deserialize; +LL | pub struct A {} | error: aborting due to previous error diff --git a/tests/ui/rust-2021/future-prelude-collision-shadow.stderr b/tests/ui/rust-2021/future-prelude-collision-shadow.stderr index 3d21b735aea0..34bf68e8913f 100644 --- a/tests/ui/rust-2021/future-prelude-collision-shadow.stderr +++ b/tests/ui/rust-2021/future-prelude-collision-shadow.stderr @@ -8,9 +8,11 @@ LL | let _: u32 = 3u8.try_into().unwrap(); = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021 help: the following traits are implemented but not in scope; perhaps add a `use` for one of them: | -LL | use crate::m::TryIntoU32; +LL + use crate::m::TryIntoU32; +LL | use crate::m::AnotherTrick as TryIntoU32; | -LL | use std::convert::TryInto; +LL + use std::convert::TryInto; +LL | use crate::m::AnotherTrick as TryIntoU32; | error: aborting due to previous error diff --git a/tests/ui/self/class-missing-self.stderr b/tests/ui/self/class-missing-self.stderr index 063c3f013c53..2f35b30dbcb0 100644 --- a/tests/ui/self/class-missing-self.stderr +++ b/tests/ui/self/class-missing-self.stderr @@ -16,7 +16,8 @@ LL | self.sleep(); | +++++ help: consider importing this function | -LL | use std::thread::sleep; +LL + use std::thread::sleep; +LL | struct Cat { | error: aborting due to 2 previous errors diff --git a/tests/ui/shadowed/shadowed-trait-methods.stderr b/tests/ui/shadowed/shadowed-trait-methods.stderr index c3b9084affdb..6d7ab27f3e15 100644 --- a/tests/ui/shadowed/shadowed-trait-methods.stderr +++ b/tests/ui/shadowed/shadowed-trait-methods.stderr @@ -10,7 +10,8 @@ LL | ().f() = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use foo::T; +LL + use foo::T; +LL | mod foo { | error: aborting due to previous error diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr index 37b2f4138603..626cc67d9eb9 100644 --- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr +++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr @@ -15,7 +15,8 @@ LL | interval: Duration, | help: consider importing this struct | -LL | use std::time::Duration; +LL + use std::time::Duration; +LL | fn main() {} | error: aborting due to 2 previous errors diff --git a/tests/ui/span/issue-35987.stderr b/tests/ui/span/issue-35987.stderr index 057d40ac0cb9..0e64bcb01069 100644 --- a/tests/ui/span/issue-35987.stderr +++ b/tests/ui/span/issue-35987.stderr @@ -11,6 +11,7 @@ LL | impl Add for Foo { | help: consider importing this trait instead | +LL + use std::ops::Add; LL | use std::ops::Add; | diff --git a/tests/ui/span/issue-71363.stderr b/tests/ui/span/issue-71363.stderr index cb5cc320276d..90b623e89cff 100644 --- a/tests/ui/span/issue-71363.stderr +++ b/tests/ui/span/issue-71363.stderr @@ -21,7 +21,8 @@ note: required by a bound in `std::error::Error` --> $SRC_DIR/core/src/error.rs:LL:COL help: consider annotating `MyError` with `#[derive(Debug)]` | -3 | #[derive(Debug)] +3 + #[derive(Debug)] +4 | struct MyError; | error: aborting due to 2 previous errors diff --git a/tests/ui/specialization/issue-59435.stderr b/tests/ui/specialization/issue-59435.stderr index 211459406686..e8a12e4d928e 100644 --- a/tests/ui/specialization/issue-59435.stderr +++ b/tests/ui/specialization/issue-59435.stderr @@ -11,7 +11,8 @@ LL | type MyType: Default; | ^^^^^^^ required by this bound in `MyTrait::MyType` help: consider annotating `MyStruct` with `#[derive(Default)]` | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | struct MyStruct {} | error: aborting due to previous error diff --git a/tests/ui/structs/struct-path-alias-bounds.stderr b/tests/ui/structs/struct-path-alias-bounds.stderr index 266291f62b45..5b01208c56fb 100644 --- a/tests/ui/structs/struct-path-alias-bounds.stderr +++ b/tests/ui/structs/struct-path-alias-bounds.stderr @@ -11,7 +11,8 @@ LL | struct S { a: T } | ^^^^^ required by this bound in `S` help: consider annotating `NoClone` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | struct NoClone; | error: aborting due to previous error diff --git a/tests/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr b/tests/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr index 45593035b9d6..0716005c679a 100644 --- a/tests/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr +++ b/tests/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr @@ -35,7 +35,8 @@ LL | t.clone() | ^ help: consider annotating `Foo` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | struct Foo; | error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.stderr b/tests/ui/suggestions/core-std-import-order-issue-83564.stderr index e4e1fc591c47..c87ff9525532 100644 --- a/tests/ui/suggestions/core-std-import-order-issue-83564.stderr +++ b/tests/ui/suggestions/core-std-import-order-issue-83564.stderr @@ -6,9 +6,11 @@ LL | let _x = NonZeroU32::new(5).unwrap(); | help: consider importing one of these items | -LL | use core::num::NonZeroU32; +LL + use core::num::NonZeroU32; +LL | fn main() { | -LL | use std::num::NonZeroU32; +LL + use std::num::NonZeroU32; +LL | fn main() { | error: aborting due to previous error diff --git a/tests/ui/suggestions/derive-macro-missing-bounds.stderr b/tests/ui/suggestions/derive-macro-missing-bounds.stderr index 79036279df95..c3f305c1770a 100644 --- a/tests/ui/suggestions/derive-macro-missing-bounds.stderr +++ b/tests/ui/suggestions/derive-macro-missing-bounds.stderr @@ -11,7 +11,8 @@ LL | struct Outer(Inner); = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `a::Inner` with `#[derive(Debug)]` | -LL | #[derive(Debug)] +LL + #[derive(Debug)] +LL | struct Inner(T); | help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement | diff --git a/tests/ui/suggestions/derive-trait-for-method-call.stderr b/tests/ui/suggestions/derive-trait-for-method-call.stderr index 924b26a8c75f..e2db0da74f02 100644 --- a/tests/ui/suggestions/derive-trait-for-method-call.stderr +++ b/tests/ui/suggestions/derive-trait-for-method-call.stderr @@ -32,7 +32,8 @@ note: the trait `Default` must be implemented --> $SRC_DIR/core/src/default.rs:LL:COL help: consider annotating `Enum` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | enum Enum { | error[E0599]: the method `test` exists for struct `Foo`, but its trait bounds were not satisfied @@ -67,11 +68,13 @@ LL | impl Foo { | unsatisfied trait bound introduced here help: consider annotating `CloneStruct` with `#[derive(Default)]` | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | struct CloneStruct { | help: consider annotating `Struct` with `#[derive(Clone, Default)]` | -LL | #[derive(Clone, Default)] +LL + #[derive(Clone, Default)] +LL | struct Struct { | error[E0599]: the method `test` exists for struct `Foo, Instant>`, but its trait bounds were not satisfied diff --git a/tests/ui/suggestions/dont-wrap-ambiguous-receivers.stderr b/tests/ui/suggestions/dont-wrap-ambiguous-receivers.stderr index 4658ecb3a7a9..6eced1d416e4 100644 --- a/tests/ui/suggestions/dont-wrap-ambiguous-receivers.stderr +++ b/tests/ui/suggestions/dont-wrap-ambiguous-receivers.stderr @@ -10,9 +10,11 @@ LL | banana::Chaenomeles.pick() = help: items from traits can only be used if the trait is in scope help: the following traits are implemented but not in scope; perhaps add a `use` for one of them: | -LL | use banana::Apple; +LL + use banana::Apple; +LL | mod banana { | -LL | use banana::Peach; +LL + use banana::Peach; +LL | mod banana { | error: aborting due to previous error diff --git a/tests/ui/suggestions/import-trait-for-method-call.stderr b/tests/ui/suggestions/import-trait-for-method-call.stderr index f159b51a2696..464fe85ac175 100644 --- a/tests/ui/suggestions/import-trait-for-method-call.stderr +++ b/tests/ui/suggestions/import-trait-for-method-call.stderr @@ -10,7 +10,8 @@ LL | h.finish() = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use std::hash::Hasher; +LL + use std::hash::Hasher; +LL | use std::hash::BuildHasher; | error[E0599]: the method `as_ref` exists for reference `&dyn Bar`, but its trait bounds were not satisfied diff --git a/tests/ui/suggestions/invalid-bin-op.stderr b/tests/ui/suggestions/invalid-bin-op.stderr index 08502dfeb2d5..e291cedb8357 100644 --- a/tests/ui/suggestions/invalid-bin-op.stderr +++ b/tests/ui/suggestions/invalid-bin-op.stderr @@ -13,7 +13,8 @@ LL | struct S(T); | ^^^^^^^^^^^ must implement `PartialEq<_>` help: consider annotating `S` with `#[derive(PartialEq)]` | -LL | #[derive(PartialEq)] +LL + #[derive(PartialEq)] +LL | struct S(T); | help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement | diff --git a/tests/ui/suggestions/issue-84973-blacklist.stderr b/tests/ui/suggestions/issue-84973-blacklist.stderr index c20cc816484b..1e243f81b10e 100644 --- a/tests/ui/suggestions/issue-84973-blacklist.stderr +++ b/tests/ui/suggestions/issue-84973-blacklist.stderr @@ -27,7 +27,8 @@ LL | fn f_clone(t: T) {} | ^^^^^ required by this bound in `f_clone` help: consider annotating `S` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | struct S; | error[E0277]: `[static generator@$DIR/issue-84973-blacklist.rs:17:13: 17:22]` cannot be unpinned diff --git a/tests/ui/suggestions/no-extern-crate-in-type.stderr b/tests/ui/suggestions/no-extern-crate-in-type.stderr index 876eef2b6249..d8e53229f49f 100644 --- a/tests/ui/suggestions/no-extern-crate-in-type.stderr +++ b/tests/ui/suggestions/no-extern-crate-in-type.stderr @@ -6,7 +6,8 @@ LL | type Output = Option; | help: consider importing this struct | -LL | use foo::Foo; +LL + use foo::Foo; +LL | extern crate foo; | error: aborting due to previous error diff --git a/tests/ui/suggestions/raw-name-use-suggestion.stderr b/tests/ui/suggestions/raw-name-use-suggestion.stderr index 95c26b9ade8b..733af9079d59 100644 --- a/tests/ui/suggestions/raw-name-use-suggestion.stderr +++ b/tests/ui/suggestions/raw-name-use-suggestion.stderr @@ -28,7 +28,8 @@ LL | r#break(); | help: consider importing this function | -LL | use foo::r#break; +LL + use foo::r#break; +LL | mod foo { | error: aborting due to 3 previous errors diff --git a/tests/ui/suggestions/suggest-tryinto-edition-change.stderr b/tests/ui/suggestions/suggest-tryinto-edition-change.stderr index 018083f9e03a..525a5bc164de 100644 --- a/tests/ui/suggestions/suggest-tryinto-edition-change.stderr +++ b/tests/ui/suggestions/suggest-tryinto-edition-change.stderr @@ -8,9 +8,11 @@ LL | let _i: i16 = TryFrom::try_from(0_i32).unwrap(); = note: 'core::convert::TryFrom' is included in the prelude starting in Edition 2021 help: consider importing one of these items | -LL | use core::convert::TryFrom; +LL + use core::convert::TryFrom; +LL | fn test() { | -LL | use std::convert::TryFrom; +LL + use std::convert::TryFrom; +LL | fn test() { | error[E0433]: failed to resolve: use of undeclared type `TryInto` @@ -23,9 +25,11 @@ LL | let _i: i16 = TryInto::try_into(0_i32).unwrap(); = note: 'core::convert::TryInto' is included in the prelude starting in Edition 2021 help: consider importing one of these items | -LL | use core::convert::TryInto; +LL + use core::convert::TryInto; +LL | fn test() { | -LL | use std::convert::TryInto; +LL + use std::convert::TryInto; +LL | fn test() { | error[E0433]: failed to resolve: use of undeclared type `FromIterator` @@ -42,9 +46,11 @@ LL | let _v: Vec<_> = IntoIterator::from_iter(&[1]); | ~~~~~~~~~~~~ help: consider importing one of these items | -LL | use core::iter::FromIterator; +LL + use core::iter::FromIterator; +LL | fn test() { | -LL | use std::iter::FromIterator; +LL + use std::iter::FromIterator; +LL | fn test() { | error[E0599]: no method named `try_into` found for type `i32` in the current scope @@ -60,7 +66,8 @@ LL | let _i: i16 = 0_i32.try_into().unwrap(); = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021 help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use std::convert::TryInto; +LL + use std::convert::TryInto; +LL | fn test() { | error: aborting due to 4 previous errors diff --git a/tests/ui/suggestions/use-placement-resolve.stderr b/tests/ui/suggestions/use-placement-resolve.stderr index 9da9e8e27021..16cbc9edcef7 100644 --- a/tests/ui/suggestions/use-placement-resolve.stderr +++ b/tests/ui/suggestions/use-placement-resolve.stderr @@ -6,7 +6,8 @@ LL | fn foobar(x: T) {} | help: consider importing this trait instead | -LL | use std::fmt::Debug; +LL + use std::fmt::Debug; +LL | fn main() {} | error: aborting due to previous error diff --git a/tests/ui/suggestions/use-placement-typeck.stderr b/tests/ui/suggestions/use-placement-typeck.stderr index 3b2749773a13..dc0586302f59 100644 --- a/tests/ui/suggestions/use-placement-typeck.stderr +++ b/tests/ui/suggestions/use-placement-typeck.stderr @@ -13,7 +13,8 @@ LL | pub struct S; = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use m::Foo; +LL + use m::Foo; +LL | fn main() { | error: aborting due to previous error diff --git a/tests/ui/trait-bounds/impl-bound-with-references-error.stderr b/tests/ui/trait-bounds/impl-bound-with-references-error.stderr index 95fd6bd504cd..cc3b887cf072 100644 --- a/tests/ui/trait-bounds/impl-bound-with-references-error.stderr +++ b/tests/ui/trait-bounds/impl-bound-with-references-error.stderr @@ -6,7 +6,8 @@ LL | T: Into>, | help: consider importing this enum | -LL | use std::borrow::Cow; +LL + use std::borrow::Cow; +LL | pub enum LabelText { | error[E0119]: conflicting implementations of trait `From` for type `LabelText` diff --git a/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr b/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr index b297662955e3..60a86cc8e41e 100644 --- a/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr +++ b/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr @@ -6,7 +6,8 @@ LL | pub struct A(pub H); | help: consider importing this trait | -LL | use A::Trait; +LL + use A::Trait; +LL | pub struct A(pub H); | help: if you import `Trait`, refer to it directly | diff --git a/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr b/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr index dc967d512987..e723c7c51814 100644 --- a/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr +++ b/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr @@ -26,7 +26,8 @@ LL | fn copy(x: T) -> (T, T) { (x, x) } | ^^^^^ required by this bound in `copy` help: consider annotating `NoClone` with `#[derive(Copy)]` | -LL | #[derive(Copy)] +LL + #[derive(Copy)] +LL | struct NoClone; | error: aborting due to 2 previous errors diff --git a/tests/ui/traits/issue-71136.stderr b/tests/ui/traits/issue-71136.stderr index f541733929d3..ef55796187ee 100644 --- a/tests/ui/traits/issue-71136.stderr +++ b/tests/ui/traits/issue-71136.stderr @@ -11,7 +11,8 @@ LL | the_foos: Vec, = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Foo` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | struct Foo(u8); | error: aborting due to previous error diff --git a/tests/ui/traits/issue-78372.stderr b/tests/ui/traits/issue-78372.stderr index 8e7fd5f25571..f9c2c0d6dec7 100644 --- a/tests/ui/traits/issue-78372.stderr +++ b/tests/ui/traits/issue-78372.stderr @@ -6,7 +6,8 @@ LL | struct Smaht(PhantomData); | help: consider importing this struct | -LL | use std::marker::PhantomData; +LL + use std::marker::PhantomData; +LL | use std::ops::DispatchFromDyn; | error[E0412]: cannot find type `U` in this scope diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr index 04995b3a17b2..f505f36aaead 100644 --- a/tests/ui/traits/item-privacy.stderr +++ b/tests/ui/traits/item-privacy.stderr @@ -29,7 +29,8 @@ LL | S.b(); = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use method::B; +LL + use method::B; +LL | struct S; | error[E0624]: method `a` is private @@ -69,7 +70,8 @@ LL | S::b(&S); = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use method::B; +LL + use method::B; +LL | struct S; | error[E0624]: method `a` is private @@ -109,7 +111,8 @@ LL | S::B; = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use assoc_const::B; +LL + use assoc_const::B; +LL | struct S; | error[E0624]: associated constant `A` is private diff --git a/tests/ui/traits/method-private.stderr b/tests/ui/traits/method-private.stderr index 55656f21e00c..2b047df75a00 100644 --- a/tests/ui/traits/method-private.stderr +++ b/tests/ui/traits/method-private.stderr @@ -10,7 +10,8 @@ LL | foo.method(); = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use inner::Bar; +LL + use inner::Bar; +LL | mod inner { | error: aborting due to previous error diff --git a/tests/ui/typeck/explain_clone_autoref.stderr b/tests/ui/typeck/explain_clone_autoref.stderr index 4539da4389b3..38cb7fe55184 100644 --- a/tests/ui/typeck/explain_clone_autoref.stderr +++ b/tests/ui/typeck/explain_clone_autoref.stderr @@ -14,7 +14,8 @@ LL | nc.clone() | ^^ help: consider annotating `NotClone` with `#[derive(Clone)]` | -LL | #[derive(Clone)] +LL + #[derive(Clone)] +LL | struct NotClone; | error: aborting due to previous error diff --git a/tests/ui/typeck/issue-43189.stderr b/tests/ui/typeck/issue-43189.stderr index caf7530b85af..fa8a61436229 100644 --- a/tests/ui/typeck/issue-43189.stderr +++ b/tests/ui/typeck/issue-43189.stderr @@ -12,7 +12,8 @@ LL | fn a(&self) {} = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use xcrate_issue_43189_b::xcrate_issue_43189_a::A; +LL + use xcrate_issue_43189_b::xcrate_issue_43189_a::A; +LL | extern crate xcrate_issue_43189_b; | error: aborting due to previous error diff --git a/tests/ui/underscore-imports/shadow.stderr b/tests/ui/underscore-imports/shadow.stderr index 7faede4e6d0a..b0ecf129ca3d 100644 --- a/tests/ui/underscore-imports/shadow.stderr +++ b/tests/ui/underscore-imports/shadow.stderr @@ -7,7 +7,8 @@ LL | x.deref(); = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: | -LL | use std::ops::Deref; +LL + use std::ops::Deref; +LL | use crate::b::Shadow as _; // Only imports the struct | error: aborting due to previous error diff --git a/tests/ui/union/union-derive-clone.mirunsafeck.stderr b/tests/ui/union/union-derive-clone.mirunsafeck.stderr index b80e8b988adb..4d23d230fa3f 100644 --- a/tests/ui/union/union-derive-clone.mirunsafeck.stderr +++ b/tests/ui/union/union-derive-clone.mirunsafeck.stderr @@ -9,7 +9,8 @@ note: required by a bound in `AssertParamIsCopy` = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `U1` with `#[derive(Copy)]` | -LL | #[derive(Copy)] +LL + #[derive(Copy)] +LL | union U1 { | error[E0599]: the method `clone` exists for union `U5`, but its trait bounds were not satisfied @@ -34,7 +35,8 @@ LL | #[derive(Clone, Copy)] | ^^^^^ unsatisfied trait bound introduced in this `derive` macro help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]` | -LL | #[derive(Clone, Copy)] +LL + #[derive(Clone, Copy)] +LL | struct CloneNoCopy; | error: aborting due to 2 previous errors diff --git a/tests/ui/union/union-derive-clone.thirunsafeck.stderr b/tests/ui/union/union-derive-clone.thirunsafeck.stderr index b80e8b988adb..4d23d230fa3f 100644 --- a/tests/ui/union/union-derive-clone.thirunsafeck.stderr +++ b/tests/ui/union/union-derive-clone.thirunsafeck.stderr @@ -9,7 +9,8 @@ note: required by a bound in `AssertParamIsCopy` = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `U1` with `#[derive(Copy)]` | -LL | #[derive(Copy)] +LL + #[derive(Copy)] +LL | union U1 { | error[E0599]: the method `clone` exists for union `U5`, but its trait bounds were not satisfied @@ -34,7 +35,8 @@ LL | #[derive(Clone, Copy)] | ^^^^^ unsatisfied trait bound introduced in this `derive` macro help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]` | -LL | #[derive(Clone, Copy)] +LL + #[derive(Clone, Copy)] +LL | struct CloneNoCopy; | error: aborting due to 2 previous errors diff --git a/tests/ui/union/union-derive-eq.mirunsafeck.stderr b/tests/ui/union/union-derive-eq.mirunsafeck.stderr index 9e55390b54db..136cd883e26c 100644 --- a/tests/ui/union/union-derive-eq.mirunsafeck.stderr +++ b/tests/ui/union/union-derive-eq.mirunsafeck.stderr @@ -12,7 +12,8 @@ note: required by a bound in `AssertParamIsEq` = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `PartialEqNotEq` with `#[derive(Eq)]` | -LL | #[derive(Eq)] +LL + #[derive(Eq)] +LL | struct PartialEqNotEq; | error: aborting due to previous error diff --git a/tests/ui/union/union-derive-eq.thirunsafeck.stderr b/tests/ui/union/union-derive-eq.thirunsafeck.stderr index 9e55390b54db..136cd883e26c 100644 --- a/tests/ui/union/union-derive-eq.thirunsafeck.stderr +++ b/tests/ui/union/union-derive-eq.thirunsafeck.stderr @@ -12,7 +12,8 @@ note: required by a bound in `AssertParamIsEq` = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `PartialEqNotEq` with `#[derive(Eq)]` | -LL | #[derive(Eq)] +LL + #[derive(Eq)] +LL | struct PartialEqNotEq; | error: aborting due to previous error diff --git a/tests/ui/unresolved/unresolved-candidates.stderr b/tests/ui/unresolved/unresolved-candidates.stderr index ea737c567b96..53f63c1c840c 100644 --- a/tests/ui/unresolved/unresolved-candidates.stderr +++ b/tests/ui/unresolved/unresolved-candidates.stderr @@ -17,7 +17,8 @@ LL | impl Trait for () {} | help: consider importing this trait | -LL | use a::Trait; +LL + use a::Trait; +LL | impl Trait for () {} | error: aborting due to 2 previous errors diff --git a/tests/ui/wf/wf-const-type.stderr b/tests/ui/wf/wf-const-type.stderr index 85938364ede1..617969720a60 100644 --- a/tests/ui/wf/wf-const-type.stderr +++ b/tests/ui/wf/wf-const-type.stderr @@ -12,7 +12,8 @@ LL | struct IsCopy { t: T } | ^^^^ required by this bound in `IsCopy` help: consider annotating `NotCopy` with `#[derive(Copy)]` | -LL | #[derive(Copy)] +LL + #[derive(Copy)] +LL | struct NotCopy; | error: aborting due to previous error diff --git a/tests/ui/wf/wf-static-type.stderr b/tests/ui/wf/wf-static-type.stderr index 16c6124b6529..bb5a57834ebd 100644 --- a/tests/ui/wf/wf-static-type.stderr +++ b/tests/ui/wf/wf-static-type.stderr @@ -12,7 +12,8 @@ LL | struct IsCopy { t: T } | ^^^^ required by this bound in `IsCopy` help: consider annotating `NotCopy` with `#[derive(Copy)]` | -LL | #[derive(Copy)] +LL + #[derive(Copy)] +LL | struct NotCopy; | error: aborting due to previous error diff --git a/tests/ui/where-clauses/where-clauses-method-unsatisfied.stderr b/tests/ui/where-clauses/where-clauses-method-unsatisfied.stderr index e90502977ff6..6cf717295141 100644 --- a/tests/ui/where-clauses/where-clauses-method-unsatisfied.stderr +++ b/tests/ui/where-clauses/where-clauses-method-unsatisfied.stderr @@ -11,7 +11,8 @@ LL | fn equals(&self, u: &Foo) -> bool where T : Eq { | ^^ required by this bound in `Foo::::equals` help: consider annotating `Bar` with `#[derive(Eq)]` | -LL | #[derive(Eq)] +LL + #[derive(Eq)] +LL | struct Bar; // does not implement Eq | error: aborting due to previous error diff --git a/tests/ui/where-clauses/where-clauses-unsatisfied.stderr b/tests/ui/where-clauses/where-clauses-unsatisfied.stderr index b1805a4522f4..4d239bf43079 100644 --- a/tests/ui/where-clauses/where-clauses-unsatisfied.stderr +++ b/tests/ui/where-clauses/where-clauses-unsatisfied.stderr @@ -11,7 +11,8 @@ LL | fn equal(a: &T, b: &T) -> bool where T : Eq { a == b } | ^^ required by this bound in `equal` help: consider annotating `Struct` with `#[derive(Eq)]` | -LL | #[derive(Eq)] +LL + #[derive(Eq)] +LL | struct Struct; | error: aborting due to previous error From 9fadcc143a49a124fa1d0d3261593defb986a987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 10 Apr 2023 16:46:12 +0000 Subject: [PATCH 237/272] Special-case item attributes in the suggestion output --- compiler/rustc_errors/src/emitter.rs | 11 ++++++++++- src/tools/clippy/tests/ui/crashes/ice-6252.stderr | 3 --- .../clippy/tests/ui/new_without_default.stderr | 6 ------ tests/ui/coherence/coherence_inherent.stderr | 1 - tests/ui/coherence/coherence_inherent_cc.stderr | 1 - .../generic_const_exprs/issue-94287.stderr | 1 - tests/ui/const-generics/issues/issue-82956.stderr | 4 ---- tests/ui/derived-errors/issue-31997-1.stderr | 1 - .../issue-56028-there-is-an-enum-variant.stderr | 4 ---- tests/ui/hygiene/globs.stderr | 2 -- tests/ui/hygiene/no_implicit_prelude.stderr | 2 -- tests/ui/hygiene/trait_items.stderr | 1 - .../impl-trait/no-method-suggested-traits.stderr | 12 ------------ tests/ui/impl-trait/universal_wrong_bounds.stderr | 2 -- tests/ui/imports/glob-resolve1.stderr | 1 - tests/ui/imports/issue-38293.stderr | 1 - tests/ui/imports/issue-4366-2.stderr | 1 - tests/ui/imports/issue-4366.stderr | 1 - tests/ui/imports/overlapping_pub_trait.stderr | 1 - tests/ui/imports/unnamed_pub_trait.stderr | 1 - tests/ui/issues/issue-10465.stderr | 1 - tests/ui/issues/issue-17546.stderr | 8 -------- tests/ui/issues/issue-35976.unimported.stderr | 1 - tests/ui/issues/issue-37534.stderr | 1 - tests/ui/issues/issue-39175.stderr | 1 - tests/ui/issues/issue-56175.stderr | 2 -- tests/ui/issues/issue-77919.stderr | 1 - tests/ui/layout/issue-84108.stderr | 2 -- tests/ui/macros/issue-100199.stderr | 1 - tests/ui/macros/macro-outer-attributes.stderr | 1 - tests/ui/namespace/namespace-mix.stderr | 8 -------- tests/ui/parser/circular_modules_main.stderr | 1 - tests/ui/privacy/privacy-ns1.stderr | 3 --- tests/ui/privacy/privacy-ns2.stderr | 3 --- tests/ui/proc-macro/amputate-span.stderr | 2 -- .../proc-macro/attributes-on-modules-fail.stderr | 2 -- tests/ui/resolve/crate-in-paths.stderr | 1 - tests/ui/resolve/enums-are-namespaced-xc.stderr | 3 --- tests/ui/resolve/filter-intrinsics.stderr | 2 -- tests/ui/resolve/issue-102946.stderr | 1 - tests/ui/resolve/issue-16058.stderr | 3 --- tests/ui/resolve/issue-17518.stderr | 1 - tests/ui/resolve/issue-21221-1.stderr | 7 ------- tests/ui/resolve/issue-21221-2.stderr | 2 -- tests/ui/resolve/issue-21221-3.stderr | 1 - tests/ui/resolve/issue-21221-4.stderr | 1 - tests/ui/resolve/issue-2356.stderr | 1 - tests/ui/resolve/issue-26545.stderr | 1 - tests/ui/resolve/issue-35675.stderr | 2 -- tests/ui/resolve/issue-3907.stderr | 1 - tests/ui/resolve/issue-50599.stderr | 2 -- tests/ui/resolve/issue-73427.stderr | 2 -- tests/ui/resolve/issue-90113.stderr | 1 - tests/ui/resolve/missing-in-namespace.stderr | 1 - .../ui/resolve/no-implicit-prelude-nested.stderr | 15 --------------- tests/ui/resolve/no-implicit-prelude.stderr | 5 ----- tests/ui/resolve/privacy-enum-ctor.stderr | 4 ---- .../ui/resolve/resolve-primitive-fallback.stderr | 1 - tests/ui/resolve/use_suggestion.stderr | 2 -- tests/ui/resolve/use_suggestion_placement.stderr | 3 --- .../rust-2018/issue-52202-use-suggestions.stderr | 4 ---- .../ui/rust-2018/trait-import-suggestions.stderr | 3 --- .../ui/rust-2018/uniform-paths/issue-87932.stderr | 1 - .../future-prelude-collision-shadow.stderr | 2 -- tests/ui/self/class-missing-self.stderr | 1 - tests/ui/shadowed/shadowed-trait-methods.stderr | 1 - ...021-incompatible-closure-captures-96258.stderr | 1 - tests/ui/span/issue-35987.stderr | 1 - .../core-std-import-order-issue-83564.stderr | 2 -- .../dont-wrap-ambiguous-receivers.stderr | 2 -- .../import-trait-for-method-call.stderr | 1 - .../ui/suggestions/no-extern-crate-in-type.stderr | 1 - .../ui/suggestions/raw-name-use-suggestion.stderr | 1 - .../suggest-tryinto-edition-change.stderr | 7 ------- tests/ui/suggestions/use-placement-resolve.stderr | 1 - tests/ui/suggestions/use-placement-typeck.stderr | 1 - .../impl-bound-with-references-error.stderr | 1 - ...shadowed-path-in-trait-bound-suggestion.stderr | 1 - tests/ui/traits/issue-78372.stderr | 1 - tests/ui/traits/item-privacy.stderr | 3 --- tests/ui/traits/method-private.stderr | 1 - tests/ui/typeck/issue-43189.stderr | 1 - tests/ui/underscore-imports/shadow.stderr | 1 - tests/ui/unresolved/unresolved-candidates.stderr | 1 - 84 files changed, 10 insertions(+), 188 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 7b6d65511c15..fe44799efdb6 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1886,6 +1886,7 @@ impl EmitterWriter { } let mut unhighlighted_lines = Vec::new(); let mut last_pos = 0; + let mut is_item_attribute = false; for (line_pos, (line, highlight_parts)) in lines.by_ref().zip(highlights).enumerate() { last_pos = line_pos; debug!(%line_pos, %line, ?highlight_parts); @@ -1895,6 +1896,12 @@ impl EmitterWriter { unhighlighted_lines.push((line_pos, line)); continue; } + if highlight_parts.len() == 1 + && line.trim().starts_with("#[") + && line.trim().ends_with(']') + { + is_item_attribute = true; + } match unhighlighted_lines.len() { 0 => (), @@ -1971,11 +1978,13 @@ impl EmitterWriter { is_multiline, ) } - if let DisplaySuggestion::Add = show_code_change { + if let DisplaySuggestion::Add = show_code_change && is_item_attribute { // The suggestion adds an entire line of code, ending on a newline, so we'll also // print the *following* line, to provide context of what we're advicing people to // do. Otherwise you would only see contextless code that can be confused for // already existing code, despite the colors and UI elements. + // We special case `#[derive(_)]\n` and other attribute suggestions, because those + // are the ones where context is most useful. let file_lines = sm .span_to_lines(span.primary_span().unwrap().shrink_to_hi()) .expect("span_to_lines failed when emitting suggestion"); diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr index 3c7e08ebeae8..4787282f504a 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr @@ -7,13 +7,10 @@ LL | _n: PhantomData, help: consider importing one of these items | LL + use core::marker::PhantomData; -LL | trait TypeVal { | LL + use serde::__private::PhantomData; -LL | trait TypeVal { | LL + use std::marker::PhantomData; -LL | trait TypeVal { | error[E0412]: cannot find type `VAL` in this scope diff --git a/src/tools/clippy/tests/ui/new_without_default.stderr b/src/tools/clippy/tests/ui/new_without_default.stderr index 9b0a2f6ca5bf..583dd327d6a5 100644 --- a/src/tools/clippy/tests/ui/new_without_default.stderr +++ b/src/tools/clippy/tests/ui/new_without_default.stderr @@ -14,7 +14,6 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } -LL | impl Foo { | error: you should consider adding a `Default` implementation for `Bar` @@ -32,7 +31,6 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } -LL | impl Bar { | error: you should consider adding a `Default` implementation for `LtKo<'c>` @@ -50,7 +48,6 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } -LL | impl<'c> LtKo<'c> { | error: you should consider adding a `Default` implementation for `NewNotEqualToDerive` @@ -68,7 +65,6 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } -LL | impl NewNotEqualToDerive { | error: you should consider adding a `Default` implementation for `FooGenerics` @@ -86,7 +82,6 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } -LL | impl FooGenerics { | error: you should consider adding a `Default` implementation for `BarGenerics` @@ -104,7 +99,6 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } -LL | impl BarGenerics { | error: you should consider adding a `Default` implementation for `Foo` diff --git a/tests/ui/coherence/coherence_inherent.stderr b/tests/ui/coherence/coherence_inherent.stderr index 48f70700046f..b381b0680734 100644 --- a/tests/ui/coherence/coherence_inherent.stderr +++ b/tests/ui/coherence/coherence_inherent.stderr @@ -8,7 +8,6 @@ LL | s.the_fn(); help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use Lib::TheTrait; -LL | use Lib::TheStruct; | error: aborting due to previous error diff --git a/tests/ui/coherence/coherence_inherent_cc.stderr b/tests/ui/coherence/coherence_inherent_cc.stderr index 58254740f82e..7b6cb7d4390b 100644 --- a/tests/ui/coherence/coherence_inherent_cc.stderr +++ b/tests/ui/coherence/coherence_inherent_cc.stderr @@ -8,7 +8,6 @@ LL | s.the_fn(); help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use coherence_inherent_cc_lib::TheTrait; -LL | use coherence_inherent_cc_lib::TheStruct; | error: aborting due to previous error diff --git a/tests/ui/const-generics/generic_const_exprs/issue-94287.stderr b/tests/ui/const-generics/generic_const_exprs/issue-94287.stderr index 1e4e4edb596b..dc7d0c54fcc9 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-94287.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-94287.stderr @@ -9,7 +9,6 @@ help: consider enabling this feature --> $DIR/issue-94287.rs:1:1 | LL + #![feature(generic_const_exprs)] -LL | #![feature(generic_const_exprs)] | error: aborting due to previous error diff --git a/tests/ui/const-generics/issues/issue-82956.stderr b/tests/ui/const-generics/issues/issue-82956.stderr index d1d507325510..d70c8d0bfbf3 100644 --- a/tests/ui/const-generics/issues/issue-82956.stderr +++ b/tests/ui/const-generics/issues/issue-82956.stderr @@ -7,16 +7,12 @@ LL | let mut iter = IntoIter::new(self); help: consider importing one of these items | LL + use std::array::IntoIter; -LL | pub struct ConstCheck; | LL + use std::collections::binary_heap::IntoIter; -LL | pub struct ConstCheck; | LL + use std::collections::btree_map::IntoIter; -LL | pub struct ConstCheck; | LL + use std::collections::btree_set::IntoIter; -LL | pub struct ConstCheck; | and 8 other candidates diff --git a/tests/ui/derived-errors/issue-31997-1.stderr b/tests/ui/derived-errors/issue-31997-1.stderr index 2ea3d910dbfa..a0262f4c1e59 100644 --- a/tests/ui/derived-errors/issue-31997-1.stderr +++ b/tests/ui/derived-errors/issue-31997-1.stderr @@ -7,7 +7,6 @@ LL | let mut map = HashMap::new(); help: consider importing this struct | LL + use std::collections::HashMap; -LL | use std::io::prelude::*; | error: aborting due to previous error diff --git a/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr b/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr index 11cdcfadef36..5c610f36322d 100644 --- a/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr +++ b/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr @@ -25,16 +25,12 @@ LL | fn setup() -> Set { Set } help: consider importing one of these items | LL + use AffixHeart::Set; -LL | enum PutDown { Set } | LL + use CauseToBe::Set; -LL | enum PutDown { Set } | LL + use Determine::Set; -LL | enum PutDown { Set } | LL + use PutDown::Set; -LL | enum PutDown { Set } | and 3 other candidates diff --git a/tests/ui/hygiene/globs.stderr b/tests/ui/hygiene/globs.stderr index b68950b66dba..180172644402 100644 --- a/tests/ui/hygiene/globs.stderr +++ b/tests/ui/hygiene/globs.stderr @@ -14,7 +14,6 @@ LL | g(); help: consider importing this function | LL + use foo::f; -LL | mod foo { | error[E0425]: cannot find function `g` in this scope @@ -41,7 +40,6 @@ LL | f(); help: consider importing this function | LL + use bar::g; -LL | mod foo { | error[E0425]: cannot find function `f` in this scope diff --git a/tests/ui/hygiene/no_implicit_prelude.stderr b/tests/ui/hygiene/no_implicit_prelude.stderr index 21cecfefd349..96187b1c5016 100644 --- a/tests/ui/hygiene/no_implicit_prelude.stderr +++ b/tests/ui/hygiene/no_implicit_prelude.stderr @@ -11,7 +11,6 @@ LL | Vec::new(); help: consider importing this struct | LL + use std::vec::Vec; -LL | pub macro m() { Vec::::new(); ().clone() } | error[E0599]: no method named `clone` found for unit type `()` in the current scope @@ -28,7 +27,6 @@ LL | ().clone() help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use std::clone::Clone; -LL | pub macro m() { Vec::::new(); ().clone() } | error: aborting due to 2 previous errors diff --git a/tests/ui/hygiene/trait_items.stderr b/tests/ui/hygiene/trait_items.stderr index 60cf6787f82f..f303534c709f 100644 --- a/tests/ui/hygiene/trait_items.stderr +++ b/tests/ui/hygiene/trait_items.stderr @@ -15,7 +15,6 @@ LL | pub macro m() { ().f() } help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use foo::T; -LL | use foo::*; | error: aborting due to previous error diff --git a/tests/ui/impl-trait/no-method-suggested-traits.stderr b/tests/ui/impl-trait/no-method-suggested-traits.stderr index 0d37ea38b58c..160cc044078e 100644 --- a/tests/ui/impl-trait/no-method-suggested-traits.stderr +++ b/tests/ui/impl-trait/no-method-suggested-traits.stderr @@ -8,16 +8,12 @@ LL | 1u32.method(); help: the following traits are implemented but not in scope; perhaps add a `use` for one of them: | LL + use foo::Bar; -LL | extern crate no_method_suggested_traits; | LL + use no_method_suggested_traits::Reexported; -LL | extern crate no_method_suggested_traits; | LL + use no_method_suggested_traits::foo::PubPub; -LL | extern crate no_method_suggested_traits; | LL + use no_method_suggested_traits::qux::PrivPub; -LL | extern crate no_method_suggested_traits; | error[E0599]: no method named `method` found for struct `Rc<&mut Box<&u32>>` in the current scope @@ -30,16 +26,12 @@ LL | std::rc::Rc::new(&mut Box::new(&1u32)).method(); help: the following traits are implemented but not in scope; perhaps add a `use` for one of them: | LL + use foo::Bar; -LL | extern crate no_method_suggested_traits; | LL + use no_method_suggested_traits::Reexported; -LL | extern crate no_method_suggested_traits; | LL + use no_method_suggested_traits::foo::PubPub; -LL | extern crate no_method_suggested_traits; | LL + use no_method_suggested_traits::qux::PrivPub; -LL | extern crate no_method_suggested_traits; | error[E0599]: no method named `method` found for type `char` in the current scope @@ -55,7 +47,6 @@ LL | 'a'.method(); help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use foo::Bar; -LL | extern crate no_method_suggested_traits; | error[E0599]: no method named `method` found for struct `Rc<&mut Box<&char>>` in the current scope @@ -68,7 +59,6 @@ LL | std::rc::Rc::new(&mut Box::new(&'a')).method(); help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use foo::Bar; -LL | extern crate no_method_suggested_traits; | error[E0599]: no method named `method` found for type `i32` in the current scope @@ -86,7 +76,6 @@ LL | fn method(&self) {} help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use no_method_suggested_traits::foo::PubPub; -LL | extern crate no_method_suggested_traits; | error[E0599]: no method named `method` found for struct `Rc<&mut Box<&i32>>` in the current scope @@ -99,7 +88,6 @@ LL | std::rc::Rc::new(&mut Box::new(&1i32)).method(); help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use no_method_suggested_traits::foo::PubPub; -LL | extern crate no_method_suggested_traits; | error[E0599]: no method named `method` found for struct `Foo` in the current scope diff --git a/tests/ui/impl-trait/universal_wrong_bounds.stderr b/tests/ui/impl-trait/universal_wrong_bounds.stderr index 1561708efba3..464d689589e9 100644 --- a/tests/ui/impl-trait/universal_wrong_bounds.stderr +++ b/tests/ui/impl-trait/universal_wrong_bounds.stderr @@ -7,7 +7,6 @@ LL | fn wants_debug(g: impl Debug) { } help: consider importing this trait instead | LL + use std::fmt::Debug; -LL | use std::fmt::Display; | error[E0404]: expected trait, found derive macro `Debug` @@ -19,7 +18,6 @@ LL | fn wants_display(g: impl Debug) { } help: consider importing this trait instead | LL + use std::fmt::Debug; -LL | use std::fmt::Display; | error: aborting due to 2 previous errors diff --git a/tests/ui/imports/glob-resolve1.stderr b/tests/ui/imports/glob-resolve1.stderr index 6d7ceb25a8fd..4401ef58732e 100644 --- a/tests/ui/imports/glob-resolve1.stderr +++ b/tests/ui/imports/glob-resolve1.stderr @@ -61,7 +61,6 @@ LL | import(); help: consider importing this function | LL + use other::import; -LL | use bar::*; | error[E0412]: cannot find type `A` in this scope diff --git a/tests/ui/imports/issue-38293.stderr b/tests/ui/imports/issue-38293.stderr index 7a3b405a7822..1bb7ae29e108 100644 --- a/tests/ui/imports/issue-38293.stderr +++ b/tests/ui/imports/issue-38293.stderr @@ -13,7 +13,6 @@ LL | baz(); help: consider importing this function instead | LL + use bar::baz; -LL | use foo::f::{self}; | error: aborting due to 2 previous errors diff --git a/tests/ui/imports/issue-4366-2.stderr b/tests/ui/imports/issue-4366-2.stderr index d8539f9a9d4f..412423f4d595 100644 --- a/tests/ui/imports/issue-4366-2.stderr +++ b/tests/ui/imports/issue-4366-2.stderr @@ -19,7 +19,6 @@ LL | foo(); help: consider importing this function instead | LL + use foo::foo; -LL | use m1::*; | error: aborting due to 2 previous errors diff --git a/tests/ui/imports/issue-4366.stderr b/tests/ui/imports/issue-4366.stderr index 724db83e99ad..4d5b392a7e10 100644 --- a/tests/ui/imports/issue-4366.stderr +++ b/tests/ui/imports/issue-4366.stderr @@ -7,7 +7,6 @@ LL | fn sub() -> isize { foo(); 1 } help: consider importing this function | LL + use foo::foo; -LL | use a::b::*; | error: aborting due to previous error diff --git a/tests/ui/imports/overlapping_pub_trait.stderr b/tests/ui/imports/overlapping_pub_trait.stderr index 268709e11b67..490dccd3e808 100644 --- a/tests/ui/imports/overlapping_pub_trait.stderr +++ b/tests/ui/imports/overlapping_pub_trait.stderr @@ -13,7 +13,6 @@ LL | pub trait Tr { fn method(&self); } help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use overlapping_pub_trait_source::m::Tr; -LL | extern crate overlapping_pub_trait_source; | error: aborting due to previous error diff --git a/tests/ui/imports/unnamed_pub_trait.stderr b/tests/ui/imports/unnamed_pub_trait.stderr index 47fa6d3a3988..5133273c22f6 100644 --- a/tests/ui/imports/unnamed_pub_trait.stderr +++ b/tests/ui/imports/unnamed_pub_trait.stderr @@ -13,7 +13,6 @@ LL | pub trait Tr { fn method(&self); } help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use unnamed_pub_trait_source::prelude::*; // trait Tr -LL | extern crate unnamed_pub_trait_source; | error: aborting due to previous error diff --git a/tests/ui/issues/issue-10465.stderr b/tests/ui/issues/issue-10465.stderr index 9941e14a94e0..1b7b9d5909eb 100644 --- a/tests/ui/issues/issue-10465.stderr +++ b/tests/ui/issues/issue-10465.stderr @@ -8,7 +8,6 @@ LL | b.foo(); help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use a::A; -LL | use b::B; | error: aborting due to previous error diff --git a/tests/ui/issues/issue-17546.stderr b/tests/ui/issues/issue-17546.stderr index 23a12fa167b7..cf7ed1bbd668 100644 --- a/tests/ui/issues/issue-17546.stderr +++ b/tests/ui/issues/issue-17546.stderr @@ -25,16 +25,12 @@ LL | fn new() -> Result { help: consider importing one of these items instead | LL + use std::fmt::Result; -LL | use foo::MyEnum::Result; | LL + use std::io::Result; -LL | use foo::MyEnum::Result; | LL + use std::result::Result; -LL | use foo::MyEnum::Result; | LL + use std::thread::Result; -LL | use foo::MyEnum::Result; | error[E0573]: expected type, found variant `Result` @@ -46,16 +42,12 @@ LL | fn new() -> Result { help: consider importing one of these items instead | LL + use std::fmt::Result; -LL | use foo::MyEnum::Result; | LL + use std::io::Result; -LL | use foo::MyEnum::Result; | LL + use std::result::Result; -LL | use foo::MyEnum::Result; | LL + use std::thread::Result; -LL | use foo::MyEnum::Result; | error[E0573]: expected type, found variant `NoResult` diff --git a/tests/ui/issues/issue-35976.unimported.stderr b/tests/ui/issues/issue-35976.unimported.stderr index 8a3e2fcd0833..b31d2a31551e 100644 --- a/tests/ui/issues/issue-35976.unimported.stderr +++ b/tests/ui/issues/issue-35976.unimported.stderr @@ -10,7 +10,6 @@ LL | arg.wait(); help: another candidate was found in the following trait, perhaps add a `use` for it: | LL + use private::Future; -LL | mod private { | error: aborting due to previous error diff --git a/tests/ui/issues/issue-37534.stderr b/tests/ui/issues/issue-37534.stderr index 8449eb9c6925..7d3dd8800bd3 100644 --- a/tests/ui/issues/issue-37534.stderr +++ b/tests/ui/issues/issue-37534.stderr @@ -7,7 +7,6 @@ LL | struct Foo { } help: consider importing this trait instead | LL + use std::hash::Hash; -LL | struct Foo { } | warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported diff --git a/tests/ui/issues/issue-39175.stderr b/tests/ui/issues/issue-39175.stderr index 19e7f5162a77..3a1476ac0e3a 100644 --- a/tests/ui/issues/issue-39175.stderr +++ b/tests/ui/issues/issue-39175.stderr @@ -8,7 +8,6 @@ LL | Command::new("echo").arg("hello").exec(); help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use std::os::unix::process::CommandExt; -LL | use std::process::Command; | error: aborting due to previous error diff --git a/tests/ui/issues/issue-56175.stderr b/tests/ui/issues/issue-56175.stderr index bedbaef29b9c..1ddee1f4895b 100644 --- a/tests/ui/issues/issue-56175.stderr +++ b/tests/ui/issues/issue-56175.stderr @@ -13,7 +13,6 @@ LL | fn trait_method(&self) { help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use reexported_trait::Trait; -LL | fn main() { | error[E0599]: no method named `trait_method_b` found for struct `FooStruct` in the current scope @@ -31,7 +30,6 @@ LL | fn trait_method_b(&self) { help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use reexported_trait::TraitBRename; -LL | fn main() { | error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-77919.stderr b/tests/ui/issues/issue-77919.stderr index 1f3f6cb33c7f..d6dcc8997b9a 100644 --- a/tests/ui/issues/issue-77919.stderr +++ b/tests/ui/issues/issue-77919.stderr @@ -7,7 +7,6 @@ LL | _n: PhantomData, help: consider importing this struct | LL + use std::marker::PhantomData; -LL | fn main() { | error[E0412]: cannot find type `VAL` in this scope diff --git a/tests/ui/layout/issue-84108.stderr b/tests/ui/layout/issue-84108.stderr index cdc21df79a7e..5ad450bed078 100644 --- a/tests/ui/layout/issue-84108.stderr +++ b/tests/ui/layout/issue-84108.stderr @@ -7,7 +7,6 @@ LL | static FOO: (dyn AsRef, u8) = ("hello", 42); help: consider importing this struct | LL + use std::ffi::OsStr; -LL | static FOO: (dyn AsRef, u8) = ("hello", 42); | error[E0412]: cannot find type `Path` in this scope @@ -19,7 +18,6 @@ LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42); help: consider importing this struct | LL + use std::path::Path; -LL | static FOO: (dyn AsRef, u8) = ("hello", 42); | error[E0277]: the size for values of type `[u8]` cannot be known at compilation time diff --git a/tests/ui/macros/issue-100199.stderr b/tests/ui/macros/issue-100199.stderr index ab6bc08b5f7c..89a6f585ce41 100644 --- a/tests/ui/macros/issue-100199.stderr +++ b/tests/ui/macros/issue-100199.stderr @@ -8,7 +8,6 @@ LL | #[issue_100199::struct_with_bound] help: consider importing this trait | LL + use traits::MyTrait; -LL | #[issue_100199::struct_with_bound] | error: aborting due to previous error diff --git a/tests/ui/macros/macro-outer-attributes.stderr b/tests/ui/macros/macro-outer-attributes.stderr index cfd1c7739ba4..0bdc3416f807 100644 --- a/tests/ui/macros/macro-outer-attributes.stderr +++ b/tests/ui/macros/macro-outer-attributes.stderr @@ -7,7 +7,6 @@ LL | a::bar(); help: consider importing this function | LL + use b::bar; -LL | macro_rules! test { ($nm:ident, | help: if you import `bar`, refer to it directly | diff --git a/tests/ui/namespace/namespace-mix.stderr b/tests/ui/namespace/namespace-mix.stderr index 216548180bc5..3ac5e96c5742 100644 --- a/tests/ui/namespace/namespace-mix.stderr +++ b/tests/ui/namespace/namespace-mix.stderr @@ -15,10 +15,8 @@ LL | check(m1::TS); help: consider importing one of these items instead | LL + use m2::S; -LL | use namespace_mix::*; | LL + use xm2::S; -LL | use namespace_mix::*; | help: if you import `S`, refer to it directly | @@ -45,10 +43,8 @@ LL | check(xm1::TS); help: consider importing one of these items instead | LL + use m2::S; -LL | use namespace_mix::*; | LL + use xm2::S; -LL | use namespace_mix::*; | help: if you import `S`, refer to it directly | @@ -73,10 +69,8 @@ LL | check(m7::TV); help: consider importing one of these items instead | LL + use m8::V; -LL | use namespace_mix::*; | LL + use xm8::V; -LL | use namespace_mix::*; | help: if you import `V`, refer to it directly | @@ -103,10 +97,8 @@ LL | check(xm7::TV); help: consider importing one of these items instead | LL + use m8::V; -LL | use namespace_mix::*; | LL + use xm8::V; -LL | use namespace_mix::*; | help: if you import `V`, refer to it directly | diff --git a/tests/ui/parser/circular_modules_main.stderr b/tests/ui/parser/circular_modules_main.stderr index 2804c6ebf509..2de70789358b 100644 --- a/tests/ui/parser/circular_modules_main.stderr +++ b/tests/ui/parser/circular_modules_main.stderr @@ -13,7 +13,6 @@ LL | println!("{}", circular_modules_main::hi_str()); help: consider importing this function | LL + use hi_str; -LL | #[path = "circular_modules_main.rs"] | help: if you import `hi_str`, refer to it directly | diff --git a/tests/ui/privacy/privacy-ns1.stderr b/tests/ui/privacy/privacy-ns1.stderr index fe3e4a78a84b..9710cc48637b 100644 --- a/tests/ui/privacy/privacy-ns1.stderr +++ b/tests/ui/privacy/privacy-ns1.stderr @@ -14,7 +14,6 @@ LL | Baz(); help: consider importing this function instead | LL + use foo2::Bar; -LL | pub mod foo1 { | error[E0425]: cannot find function, tuple struct or tuple variant `Bar` in this scope @@ -33,7 +32,6 @@ LL | Baz(); help: consider importing this function | LL + use foo2::Bar; -LL | pub mod foo1 { | error[E0412]: cannot find type `Bar` in this scope @@ -52,7 +50,6 @@ LL | let _x: Box; help: consider importing this trait | LL + use foo1::Bar; -LL | pub mod foo1 { | error[E0747]: constant provided when a type was expected diff --git a/tests/ui/privacy/privacy-ns2.stderr b/tests/ui/privacy/privacy-ns2.stderr index 73a24bd20f33..75e735e1e6a2 100644 --- a/tests/ui/privacy/privacy-ns2.stderr +++ b/tests/ui/privacy/privacy-ns2.stderr @@ -7,7 +7,6 @@ LL | Bar(); help: consider importing this function instead | LL + use foo2::Bar; -LL | pub mod foo1 { | error[E0423]: expected function, tuple struct or tuple variant, found trait `Bar` @@ -26,7 +25,6 @@ LL | Baz(); help: consider importing this function instead | LL + use foo2::Bar; -LL | pub mod foo1 { | error[E0573]: expected type, found function `Bar` @@ -42,7 +40,6 @@ LL | let _x = Bar(); help: consider importing this trait instead | LL + use foo1::Bar; -LL | pub mod foo1 { | error[E0603]: trait `Bar` is private diff --git a/tests/ui/proc-macro/amputate-span.stderr b/tests/ui/proc-macro/amputate-span.stderr index fa83707e79d5..aa797339be46 100644 --- a/tests/ui/proc-macro/amputate-span.stderr +++ b/tests/ui/proc-macro/amputate-span.stderr @@ -7,7 +7,6 @@ LL | Command::new("git"); help: consider importing this struct | LL + use std::process::Command; -LL | #[amputate_span::drop_first_token] | error[E0433]: failed to resolve: use of undeclared type `Command` @@ -19,7 +18,6 @@ LL | Command::new("git"); help: consider importing this struct | LL + use std::process::Command; -LL | #[amputate_span::drop_first_token] | error: aborting due to 2 previous errors diff --git a/tests/ui/proc-macro/attributes-on-modules-fail.stderr b/tests/ui/proc-macro/attributes-on-modules-fail.stderr index a0ab9999c088..97521f23aeef 100644 --- a/tests/ui/proc-macro/attributes-on-modules-fail.stderr +++ b/tests/ui/proc-macro/attributes-on-modules-fail.stderr @@ -51,7 +51,6 @@ LL | type A = Y; help: consider importing this struct | LL + use Y; -LL | pub struct X; | error[E0412]: cannot find type `X` in this scope @@ -63,7 +62,6 @@ LL | type A = X; help: consider importing this struct | LL + use m::X; -LL | #[macro_use] | error: aborting due to 7 previous errors diff --git a/tests/ui/resolve/crate-in-paths.stderr b/tests/ui/resolve/crate-in-paths.stderr index 45ecf5a59adf..07fb5dcc035c 100644 --- a/tests/ui/resolve/crate-in-paths.stderr +++ b/tests/ui/resolve/crate-in-paths.stderr @@ -7,7 +7,6 @@ LL | Foo; help: consider importing this unit struct | LL + use crate::bar::Foo; -LL | mod bar { | error: aborting due to previous error diff --git a/tests/ui/resolve/enums-are-namespaced-xc.stderr b/tests/ui/resolve/enums-are-namespaced-xc.stderr index efebf15684b9..5af6cb04275b 100644 --- a/tests/ui/resolve/enums-are-namespaced-xc.stderr +++ b/tests/ui/resolve/enums-are-namespaced-xc.stderr @@ -7,7 +7,6 @@ LL | let _ = namespaced_enums::A; help: consider importing this unit variant | LL + use namespaced_enums::Foo::A; -LL | extern crate namespaced_enums; | help: if you import `A`, refer to it directly | @@ -24,7 +23,6 @@ LL | let _ = namespaced_enums::B(10); help: consider importing this tuple variant | LL + use namespaced_enums::Foo::B; -LL | extern crate namespaced_enums; | help: if you import `B`, refer to it directly | @@ -41,7 +39,6 @@ LL | let _ = namespaced_enums::C { a: 10 }; help: consider importing this variant | LL + use namespaced_enums::Foo::C; -LL | extern crate namespaced_enums; | help: if you import `C`, refer to it directly | diff --git a/tests/ui/resolve/filter-intrinsics.stderr b/tests/ui/resolve/filter-intrinsics.stderr index 3b4a09a25e7f..cc1092dd0cfa 100644 --- a/tests/ui/resolve/filter-intrinsics.stderr +++ b/tests/ui/resolve/filter-intrinsics.stderr @@ -7,7 +7,6 @@ LL | let _ = size_of::(); help: consider importing this function | LL + use std::mem::size_of; -LL | fn main() { | error[E0425]: cannot find function `fabsf64` in this scope @@ -19,7 +18,6 @@ LL | let _ = fabsf64(1.0); help: consider importing this function | LL + use std::intrinsics::fabsf64; -LL | fn main() { | error: aborting due to 2 previous errors diff --git a/tests/ui/resolve/issue-102946.stderr b/tests/ui/resolve/issue-102946.stderr index 738438492140..b2cdcb25c3f9 100644 --- a/tests/ui/resolve/issue-102946.stderr +++ b/tests/ui/resolve/issue-102946.stderr @@ -7,7 +7,6 @@ LL | impl Error for str::Utf8Error { help: consider importing this trait | LL + use std::error::Error; -LL | impl Error for str::Utf8Error { | error[E0223]: ambiguous associated type diff --git a/tests/ui/resolve/issue-16058.stderr b/tests/ui/resolve/issue-16058.stderr index 65dba047234a..710002a154ef 100644 --- a/tests/ui/resolve/issue-16058.stderr +++ b/tests/ui/resolve/issue-16058.stderr @@ -7,13 +7,10 @@ LL | Result { help: consider importing one of these items instead | LL + use std::fmt::Result; -LL | pub struct GslResult { | LL + use std::io::Result; -LL | pub struct GslResult { | LL + use std::thread::Result; -LL | pub struct GslResult { | error: aborting due to previous error diff --git a/tests/ui/resolve/issue-17518.stderr b/tests/ui/resolve/issue-17518.stderr index 19b59b841e04..492e3b34a179 100644 --- a/tests/ui/resolve/issue-17518.stderr +++ b/tests/ui/resolve/issue-17518.stderr @@ -7,7 +7,6 @@ LL | E { name: "foobar" }; help: consider importing this variant | LL + use SomeEnum::E; -LL | enum SomeEnum { | error: aborting due to previous error diff --git a/tests/ui/resolve/issue-21221-1.stderr b/tests/ui/resolve/issue-21221-1.stderr index 836ea564f4ee..a38116cd7287 100644 --- a/tests/ui/resolve/issue-21221-1.stderr +++ b/tests/ui/resolve/issue-21221-1.stderr @@ -7,13 +7,10 @@ LL | impl Mul for Foo { help: consider importing one of these items | LL + use mul1::Mul; -LL | mod mul1 { | LL + use mul2::Mul; -LL | mod mul1 { | LL + use std::ops::Mul; -LL | mod mul1 { | error[E0412]: cannot find type `Mul` in this scope @@ -25,13 +22,10 @@ LL | fn getMul() -> Mul { help: consider importing one of these items | LL + use mul1::Mul; -LL | mod mul1 { | LL + use mul2::Mul; -LL | mod mul1 { | LL + use std::ops::Mul; -LL | mod mul1 { | error[E0405]: cannot find trait `ThisTraitReallyDoesntExistInAnyModuleReally` in this scope @@ -49,7 +43,6 @@ LL | impl Div for Foo { help: consider importing this trait | LL + use std::ops::Div; -LL | mod mul1 { | error: aborting due to 4 previous errors diff --git a/tests/ui/resolve/issue-21221-2.stderr b/tests/ui/resolve/issue-21221-2.stderr index e88274e6c60b..9beb626623e4 100644 --- a/tests/ui/resolve/issue-21221-2.stderr +++ b/tests/ui/resolve/issue-21221-2.stderr @@ -7,10 +7,8 @@ LL | impl T for Foo { } help: consider importing one of these items | LL + use baz::T; -LL | pub mod foo { | LL + use foo::bar::T; -LL | pub mod foo { | error: aborting due to previous error diff --git a/tests/ui/resolve/issue-21221-3.stderr b/tests/ui/resolve/issue-21221-3.stderr index e02eaec05e3e..0dabdfd9b390 100644 --- a/tests/ui/resolve/issue-21221-3.stderr +++ b/tests/ui/resolve/issue-21221-3.stderr @@ -7,7 +7,6 @@ LL | impl OuterTrait for Foo {} help: consider importing this trait | LL + use issue_21221_3::outer::OuterTrait; -LL | extern crate issue_21221_3; | error: aborting due to previous error diff --git a/tests/ui/resolve/issue-21221-4.stderr b/tests/ui/resolve/issue-21221-4.stderr index e8c38ed6acf0..5af14b1b68d3 100644 --- a/tests/ui/resolve/issue-21221-4.stderr +++ b/tests/ui/resolve/issue-21221-4.stderr @@ -7,7 +7,6 @@ LL | impl T for Foo {} help: consider importing this trait | LL + use issue_21221_4::T; -LL | extern crate issue_21221_4; | error: aborting due to previous error diff --git a/tests/ui/resolve/issue-2356.stderr b/tests/ui/resolve/issue-2356.stderr index ed820f15c83e..313b3e30dd95 100644 --- a/tests/ui/resolve/issue-2356.stderr +++ b/tests/ui/resolve/issue-2356.stderr @@ -11,7 +11,6 @@ LL | Self::default(); help: consider importing this function | LL + use std::default::default; -LL | trait Groom { | error[E0425]: cannot find value `whiskers` in this scope diff --git a/tests/ui/resolve/issue-26545.stderr b/tests/ui/resolve/issue-26545.stderr index 2b98b5b8a7bf..42a7531c5b94 100644 --- a/tests/ui/resolve/issue-26545.stderr +++ b/tests/ui/resolve/issue-26545.stderr @@ -7,7 +7,6 @@ LL | B(()); help: consider importing this tuple struct | LL + use foo::B; -LL | fn foo() { | error: aborting due to previous error diff --git a/tests/ui/resolve/issue-35675.stderr b/tests/ui/resolve/issue-35675.stderr index d28561453715..44af65b0768a 100644 --- a/tests/ui/resolve/issue-35675.stderr +++ b/tests/ui/resolve/issue-35675.stderr @@ -18,7 +18,6 @@ LL | Apple(5) help: consider importing this tuple variant | LL + use Fruit::Apple; -LL | enum Fruit { | error[E0573]: expected type, found variant `Fruit::Apple` @@ -39,7 +38,6 @@ LL | Apple(5) help: consider importing this tuple variant | LL + use Fruit::Apple; -LL | enum Fruit { | error[E0573]: expected type, found variant `Ok` diff --git a/tests/ui/resolve/issue-3907.stderr b/tests/ui/resolve/issue-3907.stderr index 50ad668f8dbf..70631a13cdf8 100644 --- a/tests/ui/resolve/issue-3907.stderr +++ b/tests/ui/resolve/issue-3907.stderr @@ -11,7 +11,6 @@ LL | trait Foo = dyn issue_3907::Foo; help: consider importing this trait instead | LL + use issue_3907::Foo; -LL | extern crate issue_3907; | error: aborting due to previous error diff --git a/tests/ui/resolve/issue-50599.stderr b/tests/ui/resolve/issue-50599.stderr index 548d215b00ac..d7419b64facd 100644 --- a/tests/ui/resolve/issue-50599.stderr +++ b/tests/ui/resolve/issue-50599.stderr @@ -7,10 +7,8 @@ LL | const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize; help: consider importing one of these items | LL + use std::f32::consts::LOG10_2; -LL | fn main() { | LL + use std::f64::consts::LOG10_2; -LL | fn main() { | help: if you import `LOG10_2`, refer to it directly | diff --git a/tests/ui/resolve/issue-73427.stderr b/tests/ui/resolve/issue-73427.stderr index 5a663ae79bcb..622de9b39bde 100644 --- a/tests/ui/resolve/issue-73427.stderr +++ b/tests/ui/resolve/issue-73427.stderr @@ -108,10 +108,8 @@ LL | (E::TupleWithFields(/* fields */)).foo(); help: consider importing one of these items instead | LL + use std::f32::consts::E; -LL | enum A { | LL + use std::f64::consts::E; -LL | enum A { | error[E0532]: expected tuple struct or tuple variant, found enum `A` diff --git a/tests/ui/resolve/issue-90113.stderr b/tests/ui/resolve/issue-90113.stderr index a9d4b573f110..5f55d9c241a5 100644 --- a/tests/ui/resolve/issue-90113.stderr +++ b/tests/ui/resolve/issue-90113.stderr @@ -7,7 +7,6 @@ LL | Cons(..) => {} help: consider importing this tuple variant | LL + use list::List::Cons; -LL | mod list { | error: aborting due to previous error diff --git a/tests/ui/resolve/missing-in-namespace.stderr b/tests/ui/resolve/missing-in-namespace.stderr index 66f40102a3ed..7a7b749aebb7 100644 --- a/tests/ui/resolve/missing-in-namespace.stderr +++ b/tests/ui/resolve/missing-in-namespace.stderr @@ -7,7 +7,6 @@ LL | let _map = std::hahmap::HashMap::new(); help: consider importing this struct | LL + use std::collections::HashMap; -LL | fn main() { | help: if you import `HashMap`, refer to it directly | diff --git a/tests/ui/resolve/no-implicit-prelude-nested.stderr b/tests/ui/resolve/no-implicit-prelude-nested.stderr index 4df6c31d3164..49cf72bfee2d 100644 --- a/tests/ui/resolve/no-implicit-prelude-nested.stderr +++ b/tests/ui/resolve/no-implicit-prelude-nested.stderr @@ -7,7 +7,6 @@ LL | impl Add for Test {} help: consider importing this trait | LL + use std::ops::Add; -LL | struct Test; | error[E0404]: expected trait, found derive macro `Clone` @@ -19,7 +18,6 @@ LL | impl Clone for Test {} help: consider importing this trait instead | LL + use std::clone::Clone; -LL | struct Test; | error[E0405]: cannot find trait `Iterator` in this scope @@ -31,7 +29,6 @@ LL | impl Iterator for Test {} help: consider importing this trait | LL + use std::iter::Iterator; -LL | struct Test; | error[E0405]: cannot find trait `ToString` in this scope @@ -43,7 +40,6 @@ LL | impl ToString for Test {} help: consider importing this trait | LL + use std::string::ToString; -LL | struct Test; | error[E0405]: cannot find trait `Writer` in this scope @@ -61,7 +57,6 @@ LL | drop(2) help: consider importing this function | LL + use std::mem::drop; -LL | struct Test; | error[E0405]: cannot find trait `Add` in this scope @@ -73,7 +68,6 @@ LL | impl Add for Test {} help: consider importing this trait | LL + use std::ops::Add; -LL | mod baz { | error[E0404]: expected trait, found derive macro `Clone` @@ -85,7 +79,6 @@ LL | impl Clone for Test {} help: consider importing this trait instead | LL + use std::clone::Clone; -LL | mod baz { | error[E0405]: cannot find trait `Iterator` in this scope @@ -97,7 +90,6 @@ LL | impl Iterator for Test {} help: consider importing this trait | LL + use std::iter::Iterator; -LL | mod baz { | error[E0405]: cannot find trait `ToString` in this scope @@ -109,7 +101,6 @@ LL | impl ToString for Test {} help: consider importing this trait | LL + use std::string::ToString; -LL | mod baz { | error[E0405]: cannot find trait `Writer` in this scope @@ -127,7 +118,6 @@ LL | drop(2) help: consider importing this function | LL + use std::mem::drop; -LL | mod baz { | error[E0405]: cannot find trait `Add` in this scope @@ -139,7 +129,6 @@ LL | impl Add for Test {} help: consider importing this trait | LL + use std::ops::Add; -LL | struct Test; | error[E0404]: expected trait, found derive macro `Clone` @@ -151,7 +140,6 @@ LL | impl Clone for Test {} help: consider importing this trait instead | LL + use std::clone::Clone; -LL | struct Test; | error[E0405]: cannot find trait `Iterator` in this scope @@ -163,7 +151,6 @@ LL | impl Iterator for Test {} help: consider importing this trait | LL + use std::iter::Iterator; -LL | struct Test; | error[E0405]: cannot find trait `ToString` in this scope @@ -175,7 +162,6 @@ LL | impl ToString for Test {} help: consider importing this trait | LL + use std::string::ToString; -LL | struct Test; | error[E0405]: cannot find trait `Writer` in this scope @@ -193,7 +179,6 @@ LL | drop(2) help: consider importing this function | LL + use std::mem::drop; -LL | struct Test; | error: aborting due to 18 previous errors diff --git a/tests/ui/resolve/no-implicit-prelude.stderr b/tests/ui/resolve/no-implicit-prelude.stderr index a8e5f1b69e23..5a759743f725 100644 --- a/tests/ui/resolve/no-implicit-prelude.stderr +++ b/tests/ui/resolve/no-implicit-prelude.stderr @@ -7,7 +7,6 @@ LL | impl Add for Test {} help: consider importing this trait | LL + use std::ops::Add; -LL | struct Test; | error[E0404]: expected trait, found derive macro `Clone` @@ -19,7 +18,6 @@ LL | impl Clone for Test {} help: consider importing this trait instead | LL + use std::clone::Clone; -LL | struct Test; | error[E0405]: cannot find trait `Iterator` in this scope @@ -31,7 +29,6 @@ LL | impl Iterator for Test {} help: consider importing this trait | LL + use std::iter::Iterator; -LL | struct Test; | error[E0405]: cannot find trait `ToString` in this scope @@ -43,7 +40,6 @@ LL | impl ToString for Test {} help: consider importing this trait | LL + use std::string::ToString; -LL | struct Test; | error[E0405]: cannot find trait `Writer` in this scope @@ -61,7 +57,6 @@ LL | drop(2) help: consider importing this function | LL + use std::mem::drop; -LL | struct Test; | error: aborting due to 6 previous errors diff --git a/tests/ui/resolve/privacy-enum-ctor.stderr b/tests/ui/resolve/privacy-enum-ctor.stderr index 76dc25539d07..0bb09090569c 100644 --- a/tests/ui/resolve/privacy-enum-ctor.stderr +++ b/tests/ui/resolve/privacy-enum-ctor.stderr @@ -85,10 +85,8 @@ LL | let _: E = m::f; help: consider importing one of these items instead | LL + use std::f32::consts::E; -LL | use m::E; // OK, only the type is imported | LL + use std::f64::consts::E; -LL | use m::E; // OK, only the type is imported | help: if you import `E`, refer to it directly | @@ -124,10 +122,8 @@ LL | let _: E = (E::Fn(/* fields */)); help: consider importing one of these items instead | LL + use std::f32::consts::E; -LL | use m::E; // OK, only the type is imported | LL + use std::f64::consts::E; -LL | use m::E; // OK, only the type is imported | error[E0412]: cannot find type `Z` in this scope diff --git a/tests/ui/resolve/resolve-primitive-fallback.stderr b/tests/ui/resolve/resolve-primitive-fallback.stderr index 2227522d6eab..e3a5d4edcf10 100644 --- a/tests/ui/resolve/resolve-primitive-fallback.stderr +++ b/tests/ui/resolve/resolve-primitive-fallback.stderr @@ -13,7 +13,6 @@ LL | let _: ::u8; help: consider importing this builtin type | LL + use std::primitive::u8; -LL | fn main() { | help: if you import `u8`, refer to it directly | diff --git a/tests/ui/resolve/use_suggestion.stderr b/tests/ui/resolve/use_suggestion.stderr index a30dbd954e12..1155f5caa173 100644 --- a/tests/ui/resolve/use_suggestion.stderr +++ b/tests/ui/resolve/use_suggestion.stderr @@ -7,7 +7,6 @@ LL | let x1 = HashMap::new(); help: consider importing this struct | LL + use std::collections::HashMap; -LL | fn main() { | error[E0412]: cannot find type `HashMap` in this scope @@ -19,7 +18,6 @@ LL | let y1: HashMap; help: consider importing this struct | LL + use std::collections::HashMap; -LL | fn main() { | error[E0412]: cannot find type `GooMap` in this scope diff --git a/tests/ui/resolve/use_suggestion_placement.stderr b/tests/ui/resolve/use_suggestion_placement.stderr index 9288530ad2e8..3611f9ae6b4e 100644 --- a/tests/ui/resolve/use_suggestion_placement.stderr +++ b/tests/ui/resolve/use_suggestion_placement.stderr @@ -7,7 +7,6 @@ LL | type Bar = Path; help: consider importing this struct | LL + use std::path::Path; -LL | #[derive(Debug)] | error[E0425]: cannot find value `A` in this scope @@ -19,7 +18,6 @@ LL | let _ = A; help: consider importing this constant | LL + use m::A; -LL | macro_rules! y { | error[E0412]: cannot find type `HashMap` in this scope @@ -31,7 +29,6 @@ LL | type Dict = HashMap; help: consider importing this struct | LL + use std::collections::HashMap; -LL | macro_rules! y { | error: aborting due to 3 previous errors diff --git a/tests/ui/rust-2018/issue-52202-use-suggestions.stderr b/tests/ui/rust-2018/issue-52202-use-suggestions.stderr index 5450ede82230..9933b92439c1 100644 --- a/tests/ui/rust-2018/issue-52202-use-suggestions.stderr +++ b/tests/ui/rust-2018/issue-52202-use-suggestions.stderr @@ -7,16 +7,12 @@ LL | let _d = Drain {}; help: consider importing one of these items | LL + use crate::plumbing::Drain; -LL | mod plumbing { | LL + use std::collections::binary_heap::Drain; -LL | mod plumbing { | LL + use std::collections::hash_map::Drain; -LL | mod plumbing { | LL + use std::collections::hash_set::Drain; -LL | mod plumbing { | and 3 other candidates diff --git a/tests/ui/rust-2018/trait-import-suggestions.stderr b/tests/ui/rust-2018/trait-import-suggestions.stderr index 4be5c7b0d0c4..325c5976e7c8 100644 --- a/tests/ui/rust-2018/trait-import-suggestions.stderr +++ b/tests/ui/rust-2018/trait-import-suggestions.stderr @@ -11,7 +11,6 @@ LL | x.foobar(); help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use crate::foo::foobar::Foobar; -LL | mod foobar { | error[E0599]: no method named `bar` found for type `u32` in the current scope @@ -27,7 +26,6 @@ LL | x.bar(); help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use crate::foo::Bar; -LL | mod foo { | error[E0599]: no method named `baz` found for type `u32` in the current scope @@ -46,7 +44,6 @@ LL | let y = u32::from_str("33"); help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use std::str::FromStr; -LL | mod foo { | help: there is an associated function with a similar name | diff --git a/tests/ui/rust-2018/uniform-paths/issue-87932.stderr b/tests/ui/rust-2018/uniform-paths/issue-87932.stderr index e5e17f22c5f1..ac2baa3595bd 100644 --- a/tests/ui/rust-2018/uniform-paths/issue-87932.stderr +++ b/tests/ui/rust-2018/uniform-paths/issue-87932.stderr @@ -11,7 +11,6 @@ LL | A::deserialize(); help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use ::deserialize::_a::Deserialize; -LL | pub struct A {} | error: aborting due to previous error diff --git a/tests/ui/rust-2021/future-prelude-collision-shadow.stderr b/tests/ui/rust-2021/future-prelude-collision-shadow.stderr index 34bf68e8913f..9dfaf13e2ecd 100644 --- a/tests/ui/rust-2021/future-prelude-collision-shadow.stderr +++ b/tests/ui/rust-2021/future-prelude-collision-shadow.stderr @@ -9,10 +9,8 @@ LL | let _: u32 = 3u8.try_into().unwrap(); help: the following traits are implemented but not in scope; perhaps add a `use` for one of them: | LL + use crate::m::TryIntoU32; -LL | use crate::m::AnotherTrick as TryIntoU32; | LL + use std::convert::TryInto; -LL | use crate::m::AnotherTrick as TryIntoU32; | error: aborting due to previous error diff --git a/tests/ui/self/class-missing-self.stderr b/tests/ui/self/class-missing-self.stderr index 2f35b30dbcb0..3c37d8197432 100644 --- a/tests/ui/self/class-missing-self.stderr +++ b/tests/ui/self/class-missing-self.stderr @@ -17,7 +17,6 @@ LL | self.sleep(); help: consider importing this function | LL + use std::thread::sleep; -LL | struct Cat { | error: aborting due to 2 previous errors diff --git a/tests/ui/shadowed/shadowed-trait-methods.stderr b/tests/ui/shadowed/shadowed-trait-methods.stderr index 6d7ab27f3e15..1af0400c8861 100644 --- a/tests/ui/shadowed/shadowed-trait-methods.stderr +++ b/tests/ui/shadowed/shadowed-trait-methods.stderr @@ -11,7 +11,6 @@ LL | ().f() help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use foo::T; -LL | mod foo { | error: aborting due to previous error diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr index 626cc67d9eb9..60433e1c2846 100644 --- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr +++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr @@ -16,7 +16,6 @@ LL | interval: Duration, help: consider importing this struct | LL + use std::time::Duration; -LL | fn main() {} | error: aborting due to 2 previous errors diff --git a/tests/ui/span/issue-35987.stderr b/tests/ui/span/issue-35987.stderr index 0e64bcb01069..88c86d2a91b5 100644 --- a/tests/ui/span/issue-35987.stderr +++ b/tests/ui/span/issue-35987.stderr @@ -12,7 +12,6 @@ LL | impl Add for Foo { help: consider importing this trait instead | LL + use std::ops::Add; -LL | use std::ops::Add; | error: aborting due to previous error diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.stderr b/tests/ui/suggestions/core-std-import-order-issue-83564.stderr index c87ff9525532..48ee44a74f2d 100644 --- a/tests/ui/suggestions/core-std-import-order-issue-83564.stderr +++ b/tests/ui/suggestions/core-std-import-order-issue-83564.stderr @@ -7,10 +7,8 @@ LL | let _x = NonZeroU32::new(5).unwrap(); help: consider importing one of these items | LL + use core::num::NonZeroU32; -LL | fn main() { | LL + use std::num::NonZeroU32; -LL | fn main() { | error: aborting due to previous error diff --git a/tests/ui/suggestions/dont-wrap-ambiguous-receivers.stderr b/tests/ui/suggestions/dont-wrap-ambiguous-receivers.stderr index 6eced1d416e4..85fbb8b88e81 100644 --- a/tests/ui/suggestions/dont-wrap-ambiguous-receivers.stderr +++ b/tests/ui/suggestions/dont-wrap-ambiguous-receivers.stderr @@ -11,10 +11,8 @@ LL | banana::Chaenomeles.pick() help: the following traits are implemented but not in scope; perhaps add a `use` for one of them: | LL + use banana::Apple; -LL | mod banana { | LL + use banana::Peach; -LL | mod banana { | error: aborting due to previous error diff --git a/tests/ui/suggestions/import-trait-for-method-call.stderr b/tests/ui/suggestions/import-trait-for-method-call.stderr index 464fe85ac175..3f54daf136f6 100644 --- a/tests/ui/suggestions/import-trait-for-method-call.stderr +++ b/tests/ui/suggestions/import-trait-for-method-call.stderr @@ -11,7 +11,6 @@ LL | h.finish() help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use std::hash::Hasher; -LL | use std::hash::BuildHasher; | error[E0599]: the method `as_ref` exists for reference `&dyn Bar`, but its trait bounds were not satisfied diff --git a/tests/ui/suggestions/no-extern-crate-in-type.stderr b/tests/ui/suggestions/no-extern-crate-in-type.stderr index d8e53229f49f..68100e56cbc8 100644 --- a/tests/ui/suggestions/no-extern-crate-in-type.stderr +++ b/tests/ui/suggestions/no-extern-crate-in-type.stderr @@ -7,7 +7,6 @@ LL | type Output = Option; help: consider importing this struct | LL + use foo::Foo; -LL | extern crate foo; | error: aborting due to previous error diff --git a/tests/ui/suggestions/raw-name-use-suggestion.stderr b/tests/ui/suggestions/raw-name-use-suggestion.stderr index 733af9079d59..fb070ffc3323 100644 --- a/tests/ui/suggestions/raw-name-use-suggestion.stderr +++ b/tests/ui/suggestions/raw-name-use-suggestion.stderr @@ -29,7 +29,6 @@ LL | r#break(); help: consider importing this function | LL + use foo::r#break; -LL | mod foo { | error: aborting due to 3 previous errors diff --git a/tests/ui/suggestions/suggest-tryinto-edition-change.stderr b/tests/ui/suggestions/suggest-tryinto-edition-change.stderr index 525a5bc164de..671f5efddd97 100644 --- a/tests/ui/suggestions/suggest-tryinto-edition-change.stderr +++ b/tests/ui/suggestions/suggest-tryinto-edition-change.stderr @@ -9,10 +9,8 @@ LL | let _i: i16 = TryFrom::try_from(0_i32).unwrap(); help: consider importing one of these items | LL + use core::convert::TryFrom; -LL | fn test() { | LL + use std::convert::TryFrom; -LL | fn test() { | error[E0433]: failed to resolve: use of undeclared type `TryInto` @@ -26,10 +24,8 @@ LL | let _i: i16 = TryInto::try_into(0_i32).unwrap(); help: consider importing one of these items | LL + use core::convert::TryInto; -LL | fn test() { | LL + use std::convert::TryInto; -LL | fn test() { | error[E0433]: failed to resolve: use of undeclared type `FromIterator` @@ -47,10 +43,8 @@ LL | let _v: Vec<_> = IntoIterator::from_iter(&[1]); help: consider importing one of these items | LL + use core::iter::FromIterator; -LL | fn test() { | LL + use std::iter::FromIterator; -LL | fn test() { | error[E0599]: no method named `try_into` found for type `i32` in the current scope @@ -67,7 +61,6 @@ LL | let _i: i16 = 0_i32.try_into().unwrap(); help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use std::convert::TryInto; -LL | fn test() { | error: aborting due to 4 previous errors diff --git a/tests/ui/suggestions/use-placement-resolve.stderr b/tests/ui/suggestions/use-placement-resolve.stderr index 16cbc9edcef7..77724e7e2a47 100644 --- a/tests/ui/suggestions/use-placement-resolve.stderr +++ b/tests/ui/suggestions/use-placement-resolve.stderr @@ -7,7 +7,6 @@ LL | fn foobar(x: T) {} help: consider importing this trait instead | LL + use std::fmt::Debug; -LL | fn main() {} | error: aborting due to previous error diff --git a/tests/ui/suggestions/use-placement-typeck.stderr b/tests/ui/suggestions/use-placement-typeck.stderr index dc0586302f59..e900e12b7df0 100644 --- a/tests/ui/suggestions/use-placement-typeck.stderr +++ b/tests/ui/suggestions/use-placement-typeck.stderr @@ -14,7 +14,6 @@ LL | pub struct S; help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use m::Foo; -LL | fn main() { | error: aborting due to previous error diff --git a/tests/ui/trait-bounds/impl-bound-with-references-error.stderr b/tests/ui/trait-bounds/impl-bound-with-references-error.stderr index cc3b887cf072..b114d295d781 100644 --- a/tests/ui/trait-bounds/impl-bound-with-references-error.stderr +++ b/tests/ui/trait-bounds/impl-bound-with-references-error.stderr @@ -7,7 +7,6 @@ LL | T: Into>, help: consider importing this enum | LL + use std::borrow::Cow; -LL | pub enum LabelText { | error[E0119]: conflicting implementations of trait `From` for type `LabelText` diff --git a/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr b/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr index 60a86cc8e41e..4547e1c984c0 100644 --- a/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr +++ b/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr @@ -7,7 +7,6 @@ LL | pub struct A(pub H); help: consider importing this trait | LL + use A::Trait; -LL | pub struct A(pub H); | help: if you import `Trait`, refer to it directly | diff --git a/tests/ui/traits/issue-78372.stderr b/tests/ui/traits/issue-78372.stderr index f9c2c0d6dec7..ec692ff911df 100644 --- a/tests/ui/traits/issue-78372.stderr +++ b/tests/ui/traits/issue-78372.stderr @@ -7,7 +7,6 @@ LL | struct Smaht(PhantomData); help: consider importing this struct | LL + use std::marker::PhantomData; -LL | use std::ops::DispatchFromDyn; | error[E0412]: cannot find type `U` in this scope diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr index f505f36aaead..f53813189254 100644 --- a/tests/ui/traits/item-privacy.stderr +++ b/tests/ui/traits/item-privacy.stderr @@ -30,7 +30,6 @@ LL | S.b(); help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use method::B; -LL | struct S; | error[E0624]: method `a` is private @@ -71,7 +70,6 @@ LL | S::b(&S); help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use method::B; -LL | struct S; | error[E0624]: method `a` is private @@ -112,7 +110,6 @@ LL | S::B; help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use assoc_const::B; -LL | struct S; | error[E0624]: associated constant `A` is private diff --git a/tests/ui/traits/method-private.stderr b/tests/ui/traits/method-private.stderr index 2b047df75a00..e11799308c5c 100644 --- a/tests/ui/traits/method-private.stderr +++ b/tests/ui/traits/method-private.stderr @@ -11,7 +11,6 @@ LL | foo.method(); help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use inner::Bar; -LL | mod inner { | error: aborting due to previous error diff --git a/tests/ui/typeck/issue-43189.stderr b/tests/ui/typeck/issue-43189.stderr index fa8a61436229..c072e6a08ba0 100644 --- a/tests/ui/typeck/issue-43189.stderr +++ b/tests/ui/typeck/issue-43189.stderr @@ -13,7 +13,6 @@ LL | fn a(&self) {} help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use xcrate_issue_43189_b::xcrate_issue_43189_a::A; -LL | extern crate xcrate_issue_43189_b; | error: aborting due to previous error diff --git a/tests/ui/underscore-imports/shadow.stderr b/tests/ui/underscore-imports/shadow.stderr index b0ecf129ca3d..f2c19405bbb8 100644 --- a/tests/ui/underscore-imports/shadow.stderr +++ b/tests/ui/underscore-imports/shadow.stderr @@ -8,7 +8,6 @@ LL | x.deref(); help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL + use std::ops::Deref; -LL | use crate::b::Shadow as _; // Only imports the struct | error: aborting due to previous error diff --git a/tests/ui/unresolved/unresolved-candidates.stderr b/tests/ui/unresolved/unresolved-candidates.stderr index 53f63c1c840c..7ef2f6b1a292 100644 --- a/tests/ui/unresolved/unresolved-candidates.stderr +++ b/tests/ui/unresolved/unresolved-candidates.stderr @@ -18,7 +18,6 @@ LL | impl Trait for () {} help: consider importing this trait | LL + use a::Trait; -LL | impl Trait for () {} | error: aborting due to 2 previous errors From 2ac8dee44fe81c75d998597d236b23470f41142e Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Wed, 5 Apr 2023 18:42:36 -0700 Subject: [PATCH 238/272] Add inline assembly support for m68k --- compiler/rustc_codegen_gcc/src/asm.rs | 7 ++ compiler/rustc_codegen_llvm/src/asm.rs | 10 +++ compiler/rustc_span/src/symbol.rs | 2 + compiler/rustc_target/src/asm/m68k.rs | 81 ++++++++++++++++++ compiler/rustc_target/src/asm/mod.rs | 24 ++++++ .../asm-experimental-arch.md | 14 +++- tests/assembly/asm/m68k-types.rs | 83 +++++++++++++++++++ 7 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_target/src/asm/m68k.rs create mode 100644 tests/assembly/asm/m68k-types.rs diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 41e9d61a10e5..65de02b35671 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -593,6 +593,9 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r", InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w", InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a", + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d", InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "d", // more specific than "r" InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f", InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r", @@ -664,6 +667,9 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl InlineAsmRegClass::Avr(_) => unimplemented!(), InlineAsmRegClass::Bpf(_) => unimplemented!(), InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(), + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => cx.type_i32(), InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(), InlineAsmRegClass::Msp430(_) => unimplemented!(), @@ -849,6 +855,7 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option InlineAsmRegClass::Avr(_) => None, InlineAsmRegClass::S390x(_) => None, InlineAsmRegClass::Msp430(_) => None, + InlineAsmRegClass::M68k(_) => None, InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index e7668341eb6e..1a3865360a3c 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -244,6 +244,9 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { InlineAsmArch::Msp430 => { constraints.push("~{sr}".to_string()); } + InlineAsmArch::M68k => { + constraints.push("~{ccr}".to_string()); + } } } if !options.contains(InlineAsmOptions::NOMEM) { @@ -671,6 +674,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f", InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r", + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a", + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d", InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") } @@ -768,6 +774,7 @@ fn modifier_to_llvm( InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") } + InlineAsmRegClass::M68k(_) => None, InlineAsmRegClass::Err => unreachable!(), } } @@ -839,6 +846,9 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(), InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(), + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(), + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => cx.type_i32(), InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7affad9aa017..03b522bc63aa 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1173,7 +1173,9 @@ symbols! { reg32, reg64, reg_abcd, + reg_addr, reg_byte, + reg_data, reg_iw, reg_nonzero, reg_pair, diff --git a/compiler/rustc_target/src/asm/m68k.rs b/compiler/rustc_target/src/asm/m68k.rs new file mode 100644 index 000000000000..8c857550cf21 --- /dev/null +++ b/compiler/rustc_target/src/asm/m68k.rs @@ -0,0 +1,81 @@ +use super::{InlineAsmArch, InlineAsmType}; +use rustc_macros::HashStable_Generic; +use rustc_span::Symbol; +use std::fmt; + +def_reg_class! { + M68k M68kInlineAsmRegClass { + reg, + reg_addr, + reg_data, + } +} + +impl M68kInlineAsmRegClass { + pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] { + &[] + } + + pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option { + None + } + + pub fn suggest_modifier( + self, + _arch: InlineAsmArch, + _ty: InlineAsmType, + ) -> Option<(char, &'static str)> { + None + } + + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + None + } + + pub fn supported_types( + self, + _arch: InlineAsmArch, + ) -> &'static [(InlineAsmType, Option)] { + match self { + Self::reg => types! { _: I16, I32; }, + Self::reg_data => types! { _: I8, I16, I32; }, + Self::reg_addr => types! { _: I16, I32; }, + } + } +} + +def_regs! { + M68k M68kInlineAsmReg M68kInlineAsmRegClass { + d0: reg, reg_data = ["d0"], + d1: reg, reg_data = ["d1"], + d2: reg, reg_data = ["d2"], + d3: reg, reg_data = ["d3"], + d4: reg, reg_data = ["d4"], + d5: reg, reg_data = ["d5"], + d6: reg, reg_data = ["d6"], + d7: reg, reg_data = ["d7"], + a0: reg, reg_addr = ["a0"], + a1: reg, reg_addr = ["a1"], + a2: reg, reg_addr = ["a2"], + a3: reg, reg_addr = ["a3"], + #error = ["a4"] => + "a4 is used internally by LLVM and cannot be used as an operand for inline asm", + #error = ["a5", "bp"] => + "a5 is used internally by LLVM and cannot be used as an operand for inline asm", + #error = ["a6", "fp"] => + "a6 is used internally by LLVM and cannot be used as an operand for inline asm", + #error = ["a7", "sp", "usp", "ssp", "isp"] => + "the stack pointer cannot be used as an operand for inline asm", + } +} + +impl M68kInlineAsmReg { + pub fn emit( + self, + out: &mut dyn fmt::Write, + _arch: InlineAsmArch, + _modifier: Option, + ) -> fmt::Result { + out.write_str(self.name()) + } +} diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 0dbfd4267818..3f9c850b3524 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -168,6 +168,7 @@ mod arm; mod avr; mod bpf; mod hexagon; +mod m68k; mod mips; mod msp430; mod nvptx; @@ -183,6 +184,7 @@ pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass}; pub use avr::{AvrInlineAsmReg, AvrInlineAsmRegClass}; pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass}; pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass}; +pub use m68k::{M68kInlineAsmReg, M68kInlineAsmRegClass}; pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass}; pub use msp430::{Msp430InlineAsmReg, Msp430InlineAsmRegClass}; pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass}; @@ -214,6 +216,7 @@ pub enum InlineAsmArch { Bpf, Avr, Msp430, + M68k, } impl FromStr for InlineAsmArch { @@ -240,6 +243,7 @@ impl FromStr for InlineAsmArch { "bpf" => Ok(Self::Bpf), "avr" => Ok(Self::Avr), "msp430" => Ok(Self::Msp430), + "m68k" => Ok(Self::M68k), _ => Err(()), } } @@ -262,6 +266,7 @@ pub enum InlineAsmReg { Bpf(BpfInlineAsmReg), Avr(AvrInlineAsmReg), Msp430(Msp430InlineAsmReg), + M68k(M68kInlineAsmReg), // Placeholder for invalid register constraints for the current target Err, } @@ -280,6 +285,7 @@ impl InlineAsmReg { Self::Bpf(r) => r.name(), Self::Avr(r) => r.name(), Self::Msp430(r) => r.name(), + Self::M68k(r) => r.name(), Self::Err => "", } } @@ -297,6 +303,7 @@ impl InlineAsmReg { Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()), Self::Avr(r) => InlineAsmRegClass::Avr(r.reg_class()), Self::Msp430(r) => InlineAsmRegClass::Msp430(r.reg_class()), + Self::M68k(r) => InlineAsmRegClass::M68k(r.reg_class()), Self::Err => InlineAsmRegClass::Err, } } @@ -328,6 +335,7 @@ impl InlineAsmReg { InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmReg::parse(name)?), InlineAsmArch::Avr => Self::Avr(AvrInlineAsmReg::parse(name)?), InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmReg::parse(name)?), + InlineAsmArch::M68k => Self::M68k(M68kInlineAsmReg::parse(name)?), }) } @@ -351,6 +359,7 @@ impl InlineAsmReg { Self::Bpf(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), Self::Avr(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), Self::Msp430(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), + Self::M68k(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), Self::Err => unreachable!(), } } @@ -375,6 +384,7 @@ impl InlineAsmReg { Self::Bpf(r) => r.emit(out, arch, modifier), Self::Avr(r) => r.emit(out, arch, modifier), Self::Msp430(r) => r.emit(out, arch, modifier), + Self::M68k(r) => r.emit(out, arch, modifier), Self::Err => unreachable!("Use of InlineAsmReg::Err"), } } @@ -392,6 +402,7 @@ impl InlineAsmReg { Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))), Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))), Self::Msp430(_) => cb(self), + Self::M68k(_) => cb(self), Self::Err => unreachable!("Use of InlineAsmReg::Err"), } } @@ -414,6 +425,7 @@ pub enum InlineAsmRegClass { Bpf(BpfInlineAsmRegClass), Avr(AvrInlineAsmRegClass), Msp430(Msp430InlineAsmRegClass), + M68k(M68kInlineAsmRegClass), // Placeholder for invalid register constraints for the current target Err, } @@ -435,6 +447,7 @@ impl InlineAsmRegClass { Self::Bpf(r) => r.name(), Self::Avr(r) => r.name(), Self::Msp430(r) => r.name(), + Self::M68k(r) => r.name(), Self::Err => rustc_span::symbol::sym::reg, } } @@ -458,6 +471,7 @@ impl InlineAsmRegClass { Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf), Self::Avr(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Avr), Self::Msp430(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Msp430), + Self::M68k(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::M68k), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), } } @@ -488,6 +502,7 @@ impl InlineAsmRegClass { Self::Bpf(r) => r.suggest_modifier(arch, ty), Self::Avr(r) => r.suggest_modifier(arch, ty), Self::Msp430(r) => r.suggest_modifier(arch, ty), + Self::M68k(r) => r.suggest_modifier(arch, ty), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), } } @@ -514,6 +529,7 @@ impl InlineAsmRegClass { Self::Bpf(r) => r.default_modifier(arch), Self::Avr(r) => r.default_modifier(arch), Self::Msp430(r) => r.default_modifier(arch), + Self::M68k(r) => r.default_modifier(arch), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), } } @@ -539,6 +555,7 @@ impl InlineAsmRegClass { Self::Bpf(r) => r.supported_types(arch), Self::Avr(r) => r.supported_types(arch), Self::Msp430(r) => r.supported_types(arch), + Self::M68k(r) => r.supported_types(arch), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), } } @@ -569,6 +586,7 @@ impl InlineAsmRegClass { InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(name)?), InlineAsmArch::Avr => Self::Avr(AvrInlineAsmRegClass::parse(name)?), InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmRegClass::parse(name)?), + InlineAsmArch::M68k => Self::M68k(M68kInlineAsmRegClass::parse(name)?), }) } @@ -590,6 +608,7 @@ impl InlineAsmRegClass { Self::Bpf(r) => r.valid_modifiers(arch), Self::Avr(r) => r.valid_modifiers(arch), Self::Msp430(r) => r.valid_modifiers(arch), + Self::M68k(r) => r.valid_modifiers(arch), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), } } @@ -776,6 +795,11 @@ pub fn allocatable_registers( msp430::fill_reg_map(arch, reloc_model, target_features, target, &mut map); map } + InlineAsmArch::M68k => { + let mut map = m68k::regclass_map(); + m68k::fill_reg_map(arch, reloc_model, target_features, target, &mut map); + map + } } } diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index 0a48eb4f81a1..1f52ab75010e 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -16,6 +16,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect - SPIR-V - AVR - MSP430 +- M68k ## Register classes @@ -41,6 +42,9 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | AVR | `reg_iw` | `r25r24`, `X`, `Z` | `w` | | AVR | `reg_ptr` | `X`, `Z` | `e` | | MSP430 | `reg` | `r[0-15]` | `r` | +| M68k | `reg` | `d[0-7]`, `a[0-7]` | `r` | +| M68k | `reg_data` | `d[0-7]` | `d` | +| M68k | `reg_addr` | `a[0-3]` | `a` | > **Notes**: > - NVPTX doesn't have a fixed register set, so named registers are not supported. @@ -70,6 +74,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | AVR | `reg`, `reg_upper` | None | `i8` | | AVR | `reg_pair`, `reg_iw`, `reg_ptr` | None | `i16` | | MSP430 | `reg` | None | `i8`, `i16` | +| M68k | `reg`, `reg_addr` | None | `i16`, `i32` | +| M68k | `reg_data` | None | `i8`, `i16`, `i32` | ## Register aliases @@ -88,6 +94,9 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | MSP430 | `r2` | `sr` | | MSP430 | `r3` | `cg` | | MSP430 | `r4` | `fp` | +| M68k | `a5` | `bp` | +| M68k | `a6` | `fp` | +| M68k | `a7` | `sp`, `usp`, `ssp`, `isp` | > **Notes**: > - TI does not mandate a frame pointer for MSP430, but toolchains are allowed @@ -98,7 +107,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | Architecture | Unsupported register | Reason | | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430) | The frame pointer cannot be used as an input or output. | +| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k) | The frame pointer cannot be used as an input or output. | | All | `r19` (Hexagon) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. | | MIPS | `$1` or `$at` | Reserved for assembler. | @@ -108,6 +117,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | Hexagon | `lr` | This is the link register which cannot be used as an input or output. | | AVR | `r0`, `r1`, `r1r0` | Due to an issue in LLVM, the `r0` and `r1` registers cannot be used as inputs or outputs. If modified, they must be restored to their original values before the end of the block. | |MSP430 | `r0`, `r2`, `r3` | These are the program counter, status register, and constant generator respectively. Neither the status register nor constant generator can be written to. | +| M68k | `a4`, `a5` | Used internally by LLVM for the base pointer and global base pointer. | ## Template modifiers @@ -130,3 +140,5 @@ These flags registers must be restored upon exiting the asm block if the `preser - The status register `SREG`. - MSP430 - The status register `r2`. +- M68k + - The condition code register `ccr`. diff --git a/tests/assembly/asm/m68k-types.rs b/tests/assembly/asm/m68k-types.rs new file mode 100644 index 000000000000..0322e615a197 --- /dev/null +++ b/tests/assembly/asm/m68k-types.rs @@ -0,0 +1,83 @@ +// assembly-output: emit-asm +// compile-flags: --target m68k-unknown-linux-gnu +// needs-llvm-components: m68k + +#![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const u64; + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for i64 {} +impl Copy for ptr {} + +macro_rules! check { + ($func:ident $ty:ident $class:ident $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov, " {}, {};"), out($class) y, in($class) x); + y + } + }; +} + +// CHECK-LABEL: reg_data_i8: +// CHECK: ;APP +// CHECK: move.b %d{{[0-9]}}, %d{{[0-9]}} +// CHECK: ;NO_APP +check!(reg_data_i8 i8 reg_data "move.b"); + +// CHECK-LABEL: reg_data_i16: +// CHECK: ;APP +// CHECK: move.w %d{{[0-9]}}, %d{{[0-9]}} +// CHECK: ;NO_APP +check!(reg_data_i16 i16 reg_data "move.w"); + +// CHECK-LABEL: reg_data_i32: +// CHECK: ;APP +// CHECK: move.l %d{{[0-9]}}, %d{{[0-9]}} +// CHECK: ;NO_APP +check!(reg_data_i32 i32 reg_data "move.l"); + +// CHECK-LABEL: reg_addr_i16: +// CHECK: ;APP +// CHECK: move.w %a{{[0-9]}}, %a{{[0-9]}} +// CHECK: ;NO_APP +check!(reg_addr_i16 i16 reg_addr "move.w"); + +// CHECK-LABEL: reg_addr_i32: +// CHECK: ;APP +// CHECK: move.l %a{{[0-9]}}, %a{{[0-9]}} +// CHECK: ;NO_APP +check!(reg_addr_i32 i32 reg_addr "move.l"); + +// CHECK-LABEL: reg_i16: +// CHECK: ;APP +// CHECK: move.w %{{[da][0-9]}}, %{{[da][0-9]}} +// CHECK: ;NO_APP +check!(reg_i16 i16 reg "move.w"); + +// CHECK-LABEL: reg_i32: +// CHECK: ;APP +// CHECK: move.l %{{[da][0-9]}}, %{{[da][0-9]}} +// CHECK: ;NO_APP +check!(reg_i32 i32 reg "move.l"); From 9b0ceb4395fbc24bb5aff18b118487cb551167ba Mon Sep 17 00:00:00 2001 From: Justin Symonds Date: Wed, 12 Apr 2023 18:21:56 -0700 Subject: [PATCH 239/272] Update unwind_safe.rs Typo in the documentation. --- library/core/src/panic/unwind_safe.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs index 9a6153f1253c..7e7b6b4dbe9b 100644 --- a/library/core/src/panic/unwind_safe.rs +++ b/library/core/src/panic/unwind_safe.rs @@ -28,7 +28,7 @@ use crate::task::{Context, Poll}; /// 2. This broken invariant is then later observed. /// /// Typically in Rust, it is difficult to perform step (2) because catching a -/// panic involves either spawning a thread (which in turns makes it difficult +/// panic involves either spawning a thread (which in turn makes it difficult /// to later witness broken invariants) or using the `catch_unwind` function in this /// module. Additionally, even if an invariant is witnessed, it typically isn't a /// problem in Rust because there are no uninitialized values (like in C or C++). From c802694bdaded1ee655a08c3ecf03cf57bc4d60f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 12 Apr 2023 15:36:03 +1000 Subject: [PATCH 240/272] Make `Region::as_var` infallible. It's what all the call sites require. --- compiler/rustc_borrowck/src/lib.rs | 8 ++------ compiler/rustc_borrowck/src/type_check/relate_tys.rs | 11 ++--------- compiler/rustc_middle/src/ty/sty.rs | 6 +++--- 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 3d876155fc95..043ccaa02715 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -507,9 +507,7 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { F: Fn() -> RegionCtxt, { let next_region = self.infcx.next_region_var(origin); - let vid = next_region - .as_var() - .unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region)); + let vid = next_region.as_var(); if cfg!(debug_assertions) && !self.inside_canonicalization_ctxt() { debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin); @@ -531,9 +529,7 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { F: Fn() -> RegionCtxt, { let next_region = self.infcx.next_nll_region_var(origin.clone()); - let vid = next_region - .as_var() - .unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region)); + let vid = next_region.as_var(); if cfg!(debug_assertions) && !self.inside_canonicalization_ctxt() { debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin); diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 6b64e65518f5..7e6d17ec3437 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -131,13 +131,9 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(sym::env), }; - let reg_var = - reg.as_var().unwrap_or_else(|| bug!("expected region {:?} to be of kind ReVar", reg)); - if cfg!(debug_assertions) && !self.type_checker.infcx.inside_canonicalization_ctxt() { let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut(); - debug!(?reg_var); - var_to_origin.insert(reg_var, RegionCtxt::Placeholder(reg_info)); + var_to_origin.insert(reg.as_var(), RegionCtxt::Placeholder(reg_info)); } reg @@ -150,12 +146,9 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> universe, ); - let reg_var = - reg.as_var().unwrap_or_else(|| bug!("expected region {:?} to be of kind ReVar", reg)); - if cfg!(debug_assertions) && !self.type_checker.infcx.inside_canonicalization_ctxt() { let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut(); - var_to_origin.insert(reg_var, RegionCtxt::Existential(None)); + var_to_origin.insert(reg.as_var(), RegionCtxt::Existential(None)); } reg diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 086ceebd24d6..bbf6430a5ae7 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1772,10 +1772,10 @@ impl<'tcx> Region<'tcx> { matches!(self.kind(), ty::ReVar(_)) } - pub fn as_var(self) -> Option { + pub fn as_var(self) -> RegionVid { match self.kind() { - ty::ReVar(vid) => Some(vid), - _ => None, + ty::ReVar(vid) => vid, + _ => bug!("expected region {:?} to be of kind ReVar", self), } } } From 411422f2b9b0861f416d18f1ab9ca079ac01bb08 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 12 Apr 2023 15:26:05 +1000 Subject: [PATCH 241/272] Remove `impl ToRegionVid for RegionVid`. It's weird and unnecessary. --- compiler/rustc_borrowck/src/dataflow.rs | 6 ++---- compiler/rustc_borrowck/src/lib.rs | 2 +- compiler/rustc_borrowck/src/nll.rs | 6 ------ .../rustc_borrowck/src/region_infer/mod.rs | 21 ++++++++----------- 4 files changed, 12 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 2cbd2e3bc0d8..94939c7e4cd7 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -11,9 +11,7 @@ use rustc_mir_dataflow::{self, fmt::DebugWithContext, CallReturnPlaces, GenKill} use rustc_mir_dataflow::{Analysis, Direction, Results}; use std::fmt; -use crate::{ - places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid, -}; +use crate::{places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext}; /// A tuple with named fields that can hold either the results or the transient state of the /// dataflow analyses used by the borrow checker. @@ -242,7 +240,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { ) -> Self { let mut prec = OutOfScopePrecomputer::new(body, nonlexical_regioncx); for (borrow_index, borrow_data) in borrow_set.iter_enumerated() { - let borrow_region = borrow_data.region.to_region_vid(); + let borrow_region = borrow_data.region; let location = borrow_data.reserve_location; prec.precompute_borrows_out_of_scope(borrow_index, borrow_region, location); diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 043ccaa02715..a4b285a34fa4 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -94,7 +94,7 @@ pub mod consumers; use borrow_set::{BorrowData, BorrowSet}; use dataflow::{BorrowIndex, BorrowckFlowState as Flows, BorrowckResults, Borrows}; -use nll::{PoloniusOutput, ToRegionVid}; +use nll::PoloniusOutput; use place_ext::PlaceExt; use places_conflict::{places_conflict, PlaceConflictBias}; use region_infer::RegionInferenceContext; diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 06ecbdb1707c..8b5ff999e9b3 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -459,12 +459,6 @@ impl<'tcx> ToRegionVid for Region<'tcx> { } } -impl ToRegionVid for RegionVid { - fn to_region_vid(self) -> RegionVid { - self - } -} - pub(crate) trait ConstraintDescription { fn description(&self) -> &'static str; } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index f67af4584a4a..ce6f3690e190 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -27,7 +27,7 @@ use crate::{ }, diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo}, member_constraints::{MemberConstraintSet, NllMemberConstraintIndex}, - nll::{PoloniusOutput, ToRegionVid}, + nll::PoloniusOutput, region_infer::reverse_sccs::ReverseSccGraph, region_infer::values::{ LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues, @@ -593,14 +593,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Returns `true` if the region `r` contains the point `p`. /// /// Panics if called before `solve()` executes, - pub(crate) fn region_contains(&self, r: impl ToRegionVid, p: impl ToElementIndex) -> bool { - let scc = self.constraint_sccs.scc(r.to_region_vid()); + pub(crate) fn region_contains(&self, r: RegionVid, p: impl ToElementIndex) -> bool { + let scc = self.constraint_sccs.scc(r); self.scc_values.contains(scc, p) } /// Returns access to the value of `r` for debugging purposes. pub(crate) fn region_value_str(&self, r: RegionVid) -> String { - let scc = self.constraint_sccs.scc(r.to_region_vid()); + let scc = self.constraint_sccs.scc(r); self.scc_values.region_value_str(scc) } @@ -608,24 +608,21 @@ impl<'tcx> RegionInferenceContext<'tcx> { &'a self, r: RegionVid, ) -> impl Iterator + 'a { - let scc = self.constraint_sccs.scc(r.to_region_vid()); + let scc = self.constraint_sccs.scc(r); self.scc_values.placeholders_contained_in(scc) } /// Returns access to the value of `r` for debugging purposes. pub(crate) fn region_universe(&self, r: RegionVid) -> ty::UniverseIndex { - let scc = self.constraint_sccs.scc(r.to_region_vid()); + let scc = self.constraint_sccs.scc(r); self.scc_universes[scc] } /// Once region solving has completed, this function will return /// the member constraints that were applied to the value of a given /// region `r`. See `AppliedMemberConstraint`. - pub(crate) fn applied_member_constraints( - &self, - r: impl ToRegionVid, - ) -> &[AppliedMemberConstraint] { - let scc = self.constraint_sccs.scc(r.to_region_vid()); + pub(crate) fn applied_member_constraints(&self, r: RegionVid) -> &[AppliedMemberConstraint] { + let scc = self.constraint_sccs.scc(r); binary_search_util::binary_search_slice( &self.member_constraints_applied, |applied| applied.member_region_scc, @@ -2234,7 +2231,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { r: RegionVid, body: &Body<'_>, ) -> Option { - let scc = self.constraint_sccs.scc(r.to_region_vid()); + let scc = self.constraint_sccs.scc(r); let locations = self.scc_values.locations_outlived_by(scc); for location in locations { let bb = &body[location.block]; From bbc400993eadea8a927cc5f96a15cc7c493c7a88 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 12 Apr 2023 15:31:57 +1000 Subject: [PATCH 242/272] Remove `ToRegionVid`. It is only implemented for `Region`, where it is equivalent to the inherent `as_var` method. --- compiler/rustc_borrowck/src/borrow_set.rs | 5 ++-- .../src/constraint_generation.rs | 6 ++--- .../src/diagnostics/find_use.rs | 3 +-- .../src/diagnostics/region_name.rs | 10 ++++---- .../src/diagnostics/var_name.rs | 6 ++--- compiler/rustc_borrowck/src/nll.rs | 17 +------------- .../rustc_borrowck/src/region_infer/mod.rs | 2 +- .../src/type_check/constraint_conversion.rs | 3 +-- .../src/type_check/liveness/mod.rs | 5 +--- compiler/rustc_borrowck/src/type_check/mod.rs | 7 +++--- .../rustc_borrowck/src/universal_regions.rs | 23 +++++++++---------- 11 files changed, 32 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index fa0552e012de..4824f6346d4c 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -1,6 +1,5 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -use crate::nll::ToRegionVid; use crate::path_utils::allow_two_phase_borrow; use crate::place_ext::PlaceExt; use crate::BorrowIndex; @@ -204,7 +203,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> { return; } - let region = region.to_region_vid(); + let region = region.as_var(); let borrow = BorrowData { kind, @@ -279,7 +278,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> { let borrow_data = &self.location_map[&location]; assert_eq!(borrow_data.reserve_location, location); assert_eq!(borrow_data.kind, kind); - assert_eq!(borrow_data.region, region.to_region_vid()); + assert_eq!(borrow_data.region, region.as_var()); assert_eq!(borrow_data.borrowed_place, place); } diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs index 1427f5cb31d9..2aa09a3f26c1 100644 --- a/compiler/rustc_borrowck/src/constraint_generation.rs +++ b/compiler/rustc_borrowck/src/constraint_generation.rs @@ -12,8 +12,8 @@ use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt}; use crate::{ - borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, nll::ToRegionVid, - places_conflict, region_infer::values::LivenessValues, + borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, places_conflict, + region_infer::values::LivenessValues, }; pub(super) fn generate_constraints<'tcx>( @@ -170,7 +170,7 @@ impl<'cx, 'tcx> ConstraintGeneration<'cx, 'tcx> { debug!("add_regular_live_constraint(live_ty={:?}, location={:?})", live_ty, location); self.infcx.tcx.for_each_free_region(&live_ty, |live_region| { - let vid = live_region.to_region_vid(); + let vid = live_region.as_var(); self.liveness_constraints.add_element(vid, location); }); } diff --git a/compiler/rustc_borrowck/src/diagnostics/find_use.rs b/compiler/rustc_borrowck/src/diagnostics/find_use.rs index e2d04324f3b6..2495613fea1d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/find_use.rs +++ b/compiler/rustc_borrowck/src/diagnostics/find_use.rs @@ -6,7 +6,6 @@ use std::rc::Rc; use crate::{ def_use::{self, DefUse}, - nll::ToRegionVid, region_infer::{Cause, RegionInferenceContext}, }; use rustc_data_structures::fx::FxIndexSet; @@ -117,7 +116,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'tcx> { let mut found_it = false; self.tcx.for_each_free_region(&local_ty, |r| { - if r.to_region_vid() == self.region_vid { + if r.as_var() == self.region_vid { found_it = true; } }); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index cc5a1f5ab122..f69c4829ae29 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::{self, RegionVid, Ty}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; -use crate::{nll::ToRegionVid, universal_regions::DefiningTy, MirBorrowckCtxt}; +use crate::{universal_regions::DefiningTy, MirBorrowckCtxt}; /// A name for a particular region used in emitting diagnostics. This name could be a generated /// name like `'1`, a name used by the user like `'a`, or a name like `'static`. @@ -497,7 +497,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { // & // - let's call the lifetime of this reference `'1` (ty::Ref(region, referent_ty, _), hir::TyKind::Ref(_lifetime, referent_hir_ty)) => { - if region.to_region_vid() == needle_fr { + if region.as_var() == needle_fr { // Just grab the first character, the `&`. let source_map = self.infcx.tcx.sess.source_map(); let ampersand_span = source_map.start_point(hir_ty.span); @@ -598,7 +598,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { for (kind, hir_arg) in iter::zip(substs, args.args) { match (kind.unpack(), hir_arg) { (GenericArgKind::Lifetime(r), hir::GenericArg::Lifetime(lt)) => { - if r.to_region_vid() == needle_fr { + if r.as_var() == needle_fr { return Some(lt); } } @@ -666,7 +666,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let return_ty = self.regioncx.universal_regions().unnormalized_output_ty; debug!("give_name_if_anonymous_region_appears_in_output: return_ty = {:?}", return_ty); - if !tcx.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) { + if !tcx.any_free_region_meets(&return_ty, |r| r.as_var() == fr) { return None; } @@ -803,7 +803,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let tcx = self.infcx.tcx; - if !tcx.any_free_region_meets(&yield_ty, |r| r.to_region_vid() == fr) { + if !tcx.any_free_region_meets(&yield_ty, |r| r.as_var() == fr) { return None; } diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs index 80b2787ce0c4..376415e3d320 100644 --- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs @@ -1,8 +1,8 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +use crate::region_infer::RegionInferenceContext; use crate::Upvar; -use crate::{nll::ToRegionVid, region_infer::RegionInferenceContext}; use rustc_index::vec::{Idx, IndexSlice}; use rustc_middle::mir::{Body, Local}; use rustc_middle::ty::{RegionVid, TyCtxt}; @@ -46,7 +46,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.universal_regions().defining_ty.upvar_tys().position(|upvar_ty| { debug!("get_upvar_index_for_region: upvar_ty={upvar_ty:?}"); tcx.any_free_region_meets(&upvar_ty, |r| { - let r = r.to_region_vid(); + let r = r.as_var(); debug!("get_upvar_index_for_region: r={r:?} fr={fr:?}"); r == fr }) @@ -96,7 +96,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.universal_regions().unnormalized_input_tys.iter().skip(implicit_inputs).position( |arg_ty| { debug!("get_argument_index_for_region: arg_ty = {arg_ty:?}"); - tcx.any_free_region_meets(arg_ty, |r| r.to_region_vid() == fr) + tcx.any_free_region_meets(arg_ty, |r| r.as_var() == fr) }, )?; diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 8b5ff999e9b3..59a3ab3189d7 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -10,7 +10,7 @@ use rustc_middle::mir::{ BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, Promoted, }; -use rustc_middle::ty::{self, OpaqueHiddenType, Region, RegionVid, TyCtxt}; +use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt}; use rustc_span::symbol::sym; use std::env; use std::io; @@ -444,21 +444,6 @@ fn for_each_region_constraint<'tcx>( Ok(()) } -/// Right now, we piggy back on the `ReVar` to store our NLL inference -/// regions. These are indexed with `RegionVid`. This method will -/// assert that the region is a `ReVar` and extract its internal index. -/// This is reasonable because in our MIR we replace all universal regions -/// with inference variables. -pub trait ToRegionVid { - fn to_region_vid(self) -> RegionVid; -} - -impl<'tcx> ToRegionVid for Region<'tcx> { - fn to_region_vid(self) -> RegionVid { - if let ty::ReVar(vid) = *self { vid } else { bug!("region is not an ReVar: {:?}", self) } - } -} - pub(crate) trait ConstraintDescription { fn description(&self) -> &'static str; } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index ce6f3690e190..729f3dbff3b4 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1130,7 +1130,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let r_vid = self.to_region_vid(r); let r_scc = self.constraint_sccs.scc(r_vid); - // The challenge if this. We have some region variable `r` + // The challenge is this. We have some region variable `r` // whose value is a set of CFG points and universal // regions. We want to find if that set is *equivalent* to // any of the named regions found in the closure. diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index a93561350062..71eae7b27d1d 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -12,7 +12,6 @@ use rustc_span::{Span, DUMMY_SP}; use crate::{ constraints::OutlivesConstraint, - nll::ToRegionVid, region_infer::TypeTest, type_check::{Locations, MirTypeckRegionConstraints}, universal_regions::UniversalRegions, @@ -198,7 +197,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid { if let ty::RePlaceholder(placeholder) = *r { - self.constraints.placeholder_region(self.infcx, placeholder).to_region_vid() + self.constraints.placeholder_region(self.infcx, placeholder).as_var() } else { self.universal_regions.to_region_vid(r) } diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index a411aec518e9..f1ad0ca55ccf 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -11,7 +11,6 @@ use crate::{ constraints::OutlivesConstraintSet, facts::{AllFacts, AllFactsExt}, location::LocationTable, - nll::ToRegionVid, region_infer::values::RegionValueElements, universal_regions::UniversalRegions, }; @@ -80,9 +79,7 @@ fn compute_relevant_live_locals<'tcx>( ) -> (Vec, Vec) { let (boring_locals, relevant_live_locals): (Vec<_>, Vec<_>) = body.local_decls.iter_enumerated().partition_map(|(local, local_decl)| { - if tcx.all_free_regions_meet(&local_decl.ty, |r| { - free_regions.contains(&r.to_region_vid()) - }) { + if tcx.all_free_regions_meet(&local_decl.ty, |r| free_regions.contains(&r.as_var())) { Either::Left(local) } else { Either::Right(local) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 6d8305b7d471..375eca1b29d3 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -56,7 +56,6 @@ use crate::{ facts::AllFacts, location::LocationTable, member_constraints::MemberConstraintSet, - nll::ToRegionVid, path_utils, region_infer::values::{ LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements, @@ -2419,7 +2418,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Some(all_facts) = all_facts { let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation"); if let Some(borrow_index) = borrow_set.get_index_of(&location) { - let region_vid = borrow_region.to_region_vid(); + let region_vid = borrow_region.as_var(); all_facts.loan_issued_at.push(( region_vid, borrow_index, @@ -2465,8 +2464,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { match base_ty.kind() { ty::Ref(ref_region, _, mutbl) => { constraints.outlives_constraints.push(OutlivesConstraint { - sup: ref_region.to_region_vid(), - sub: borrow_region.to_region_vid(), + sup: ref_region.as_var(), + sub: borrow_region.as_var(), locations: location.to_locations(), span: location.to_locations().span(body), category, diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 35dfc1f7d129..70fddb1057c0 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -28,7 +28,6 @@ use rustc_span::symbol::{kw, sym}; use rustc_span::Symbol; use std::iter; -use crate::nll::ToRegionVid; use crate::renumber::{BoundRegionInfo, RegionCtxt}; use crate::BorrowckInferCtxt; @@ -406,7 +405,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // Create the "global" region that is always free in all contexts: 'static. let fr_static = - self.infcx.next_nll_region_var(FR, || RegionCtxt::Free(kw::Static)).to_region_vid(); + self.infcx.next_nll_region_var(FR, || RegionCtxt::Free(kw::Static)).as_var(); // We've now added all the global regions. The next ones we // add will be external. @@ -446,7 +445,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { }; debug!(?region_vid); - indices.insert_late_bound_region(r, region_vid.to_region_vid()); + indices.insert_late_bound_region(r, region_vid.as_var()); } }, ); @@ -480,7 +479,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { }; debug!(?region_vid); - indices.insert_late_bound_region(r, region_vid.to_region_vid()); + indices.insert_late_bound_region(r, region_vid.as_var()); } }); @@ -499,7 +498,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let reg_vid = self .infcx .next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("c-variadic"))) - .to_region_vid(); + .as_var(); let region = self.infcx.tcx.mk_re_var(reg_vid); let va_list_ty = @@ -514,7 +513,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let fr_fn_body = self .infcx .next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("fn_body"))) - .to_region_vid(); + .as_var(); let num_universals = self.infcx.num_region_vars(); @@ -635,7 +634,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static)); let subst_mapping = - iter::zip(identity_substs.regions(), fr_substs.regions().map(|r| r.to_region_vid())); + iter::zip(identity_substs.regions(), fr_substs.regions().map(|r| r.as_var())); UniversalRegionIndices { indices: global_mapping.chain(subst_mapping).collect(), fr_static } } @@ -789,7 +788,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { self.next_nll_region_var(origin, || RegionCtxt::Bound(BoundRegionInfo::Name(name))) }; - indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid()); + indices.insert_late_bound_region(liberated_region, region_vid.as_var()); debug!(?liberated_region, ?region_vid); region_vid }); @@ -822,7 +821,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { }; debug!(?region_vid); - indices.insert_late_bound_region(r, region_vid.to_region_vid()); + indices.insert_late_bound_region(r, region_vid.as_var()); } }); } @@ -843,7 +842,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { }) }; - indices.insert_late_bound_region(r, region_vid.to_region_vid()); + indices.insert_late_bound_region(r, region_vid.as_var()); } }); } @@ -861,7 +860,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> { } /// Converts `r` into a local inference variable: `r` can either - /// by a `ReVar` (i.e., already a reference to an inference + /// be a `ReVar` (i.e., already a reference to an inference /// variable) or it can be `'static` or some early-bound /// region. This is useful when taking the results from /// type-checking and trait-matching, which may sometimes @@ -870,7 +869,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> { /// fully initialized. pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { if let ty::ReVar(..) = *r { - r.to_region_vid() + r.as_var() } else if r.is_error() { // We use the `'static` `RegionVid` because `ReError` doesn't actually exist in the // `UniversalRegionIndices`. This is fine because 1) it is a fallback only used if From 72605cd267fa0a812e74ad8412738b4db37aca9d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 12 Apr 2023 16:49:13 +1000 Subject: [PATCH 243/272] Remove some unused type folders. I'm surprised the compiler doesn't warn about these. It appears having an `impl` on a struct is enough to avoid a warning about it never being constructed. --- .../rustc_hir_analysis/src/collect/type_of.rs | 27 +------ compiler/rustc_hir_typeck/src/op.rs | 22 +----- compiler/rustc_middle/src/ty/sty.rs | 79 +------------------ .../src/traits/auto_trait.rs | 21 ----- 4 files changed, 4 insertions(+), 145 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 225b15505807..c173bd913a84 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -8,10 +8,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::IntTypeExt; -use rustc_middle::ty::{ - self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, - TypeVisitableExt, -}; +use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::symbol::Ident; use rustc_span::{Span, DUMMY_SP}; @@ -874,28 +871,6 @@ fn infer_placeholder_type<'a>( item_ident: Ident, kind: &'static str, ) -> Ty<'a> { - // Attempts to make the type nameable by turning FnDefs into FnPtrs. - struct MakeNameable<'tcx> { - tcx: TyCtxt<'tcx>, - } - - impl<'tcx> TypeFolder> for MakeNameable<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - let ty = match *ty.kind() { - ty::FnDef(def_id, substs) => { - self.tcx.mk_fn_ptr(self.tcx.fn_sig(def_id).subst(self.tcx, substs)) - } - _ => ty, - }; - - ty.super_fold_with(self) - } - } - let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id); // If this came from a free `const` or `static mut?` item, diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 0ab6af127c09..a52c94cb00c5 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -12,9 +12,7 @@ use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, }; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{ - self, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitableExt, -}; +use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Ident}; @@ -965,21 +963,3 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool } } } - -struct TypeParamEraser<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, Span); - -impl<'tcx> TypeFolder> for TypeParamEraser<'_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { - self.0.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind() { - ty::Param(_) => self.0.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: self.1, - }), - _ => ty.super_fold_with(self), - } - } -} diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index bbf6430a5ae7..96c1577d52bc 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -7,8 +7,8 @@ use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; use crate::ty::visit::ValidateBoundVars; use crate::ty::InferTy::*; use crate::ty::{ - self, AdtDef, Discr, FallibleTypeFolder, Term, Ty, TyCtxt, TypeFlags, TypeFoldable, - TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, + self, AdtDef, Discr, Term, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, }; use crate::ty::{List, ParamEnv}; use hir::def::DefKind; @@ -1156,81 +1156,6 @@ where } } -struct SkipBindersAt<'tcx> { - tcx: TyCtxt<'tcx>, - index: ty::DebruijnIndex, -} - -impl<'tcx> FallibleTypeFolder> for SkipBindersAt<'tcx> { - type Error = (); - - fn interner(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn try_fold_binder(&mut self, t: Binder<'tcx, T>) -> Result, Self::Error> - where - T: ty::TypeFoldable>, - { - self.index.shift_in(1); - let value = t.try_map_bound(|t| t.try_fold_with(self)); - self.index.shift_out(1); - value - } - - fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result, Self::Error> { - if !ty.has_escaping_bound_vars() { - Ok(ty) - } else if let ty::Bound(index, bv) = *ty.kind() { - if index == self.index { - Err(()) - } else { - Ok(self.interner().mk_bound(index.shifted_out(1), bv)) - } - } else { - ty.try_super_fold_with(self) - } - } - - fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result, Self::Error> { - if !r.has_escaping_bound_vars() { - Ok(r) - } else if let ty::ReLateBound(index, bv) = r.kind() { - if index == self.index { - Err(()) - } else { - Ok(self.interner().mk_re_late_bound(index.shifted_out(1), bv)) - } - } else { - r.try_super_fold_with(self) - } - } - - fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result, Self::Error> { - if !ct.has_escaping_bound_vars() { - Ok(ct) - } else if let ty::ConstKind::Bound(index, bv) = ct.kind() { - if index == self.index { - Err(()) - } else { - Ok(self.interner().mk_const( - ty::ConstKind::Bound(index.shifted_out(1), bv), - ct.ty().try_fold_with(self)?, - )) - } - } else { - ct.try_super_fold_with(self) - } - } - - fn try_fold_predicate( - &mut self, - p: ty::Predicate<'tcx>, - ) -> Result, Self::Error> { - if !p.has_escaping_bound_vars() { Ok(p) } else { p.try_super_fold_with(self) } - } -} - /// Represents the projection of an associated type. /// /// For a projection, this would be `>::N`. diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index a53d414be9e7..686631e5369f 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -9,7 +9,6 @@ use crate::infer::InferCtxt; use crate::traits::project::ProjectAndUnifyResult; use rustc_infer::infer::DefineOpaqueTypes; use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{ImplPolarity, Region, RegionVid}; @@ -851,23 +850,3 @@ impl<'tcx> AutoTraitFinder<'tcx> { infcx.freshen(p) } } - -/// Replaces all ReVars in a type with ty::Region's, using the provided map -pub struct RegionReplacer<'a, 'tcx> { - vid_to_region: &'a FxHashMap>, - tcx: TyCtxt<'tcx>, -} - -impl<'a, 'tcx> TypeFolder> for RegionReplacer<'a, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - (match *r { - ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(), - _ => None, - }) - .unwrap_or_else(|| r.super_fold_with(self)) - } -} From 722e07854a8ea7b276c802400ac7224f41aa6910 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 13 Apr 2023 14:46:51 +1000 Subject: [PATCH 244/272] Remove useless match. --- compiler/rustc_hir_typeck/src/generator_interior/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 5faa6ab13dd7..6f0d078fb2ca 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -293,10 +293,7 @@ pub fn resolve_interior<'a, 'tcx>( type_causes, FnMutDelegate { regions: &mut |br| { - let kind = match br.kind { - ty::BrAnon(span) => ty::BrAnon(span), - _ => br.kind, - }; + let kind = br.kind; let var = ty::BoundVar::from_usize(bound_vars.len()); bound_vars.push(ty::BoundVariableKind::Region(kind)); counter += 1; From c18773a286094f1e7ddfb52208819841cbff8897 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 13 Apr 2023 12:08:45 +1000 Subject: [PATCH 245/272] Make `mk_bound_region` closure more generic. This is necessary for the subsequent commits. --- .../src/generator_interior/mod.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 6f0d078fb2ca..161db618b6fe 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -239,8 +239,7 @@ pub fn resolve_interior<'a, 'tcx>( // typeck had previously found constraints that would cause them to be related. let mut counter = 0; - let mut mk_bound_region = |span| { - let kind = ty::BrAnon(span); + let mut mk_bound_region = |kind| { let var = ty::BoundVar::from_u32(counter); counter += 1; ty::BoundRegion { var, kind } @@ -252,24 +251,24 @@ pub fn resolve_interior<'a, 'tcx>( let origin = fcx.region_var_origin(vid); match origin { RegionVariableOrigin::EarlyBoundRegion(span, _) => { - mk_bound_region(Some(span)) + mk_bound_region(ty::BrAnon(Some(span))) } - _ => mk_bound_region(None), + _ => mk_bound_region(ty::BrAnon(None)), } } // FIXME: these should use `BrNamed` ty::ReEarlyBound(region) => { - mk_bound_region(Some(fcx.tcx.def_span(region.def_id))) + mk_bound_region(ty::BrAnon(Some(fcx.tcx.def_span(region.def_id)))) } ty::ReLateBound(_, ty::BoundRegion { kind, .. }) | ty::ReFree(ty::FreeRegion { bound_region: kind, .. }) => match kind { - ty::BoundRegionKind::BrAnon(span) => mk_bound_region(span), + ty::BoundRegionKind::BrAnon(span) => mk_bound_region(ty::BrAnon(span)), ty::BoundRegionKind::BrNamed(def_id, _) => { - mk_bound_region(Some(fcx.tcx.def_span(def_id))) + mk_bound_region(ty::BrAnon(Some(fcx.tcx.def_span(def_id)))) } - ty::BoundRegionKind::BrEnv => mk_bound_region(None), + ty::BoundRegionKind::BrEnv => mk_bound_region(ty::BrAnon(None)), }, - _ => mk_bound_region(None), + _ => mk_bound_region(ty::BrAnon(None)), }; let r = fcx.tcx.mk_re_late_bound(current_depth, br); r From 1e2f0d2469c2038784e4394b80b7c18be843b3d3 Mon Sep 17 00:00:00 2001 From: Krishna Ramasimha Date: Thu, 13 Apr 2023 10:31:29 +0530 Subject: [PATCH 246/272] automatically update the LLVM submodule --- src/bootstrap/dist.rs | 2 ++ src/bootstrap/llvm.rs | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 8ce220c86478..94e71b89b5c8 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -895,6 +895,8 @@ impl Step for Src { /// Creates the `rust-src` installer component fn run(self, builder: &Builder<'_>) -> GeneratedTarball { + builder.update_submodule(&Path::new("src/llvm-project")); + let tarball = Tarball::new_targetless(builder, "rust-src"); // A lot of tools expect the rust-src component to be entirely in this directory, so if you diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index d123deec3545..a893c3a47c9f 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -1087,6 +1087,8 @@ impl Step for CrtBeginEnd { /// Build crtbegin.o/crtend.o for musl target. fn run(self, builder: &Builder<'_>) -> Self::Output { + builder.update_submodule(&Path::new("src/llvm-project")); + let out_dir = builder.native_dir(self.target).join("crt"); if builder.config.dry_run() { @@ -1153,6 +1155,8 @@ impl Step for Libunwind { /// Build linunwind.a fn run(self, builder: &Builder<'_>) -> Self::Output { + builder.update_submodule(&Path::new("src/llvm-project")); + if builder.config.dry_run() { return PathBuf::new(); } From 03cf0e949fc1537f4a626eb0a925f23cb9010cb3 Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Thu, 13 Apr 2023 08:48:50 +1200 Subject: [PATCH 247/272] refactor: emit "unused assoc fn" in lexical order with repect to other dead code lints --- compiler/rustc_passes/src/dead.rs | 11 +++-- tests/ui/lint/dead-code/issue-85255.stderr | 40 +++++++++---------- .../ui/lint/dead-code/lint-dead-code-3.stderr | 12 +++--- tests/ui/lint/dead-code/unused-assoc-fns.rs | 27 +++++++++++++ .../ui/lint/dead-code/unused-assoc-fns.stderr | 27 +++++++++++++ 5 files changed, 87 insertions(+), 30 deletions(-) create mode 100644 tests/ui/lint/dead-code/unused-assoc-fns.rs create mode 100644 tests/ui/lint/dead-code/unused-assoc-fns.stderr diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 91483fe3de77..d08dc4055ecb 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -836,6 +836,13 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) { let module_items = tcx.hir_module_items(module); for item in module_items.items() { + if let hir::ItemKind::Impl(impl_item) = tcx.hir().item(item).kind { + for item in impl_item.items { + visitor.check_definition(item.id.owner_id.def_id); + } + continue; + } + if !live_symbols.contains(&item.owner_id.def_id) { let parent = tcx.local_parent(item.owner_id.def_id); if parent != module && !live_symbols.contains(&parent) { @@ -900,10 +907,6 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) { } } - for impl_item in module_items.impl_items() { - visitor.check_definition(impl_item.owner_id.def_id); - } - for foreign_item in module_items.foreign_items() { visitor.check_definition(foreign_item.owner_id.def_id); } diff --git a/tests/ui/lint/dead-code/issue-85255.stderr b/tests/ui/lint/dead-code/issue-85255.stderr index 58a19cf3c99a..dec6f174628a 100644 --- a/tests/ui/lint/dead-code/issue-85255.stderr +++ b/tests/ui/lint/dead-code/issue-85255.stderr @@ -14,26 +14,6 @@ note: the lint level is defined here LL | #![warn(dead_code)] | ^^^^^^^^^ -warning: fields `a` and `b` are never read - --> $DIR/issue-85255.rs:19:5 - | -LL | pub(crate) struct Foo1 { - | ---- fields in this struct -LL | a: i32, - | ^ -LL | pub b: i32, - | ^ - -warning: fields `a` and `b` are never read - --> $DIR/issue-85255.rs:31:5 - | -LL | pub(crate) struct Foo2 { - | ---- fields in this struct -LL | a: i32, - | ^ -LL | pub b: i32, - | ^ - warning: method `a` is never used --> $DIR/issue-85255.rs:14:8 | @@ -46,6 +26,16 @@ warning: method `b` is never used LL | pub fn b(&self) -> i32 { 6 } | ^ +warning: fields `a` and `b` are never read + --> $DIR/issue-85255.rs:19:5 + | +LL | pub(crate) struct Foo1 { + | ---- fields in this struct +LL | a: i32, + | ^ +LL | pub b: i32, + | ^ + warning: method `a` is never used --> $DIR/issue-85255.rs:26:8 | @@ -58,6 +48,16 @@ warning: method `b` is never used LL | pub fn b(&self) -> i32 { 6 } | ^ +warning: fields `a` and `b` are never read + --> $DIR/issue-85255.rs:31:5 + | +LL | pub(crate) struct Foo2 { + | ---- fields in this struct +LL | a: i32, + | ^ +LL | pub b: i32, + | ^ + warning: method `a` is never used --> $DIR/issue-85255.rs:38:8 | diff --git a/tests/ui/lint/dead-code/lint-dead-code-3.stderr b/tests/ui/lint/dead-code/lint-dead-code-3.stderr index 797b7559c01b..9314f8be82a6 100644 --- a/tests/ui/lint/dead-code/lint-dead-code-3.stderr +++ b/tests/ui/lint/dead-code/lint-dead-code-3.stderr @@ -10,6 +10,12 @@ note: the lint level is defined here LL | #![deny(dead_code)] | ^^^^^^^^^ +error: method `foo` is never used + --> $DIR/lint-dead-code-3.rs:16:8 + | +LL | fn foo(&self) { + | ^^^ + error: function `bar` is never used --> $DIR/lint-dead-code-3.rs:21:4 | @@ -34,12 +40,6 @@ error: function `blah` is never used LL | fn blah() {} | ^^^^ -error: method `foo` is never used - --> $DIR/lint-dead-code-3.rs:16:8 - | -LL | fn foo(&self) { - | ^^^ - error: function `free` is never used --> $DIR/lint-dead-code-3.rs:62:8 | diff --git a/tests/ui/lint/dead-code/unused-assoc-fns.rs b/tests/ui/lint/dead-code/unused-assoc-fns.rs new file mode 100644 index 000000000000..11bdbca821b6 --- /dev/null +++ b/tests/ui/lint/dead-code/unused-assoc-fns.rs @@ -0,0 +1,27 @@ +#![deny(unused)] + +struct Foo; + +impl Foo { + fn one() {} + //~^ ERROR associated function `one` is never used [dead_code] + + fn two(&self) {} + //~^ ERROR method `two` is never used [dead_code] + + // seperation between functions + // ... + // ... + + fn used() {} + + fn three(&self) { + //~^ ERROR method `three` is never used [dead_code] + Foo::one(); + // ... + } +} + +fn main() { + Foo::used(); +} diff --git a/tests/ui/lint/dead-code/unused-assoc-fns.stderr b/tests/ui/lint/dead-code/unused-assoc-fns.stderr new file mode 100644 index 000000000000..2b8ea88c6092 --- /dev/null +++ b/tests/ui/lint/dead-code/unused-assoc-fns.stderr @@ -0,0 +1,27 @@ +error: associated function `one` is never used + --> $DIR/unused-assoc-fns.rs:6:8 + | +LL | fn one() {} + | ^^^ + | +note: the lint level is defined here + --> $DIR/unused-assoc-fns.rs:1:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(unused)]` + +error: method `two` is never used + --> $DIR/unused-assoc-fns.rs:9:8 + | +LL | fn two(&self) {} + | ^^^ + +error: method `three` is never used + --> $DIR/unused-assoc-fns.rs:18:8 + | +LL | fn three(&self) { + | ^^^^^ + +error: aborting due to 3 previous errors + From 731c6dcb60ffd4980b27338be652bb932790cc83 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 12 Apr 2023 14:55:35 +0100 Subject: [PATCH 248/272] Document catch_fn in r#try cannot unwind --- library/core/src/intrinsics.rs | 2 ++ library/std/src/panicking.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 10c5425b7cf0..a7c100e1b23e 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2276,6 +2276,8 @@ extern "rust-intrinsic" { /// takes the data pointer and a pointer to the target-specific exception /// object that was caught. For more information see the compiler's /// source as well as std's catch implementation. + /// + /// `catch_fn` must not unwind. #[rustc_nounwind] pub fn r#try(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32; diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index e505466e535a..a46a29cbad60 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -498,6 +498,7 @@ pub unsafe fn r#try R>(f: F) -> Result> // This function cannot be marked as `unsafe` because `intrinsics::r#try` // expects normal function pointers. #[inline] + #[rustc_nounwind] // `intrinsic::r#try` requires catch fn to be nounwind fn do_catch R, R>(data: *mut u8, payload: *mut u8) { // SAFETY: this is the responsibility of the caller, see above. // From c41dcac8e869160184fc2d80f643bc74601a45ef Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Thu, 13 Apr 2023 22:42:47 +1200 Subject: [PATCH 249/272] dead-code-lint: de-dup multiple unused assoc fns --- compiler/rustc_passes/src/dead.rs | 54 +++++++++++++------ tests/ui/lint/dead-code/issue-85255.rs | 12 ++--- tests/ui/lint/dead-code/issue-85255.stderr | 26 ++++----- .../ui/lint/dead-code/lint-dead-code-3.stderr | 2 + tests/ui/lint/dead-code/lint-dead-code-6.rs | 9 ++-- .../ui/lint/dead-code/lint-dead-code-6.stderr | 18 +++---- tests/ui/lint/dead-code/unused-assoc-fns.rs | 4 +- .../ui/lint/dead-code/unused-assoc-fns.stderr | 24 ++++----- 8 files changed, 77 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index d08dc4055ecb..fc7755d3df80 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -712,12 +712,12 @@ impl<'tcx> DeadVisitor<'tcx> { let parent_info = if let Some(parent_item) = parent_item { let parent_descr = tcx.def_descr(parent_item.to_def_id()); - Some(ParentInfo { - num, - descr, - parent_descr, - span: tcx.def_ident_span(parent_item).unwrap(), - }) + let span = if let DefKind::Impl { .. } = tcx.def_kind(parent_item) { + tcx.def_span(parent_item) + } else { + tcx.def_ident_span(parent_item).unwrap() + }; + Some(ParentInfo { num, descr, parent_descr, span }) } else { None }; @@ -800,16 +800,7 @@ impl<'tcx> DeadVisitor<'tcx> { } fn check_definition(&mut self, def_id: LocalDefId) { - if self.live_symbols.contains(&def_id) { - return; - } - if has_allow_dead_code_or_lang_attr(self.tcx, def_id) { - return; - } - let Some(name) = self.tcx.opt_item_name(def_id.to_def_id()) else { - return - }; - if name.as_str().starts_with('_') { + if self.is_live_code(def_id) { return; } match self.tcx.def_kind(def_id) { @@ -827,6 +818,18 @@ impl<'tcx> DeadVisitor<'tcx> { _ => {} } } + + fn is_live_code(&self, def_id: LocalDefId) -> bool { + // if we cannot get a name for the item, then we just assume that it is + // live. I mean, we can't really emit a lint. + let Some(name) = self.tcx.opt_item_name(def_id.to_def_id()) else { + return true; + }; + + self.live_symbols.contains(&def_id) + || has_allow_dead_code_or_lang_attr(self.tcx, def_id) + || name.as_str().starts_with('_') + } } fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) { @@ -837,9 +840,26 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) { for item in module_items.items() { if let hir::ItemKind::Impl(impl_item) = tcx.hir().item(item).kind { + let mut dead_items = Vec::new(); for item in impl_item.items { - visitor.check_definition(item.id.owner_id.def_id); + match item.kind { + hir::AssocItemKind::Const | hir::AssocItemKind::Type => { + visitor.check_definition(item.id.owner_id.def_id) + } + hir::AssocItemKind::Fn { .. } => { + let did = item.id.owner_id.def_id; + if !visitor.is_live_code(did) { + dead_items.push(did) + } + } + } } + visitor.warn_multiple_dead_codes( + &dead_items, + "used", + Some(item.owner_id.def_id), + false, + ); continue; } diff --git a/tests/ui/lint/dead-code/issue-85255.rs b/tests/ui/lint/dead-code/issue-85255.rs index 1978bd4e8247..d75a8e2dd41a 100644 --- a/tests/ui/lint/dead-code/issue-85255.rs +++ b/tests/ui/lint/dead-code/issue-85255.rs @@ -11,8 +11,8 @@ struct Foo { struct Bar; impl Bar { - fn a(&self) -> i32 { 5 } //~ WARNING: method `a` is never used - pub fn b(&self) -> i32 { 6 } //~ WARNING: method `b` is never used + fn a(&self) -> i32 { 5 } //~ WARNING: methods `a` and `b` are never used [dead_code] + pub fn b(&self) -> i32 { 6 } } pub(crate) struct Foo1 { @@ -23,8 +23,8 @@ pub(crate) struct Foo1 { pub(crate) struct Bar1; impl Bar1 { - fn a(&self) -> i32 { 5 } //~ WARNING: method `a` is never used - pub fn b(&self) -> i32 { 6 } //~ WARNING: method `b` is never used + fn a(&self) -> i32 { 5 } //~ WARNING: methods `a` and `b` are never used [dead_code] + pub fn b(&self) -> i32 { 6 } } pub(crate) struct Foo2 { @@ -35,8 +35,8 @@ pub(crate) struct Foo2 { pub(crate) struct Bar2; impl Bar2 { - fn a(&self) -> i32 { 5 } //~ WARNING: method `a` is never used - pub fn b(&self) -> i32 { 6 } //~ WARNING: method `b` is never used + fn a(&self) -> i32 { 5 } //~ WARNING: methods `a` and `b` are never used [dead_code] + pub fn b(&self) -> i32 { 6 } } diff --git a/tests/ui/lint/dead-code/issue-85255.stderr b/tests/ui/lint/dead-code/issue-85255.stderr index dec6f174628a..d981085a4fa5 100644 --- a/tests/ui/lint/dead-code/issue-85255.stderr +++ b/tests/ui/lint/dead-code/issue-85255.stderr @@ -14,15 +14,13 @@ note: the lint level is defined here LL | #![warn(dead_code)] | ^^^^^^^^^ -warning: method `a` is never used +warning: methods `a` and `b` are never used --> $DIR/issue-85255.rs:14:8 | +LL | impl Bar { + | -------- methods in this implementation LL | fn a(&self) -> i32 { 5 } | ^ - -warning: method `b` is never used - --> $DIR/issue-85255.rs:15:12 - | LL | pub fn b(&self) -> i32 { 6 } | ^ @@ -36,15 +34,13 @@ LL | a: i32, LL | pub b: i32, | ^ -warning: method `a` is never used +warning: methods `a` and `b` are never used --> $DIR/issue-85255.rs:26:8 | +LL | impl Bar1 { + | --------- methods in this implementation LL | fn a(&self) -> i32 { 5 } | ^ - -warning: method `b` is never used - --> $DIR/issue-85255.rs:27:12 - | LL | pub fn b(&self) -> i32 { 6 } | ^ @@ -58,17 +54,15 @@ LL | a: i32, LL | pub b: i32, | ^ -warning: method `a` is never used +warning: methods `a` and `b` are never used --> $DIR/issue-85255.rs:38:8 | +LL | impl Bar2 { + | --------- methods in this implementation LL | fn a(&self) -> i32 { 5 } | ^ - -warning: method `b` is never used - --> $DIR/issue-85255.rs:39:12 - | LL | pub fn b(&self) -> i32 { 6 } | ^ -warning: 9 warnings emitted +warning: 6 warnings emitted diff --git a/tests/ui/lint/dead-code/lint-dead-code-3.stderr b/tests/ui/lint/dead-code/lint-dead-code-3.stderr index 9314f8be82a6..5c68cf0e18b6 100644 --- a/tests/ui/lint/dead-code/lint-dead-code-3.stderr +++ b/tests/ui/lint/dead-code/lint-dead-code-3.stderr @@ -13,6 +13,8 @@ LL | #![deny(dead_code)] error: method `foo` is never used --> $DIR/lint-dead-code-3.rs:16:8 | +LL | impl Foo { + | -------- method in this implementation LL | fn foo(&self) { | ^^^ diff --git a/tests/ui/lint/dead-code/lint-dead-code-6.rs b/tests/ui/lint/dead-code/lint-dead-code-6.rs index e3074acf129f..5b2b76b76ecd 100644 --- a/tests/ui/lint/dead-code/lint-dead-code-6.rs +++ b/tests/ui/lint/dead-code/lint-dead-code-6.rs @@ -2,17 +2,16 @@ struct UnusedStruct; //~ ERROR struct `UnusedStruct` is never constructed impl UnusedStruct { - fn unused_impl_fn_1() { //~ ERROR associated function `unused_impl_fn_1` is never used + fn unused_impl_fn_1() { + //~^ ERROR associated functions `unused_impl_fn_1`, `unused_impl_fn_2`, and `unused_impl_fn_3` are never used [dead_code] println!("blah"); } - fn unused_impl_fn_2(var: i32) { //~ ERROR associated function `unused_impl_fn_2` is never used + fn unused_impl_fn_2(var: i32) { println!("foo {}", var); } - fn unused_impl_fn_3( //~ ERROR associated function `unused_impl_fn_3` is never used - var: i32, - ) { + fn unused_impl_fn_3(var: i32) { println!("bar {}", var); } } diff --git a/tests/ui/lint/dead-code/lint-dead-code-6.stderr b/tests/ui/lint/dead-code/lint-dead-code-6.stderr index f9d83308a3de..ce41100866ad 100644 --- a/tests/ui/lint/dead-code/lint-dead-code-6.stderr +++ b/tests/ui/lint/dead-code/lint-dead-code-6.stderr @@ -10,23 +10,19 @@ note: the lint level is defined here LL | #![deny(dead_code)] | ^^^^^^^^^ -error: associated function `unused_impl_fn_1` is never used +error: associated functions `unused_impl_fn_1`, `unused_impl_fn_2`, and `unused_impl_fn_3` are never used --> $DIR/lint-dead-code-6.rs:5:8 | +LL | impl UnusedStruct { + | ----------------- associated functions in this implementation LL | fn unused_impl_fn_1() { | ^^^^^^^^^^^^^^^^ - -error: associated function `unused_impl_fn_2` is never used - --> $DIR/lint-dead-code-6.rs:9:8 - | +... LL | fn unused_impl_fn_2(var: i32) { | ^^^^^^^^^^^^^^^^ - -error: associated function `unused_impl_fn_3` is never used - --> $DIR/lint-dead-code-6.rs:13:8 - | -LL | fn unused_impl_fn_3( +... +LL | fn unused_impl_fn_3(var: i32) { | ^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/lint/dead-code/unused-assoc-fns.rs b/tests/ui/lint/dead-code/unused-assoc-fns.rs index 11bdbca821b6..9e3ad85390a8 100644 --- a/tests/ui/lint/dead-code/unused-assoc-fns.rs +++ b/tests/ui/lint/dead-code/unused-assoc-fns.rs @@ -4,10 +4,9 @@ struct Foo; impl Foo { fn one() {} - //~^ ERROR associated function `one` is never used [dead_code] + //~^ ERROR associated functions `one`, `two`, and `three` are never used [dead_code] fn two(&self) {} - //~^ ERROR method `two` is never used [dead_code] // seperation between functions // ... @@ -16,7 +15,6 @@ impl Foo { fn used() {} fn three(&self) { - //~^ ERROR method `three` is never used [dead_code] Foo::one(); // ... } diff --git a/tests/ui/lint/dead-code/unused-assoc-fns.stderr b/tests/ui/lint/dead-code/unused-assoc-fns.stderr index 2b8ea88c6092..71174a1c3ded 100644 --- a/tests/ui/lint/dead-code/unused-assoc-fns.stderr +++ b/tests/ui/lint/dead-code/unused-assoc-fns.stderr @@ -1,8 +1,16 @@ -error: associated function `one` is never used +error: associated functions `one`, `two`, and `three` are never used --> $DIR/unused-assoc-fns.rs:6:8 | +LL | impl Foo { + | -------- associated functions in this implementation LL | fn one() {} | ^^^ +... +LL | fn two(&self) {} + | ^^^ +... +LL | fn three(&self) { + | ^^^^^ | note: the lint level is defined here --> $DIR/unused-assoc-fns.rs:1:9 @@ -11,17 +19,5 @@ LL | #![deny(unused)] | ^^^^^^ = note: `#[deny(dead_code)]` implied by `#[deny(unused)]` -error: method `two` is never used - --> $DIR/unused-assoc-fns.rs:9:8 - | -LL | fn two(&self) {} - | ^^^ - -error: method `three` is never used - --> $DIR/unused-assoc-fns.rs:18:8 - | -LL | fn three(&self) { - | ^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to previous error From 5e51b2d9688ccdfb082a1b855c9aa8398b86b870 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 13 Apr 2023 11:33:44 +0200 Subject: [PATCH 250/272] Correctly handle built-in compiler proc-macros as proc-macro and not macro --- src/librustdoc/clean/inline.rs | 26 ++++++++----- src/librustdoc/clean/mod.rs | 69 +++++++++++++++++++--------------- 2 files changed, 55 insertions(+), 40 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 9270d1c02e21..8a089b250769 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -111,7 +111,7 @@ pub(crate) fn try_inline( clean::ConstantItem(build_const(cx, did)) } Res::Def(DefKind::Macro(kind), did) => { - let mac = build_macro(cx, did, name, import_def_id); + let mac = build_macro(cx, did, name, import_def_id, kind); let type_kind = match kind { MacroKind::Bang => ItemType::Macro, @@ -651,18 +651,24 @@ fn build_macro( def_id: DefId, name: Symbol, import_def_id: Option, + macro_kind: MacroKind, ) -> clean::ItemKind { match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.sess()) { - LoadedMacro::MacroDef(item_def, _) => { - if let ast::ItemKind::MacroDef(ref def) = item_def.kind { - let vis = cx.tcx.visibility(import_def_id.unwrap_or(def_id)); - clean::MacroItem(clean::Macro { - source: utils::display_macro_source(cx, name, def, def_id, vis), - }) - } else { - unreachable!() + LoadedMacro::MacroDef(item_def, _) => match macro_kind { + MacroKind::Bang => { + if let ast::ItemKind::MacroDef(ref def) = item_def.kind { + let vis = cx.tcx.visibility(import_def_id.unwrap_or(def_id)); + clean::MacroItem(clean::Macro { + source: utils::display_macro_source(cx, name, def, def_id, vis), + }) + } else { + unreachable!() + } } - } + MacroKind::Derive | MacroKind::Attr => { + clean::ProcMacroItem(clean::ProcMacro { kind: macro_kind, helpers: Vec::new() }) + } + }, LoadedMacro::ProcMacro(ext) => clean::ProcMacroItem(clean::ProcMacro { kind: ext.macro_kind(), helpers: ext.helper_attrs, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b3df12a9df13..f8dd8a234df9 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -909,6 +909,38 @@ fn clean_ty_generics<'tcx>( } } +fn clean_proc_macro<'tcx>( + item: &hir::Item<'tcx>, + name: &mut Symbol, + kind: MacroKind, + cx: &mut DocContext<'tcx>, +) -> ItemKind { + let attrs = cx.tcx.hir().attrs(item.hir_id()); + if kind == MacroKind::Derive && + let Some(derive_name) = attrs + .lists(sym::proc_macro_derive) + .find_map(|mi| mi.ident()) + { + *name = derive_name.name; + } + + let mut helpers = Vec::new(); + for mi in attrs.lists(sym::proc_macro_derive) { + if !mi.has_name(sym::attributes) { + continue; + } + + if let Some(list) = mi.meta_item_list() { + for inner_mi in list { + if let Some(ident) = inner_mi.ident() { + helpers.push(ident.name); + } + } + } + } + ProcMacroItem(ProcMacro { kind, helpers }) +} + fn clean_fn_or_proc_macro<'tcx>( item: &hir::Item<'tcx>, sig: &hir::FnSig<'tcx>, @@ -930,31 +962,7 @@ fn clean_fn_or_proc_macro<'tcx>( } }); match macro_kind { - Some(kind) => { - if kind == MacroKind::Derive { - *name = attrs - .lists(sym::proc_macro_derive) - .find_map(|mi| mi.ident()) - .expect("proc-macro derives require a name") - .name; - } - - let mut helpers = Vec::new(); - for mi in attrs.lists(sym::proc_macro_derive) { - if !mi.has_name(sym::attributes) { - continue; - } - - if let Some(list) = mi.meta_item_list() { - for inner_mi in list { - if let Some(ident) = inner_mi.ident() { - helpers.push(ident.name); - } - } - } - } - ProcMacroItem(ProcMacro { kind, helpers }) - } + Some(kind) => clean_proc_macro(item, name, kind, cx), None => { let mut func = clean_function(cx, sig, generics, FunctionArgs::Body(body_id)); clean_fn_decl_legacy_const_generics(&mut func, attrs); @@ -2247,16 +2255,17 @@ fn clean_maybe_renamed_item<'tcx>( fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(), }), ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx), - // proc macros can have a name set by attributes - ItemKind::Fn(ref sig, generics, body_id) => { - clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) - } - ItemKind::Macro(ref macro_def, _) => { + ItemKind::Macro(ref macro_def, MacroKind::Bang) => { let ty_vis = cx.tcx.visibility(def_id); MacroItem(Macro { source: display_macro_source(cx, name, macro_def, def_id, ty_vis), }) } + ItemKind::Macro(_, macro_kind) => clean_proc_macro(item, &mut name, macro_kind, cx), + // proc macros can have a name set by attributes + ItemKind::Fn(ref sig, generics, body_id) => { + clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) + } ItemKind::Trait(_, _, generics, bounds, item_ids) => { let items = item_ids .iter() From b07a470d1ae47bbae86df0b9dc6de624bcdf0357 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 12 Apr 2023 14:04:41 +0100 Subject: [PATCH 251/272] Add regression test --- ...rinsics.main.AbortUnwindingCalls.after.mir | 25 +++++++++++++++++++ .../issue_104451_unwindable_intrinsics.rs | 14 +++++++++++ 2 files changed, 39 insertions(+) create mode 100644 tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.mir create mode 100644 tests/mir-opt/issue_104451_unwindable_intrinsics.rs diff --git a/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.mir b/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.mir new file mode 100644 index 000000000000..f50c0eb47889 --- /dev/null +++ b/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.mir @@ -0,0 +1,25 @@ +// MIR for `main` after AbortUnwindingCalls + +fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/issue_104451_unwindable_intrinsics.rs:+0:11: +0:11 + let mut _1: !; // in scope 0 at $DIR/issue_104451_unwindable_intrinsics.rs:+2:9: +2:62 + let mut _2: (); // in scope 0 at $DIR/issue_104451_unwindable_intrinsics.rs:+2:45: +2:47 + scope 1 { + } + + bb0: { + StorageLive(_1); // scope 1 at $DIR/issue_104451_unwindable_intrinsics.rs:+2:9: +2:62 + StorageLive(_2); // scope 1 at $DIR/issue_104451_unwindable_intrinsics.rs:+2:45: +2:47 + _2 = (); // scope 1 at $DIR/issue_104451_unwindable_intrinsics.rs:+2:45: +2:47 + _1 = const_eval_select::<(), fn() -> ! {ow_ct}, fn() -> ! {ow_ct}, !>(move _2, ow_ct, ow_ct); // scope 1 at $DIR/issue_104451_unwindable_intrinsics.rs:+2:9: +2:62 + // mir::Constant + // + span: $DIR/issue_104451_unwindable_intrinsics.rs:8:9: 8:44 + // + literal: Const { ty: unsafe extern "rust-intrinsic" fn((), fn() -> ! {ow_ct}, fn() -> ! {ow_ct}) -> ! {const_eval_select::<(), fn() -> ! {ow_ct}, fn() -> ! {ow_ct}, !>}, val: Value() } + // mir::Constant + // + span: $DIR/issue_104451_unwindable_intrinsics.rs:8:49: 8:54 + // + literal: Const { ty: fn() -> ! {ow_ct}, val: Value() } + // mir::Constant + // + span: $DIR/issue_104451_unwindable_intrinsics.rs:8:56: 8:61 + // + literal: Const { ty: fn() -> ! {ow_ct}, val: Value() } + } +} diff --git a/tests/mir-opt/issue_104451_unwindable_intrinsics.rs b/tests/mir-opt/issue_104451_unwindable_intrinsics.rs new file mode 100644 index 000000000000..9babd4aaed51 --- /dev/null +++ b/tests/mir-opt/issue_104451_unwindable_intrinsics.rs @@ -0,0 +1,14 @@ +// Check that `UnwindAction::Unreachable` is not generated for unwindable intrinsics. +// ignore-wasm32 compiled with panic=abort by default +#![feature(core_intrinsics)] + +// EMIT_MIR issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.mir +fn main() { + unsafe { + core::intrinsics::const_eval_select((), ow_ct, ow_ct) + } +} + +const fn ow_ct() -> ! { + panic!(); +} From 39e23ef532fa894f33ffcd105e630955bf315411 Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Thu, 13 Apr 2023 23:38:52 +1200 Subject: [PATCH 252/272] impl reviewer feedback - remove unused (pun intentional) `continue` - improve wording with assoc items in general --- compiler/rustc_passes/src/dead.rs | 21 +++++++++---------- tests/ui/lint/dead-code/unused-assoc-fns.rs | 14 +++++++++++-- .../ui/lint/dead-code/unused-assoc-fns.stderr | 14 +++++++++---- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index fc7755d3df80..5cfe691df17a 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -700,6 +700,13 @@ impl<'tcx> DeadVisitor<'tcx> { .collect(); let descr = tcx.def_descr(first_id.to_def_id()); + // `impl` blocks are "batched" and (unlike other batching) might + // contain different kinds of associated items. + let descr = if dead_codes.iter().any(|did| tcx.def_descr(did.to_def_id()) != descr) { + "associated item" + } else { + descr + }; let num = dead_codes.len(); let multiple = num > 6; let name_list = names.into(); @@ -842,16 +849,9 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) { if let hir::ItemKind::Impl(impl_item) = tcx.hir().item(item).kind { let mut dead_items = Vec::new(); for item in impl_item.items { - match item.kind { - hir::AssocItemKind::Const | hir::AssocItemKind::Type => { - visitor.check_definition(item.id.owner_id.def_id) - } - hir::AssocItemKind::Fn { .. } => { - let did = item.id.owner_id.def_id; - if !visitor.is_live_code(did) { - dead_items.push(did) - } - } + let did = item.id.owner_id.def_id; + if !visitor.is_live_code(did) { + dead_items.push(did) } } visitor.warn_multiple_dead_codes( @@ -860,7 +860,6 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) { Some(item.owner_id.def_id), false, ); - continue; } if !live_symbols.contains(&item.owner_id.def_id) { diff --git a/tests/ui/lint/dead-code/unused-assoc-fns.rs b/tests/ui/lint/dead-code/unused-assoc-fns.rs index 9e3ad85390a8..b111f4b9463c 100644 --- a/tests/ui/lint/dead-code/unused-assoc-fns.rs +++ b/tests/ui/lint/dead-code/unused-assoc-fns.rs @@ -1,19 +1,29 @@ +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] #![deny(unused)] struct Foo; impl Foo { fn one() {} - //~^ ERROR associated functions `one`, `two`, and `three` are never used [dead_code] + //~^ ERROR associated items `one`, `two`, `CONSTANT`, `Type`, and `three` are never used [dead_code] fn two(&self) {} - // seperation between functions + // seperation between items // ... // ... fn used() {} + const CONSTANT: usize = 5; + + // more seperation + // ... + // ... + + type Type = usize; + fn three(&self) { Foo::one(); // ... diff --git a/tests/ui/lint/dead-code/unused-assoc-fns.stderr b/tests/ui/lint/dead-code/unused-assoc-fns.stderr index 71174a1c3ded..6344a70ea3ae 100644 --- a/tests/ui/lint/dead-code/unused-assoc-fns.stderr +++ b/tests/ui/lint/dead-code/unused-assoc-fns.stderr @@ -1,19 +1,25 @@ -error: associated functions `one`, `two`, and `three` are never used - --> $DIR/unused-assoc-fns.rs:6:8 +error: associated items `one`, `two`, `CONSTANT`, `Type`, and `three` are never used + --> $DIR/unused-assoc-fns.rs:8:8 | LL | impl Foo { - | -------- associated functions in this implementation + | -------- associated items in this implementation LL | fn one() {} | ^^^ ... LL | fn two(&self) {} | ^^^ ... +LL | const CONSTANT: usize = 5; + | ^^^^^^^^ +... +LL | type Type = usize; + | ^^^^ +LL | LL | fn three(&self) { | ^^^^^ | note: the lint level is defined here - --> $DIR/unused-assoc-fns.rs:1:9 + --> $DIR/unused-assoc-fns.rs:3:9 | LL | #![deny(unused)] | ^^^^^^ From 2bafc0fcee7c2ef0ea8c8a8af112e07a83304f79 Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Fri, 14 Apr 2023 00:06:21 +1200 Subject: [PATCH 253/272] bless the single test --- tests/ui/associated-consts/associated-const-dead-code.stderr | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/ui/associated-consts/associated-const-dead-code.stderr b/tests/ui/associated-consts/associated-const-dead-code.stderr index cc701cc4b942..7e485a314c54 100644 --- a/tests/ui/associated-consts/associated-const-dead-code.stderr +++ b/tests/ui/associated-consts/associated-const-dead-code.stderr @@ -1,6 +1,8 @@ error: associated constant `BAR` is never used --> $DIR/associated-const-dead-code.rs:6:11 | +LL | impl MyFoo { + | ---------- associated constant in this implementation LL | const BAR: u32 = 1; | ^^^ | From 4061eb589797ab4498f00ba0be337e4a1355cb49 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Thu, 13 Apr 2023 09:20:36 -0400 Subject: [PATCH 254/272] Only emit alignment checks if we have a panic_impl --- .../rustc_mir_transform/src/check_alignment.rs | 7 +++++++ tests/ui/mir/checks_without_panic_impl.rs | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 tests/ui/mir/checks_without_panic_impl.rs diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index 8086a4557b70..c76dc56065c3 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -1,5 +1,6 @@ use crate::MirPass; use rustc_hir::def_id::DefId; +use rustc_hir::lang_items::LangItem; use rustc_index::vec::IndexVec; use rustc_middle::mir::*; use rustc_middle::mir::{ @@ -17,6 +18,12 @@ impl<'tcx> MirPass<'tcx> for CheckAlignment { } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + // This pass emits new panics. If for whatever reason we do not have a panic + // implementation, running this pass may cause otherwise-valid code to not compile. + if tcx.lang_items().get(LangItem::PanicImpl).is_none() { + return; + } + let basic_blocks = body.basic_blocks.as_mut(); let local_decls = &mut body.local_decls; diff --git a/tests/ui/mir/checks_without_panic_impl.rs b/tests/ui/mir/checks_without_panic_impl.rs new file mode 100644 index 000000000000..04f410b77a3b --- /dev/null +++ b/tests/ui/mir/checks_without_panic_impl.rs @@ -0,0 +1,17 @@ +// Ensures that the alignment check we insert for raw pointer dereferences +// does not prevent crates without a panic_impl from compiling. +// See rust-lang/rust#109996 + +// build-pass +// compile-flags: -Cdebug-assertions=yes + +#![crate_type = "lib"] + +#![feature(lang_items)] +#![feature(no_core)] +#![no_core] + +#[lang = "sized"] +trait Foo {} + +pub unsafe fn foo(x: *const i32) -> &'static i32 { unsafe { &*x } } From 09a8791d42152bb08ecb99d029ef6ce51ef48aea Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 13 Apr 2023 18:04:30 +0000 Subject: [PATCH 255/272] Implement `Copy` for `LocationDetail` --- .../src/interpret/intrinsics/caller_location.rs | 2 +- compiler/rustc_session/src/config.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs index 76c8d0a975ac..3701eb93ec83 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs @@ -77,7 +77,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { line: u32, col: u32, ) -> MPlaceTy<'tcx, M::Provenance> { - let loc_details = &self.tcx.sess.opts.unstable_opts.location_detail; + let loc_details = self.tcx.sess.opts.unstable_opts.location_detail; // This can fail if rustc runs out of memory right here. Trying to emit an error would be // pointless, since that would require allocating more memory than these short strings. let file = if loc_details.file { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index acfb36c97d0c..79eb31bb1050 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -222,7 +222,7 @@ impl LinkerPluginLto { } /// The different settings that can be enabled via the `-Z location-detail` flag. -#[derive(Clone, PartialEq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Hash, Debug)] pub struct LocationDetail { pub file: bool, pub line: bool, From 80c43232177c1a04ef11bd8103b56b67f69b669c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 13 Apr 2023 13:19:00 +0200 Subject: [PATCH 256/272] Add test to ensure that compiler built-in proc-macro are considered as such --- tests/rustdoc/compiler-derive-proc-macro.rs | 15 +++++++++++++++ tests/rustdoc/macro_pub_in_module.rs | 12 ++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 tests/rustdoc/compiler-derive-proc-macro.rs diff --git a/tests/rustdoc/compiler-derive-proc-macro.rs b/tests/rustdoc/compiler-derive-proc-macro.rs new file mode 100644 index 000000000000..489ec924c1fc --- /dev/null +++ b/tests/rustdoc/compiler-derive-proc-macro.rs @@ -0,0 +1,15 @@ +// This test ensures that compiler builtin proc-macros are considered as such. + +#![crate_name = "foo"] + +// @has 'foo/index.html' +// Each compiler builtin proc-macro has a trait equivalent so we should have +// a trait section as well. +// @count - '//*[@id="main-content"]//*[@class="small-section-header"]' 2 +// @has - '//*[@id="main-content"]//*[@class="small-section-header"]' 'Traits' +// @has - '//*[@id="main-content"]//*[@class="small-section-header"]' 'Derive Macros' + +// Now checking the correct file is generated as well. +// @has 'foo/derive.Clone.html' +// @!has 'foo/macro.Clone.html' +pub use std::clone::Clone; diff --git a/tests/rustdoc/macro_pub_in_module.rs b/tests/rustdoc/macro_pub_in_module.rs index 4fd85d689940..42f760cff6a7 100644 --- a/tests/rustdoc/macro_pub_in_module.rs +++ b/tests/rustdoc/macro_pub_in_module.rs @@ -7,8 +7,8 @@ #![crate_name = "krate"] #![no_core] - // @has external_crate/some_module/macro.external_macro.html - // @!has external_crate/macro.external_macro.html +// @has external_crate/some_module/macro.external_macro.html +// @!has external_crate/macro.external_macro.html extern crate external_crate; pub mod inner { @@ -16,13 +16,17 @@ pub mod inner { // @!has krate/macro.raw_const.html pub macro raw_const() {} - // @has krate/inner/macro.test.html + // @has krate/inner/attr.test.html // @!has krate/macro.test.html + // @!has krate/inner/macro.test.html + // @!has krate/attr.test.html #[rustc_builtin_macro] pub macro test($item:item) {} - // @has krate/inner/macro.Clone.html + // @has krate/inner/derive.Clone.html + // @!has krate/inner/macro.Clone.html // @!has krate/macro.Clone.html + // @!has krate/derive.Clone.html #[rustc_builtin_macro] pub macro Clone($item:item) {} From cd868dcf987b71148bc40271aede9f5b02645c26 Mon Sep 17 00:00:00 2001 From: jmaargh Date: Thu, 13 Apr 2023 22:26:38 +0100 Subject: [PATCH 257/272] Cover edge cases for {f32, f64}.hypot() docs Re-phrase in a way that handles input values being either 0 or negative. --- library/std/src/f32.rs | 6 ++++-- library/std/src/f64.rs | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index c7c33678fd34..408244b2ce9e 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -581,8 +581,10 @@ impl f32 { unsafe { cmath::cbrtf(self) } } - /// Calculates the length of the hypotenuse of a right-angle triangle given - /// legs of length `x` and `y`. + /// Compute the distance between the origin and a point (`x`, `y`) on the + /// Euclidean plane. Equivalently, compute the length of the hypotenuse of a + /// right-angle triangle with other sides having length `x.abs()` and + /// `y.abs()`. /// /// # Examples /// diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index b1faa670307d..6782b861f110 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -583,8 +583,10 @@ impl f64 { unsafe { cmath::cbrt(self) } } - /// Calculates the length of the hypotenuse of a right-angle triangle given - /// legs of length `x` and `y`. + /// Compute the distance between the origin and a point (`x`, `y`) on the + /// Euclidean plane. Equivalently, compute the length of the hypotenuse of a + /// right-angle triangle with other sides having length `x.abs()` and + /// `y.abs()`. /// /// # Examples /// From 544c5a5dc33a52dd3e4019c4900d011f89ec5c59 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Thu, 13 Apr 2023 22:42:27 +0100 Subject: [PATCH 258/272] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 7bf43f028ba5..84b7041fd274 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 7bf43f028ba5eb1f4d70d271c2546c38512c9875 +Subproject commit 84b7041fd2745ee6b3b4a150314f81aabb78e6b2 From dcc51f1ef5e19dba1d791e47c0dc07f45b68fa44 Mon Sep 17 00:00:00 2001 From: Kyle Matsuda Date: Thu, 13 Apr 2023 15:16:55 -0600 Subject: [PATCH 259/272] change usage of bound_impl_subject to impl_subject --- compiler/rustc_trait_selection/src/traits/coherence.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 3c918b6028d4..93e1dfcfaae1 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -306,7 +306,7 @@ fn negative_impl(tcx: TyCtxt<'_>, impl1_def_id: DefId, impl2_def_id: DefId) -> b &infcx, ObligationCause::dummy(), impl_env, - tcx.impl_subject(impl1_def_id), + tcx.bound_impl_subject(impl1_def_id).subst_identity(), ) { Ok(s) => s, Err(err) => { From e2f5a5a71fa2a55e976484b9e72f5aa425ebab62 Mon Sep 17 00:00:00 2001 From: Kyle Matsuda Date: Thu, 13 Apr 2023 15:23:54 -0600 Subject: [PATCH 260/272] make tcx.impl_subject return EarlyBinder, remove bound_impl_subject, rename usages of bound_impl_subject to impl_subject --- compiler/rustc_middle/src/hir/mod.rs | 14 ++++++++------ compiler/rustc_middle/src/ty/util.rs | 4 ---- .../rustc_trait_selection/src/traits/coherence.rs | 2 +- compiler/rustc_trait_selection/src/traits/util.rs | 2 +- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 0d8a8c9cdfd4..50a3067c5595 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -7,7 +7,7 @@ pub mod nested_filter; pub mod place; use crate::ty::query::Providers; -use crate::ty::{ImplSubject, TyCtxt}; +use crate::ty::{EarlyBinder, ImplSubject, TyCtxt}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -104,11 +104,13 @@ impl<'tcx> TyCtxt<'tcx> { self.parent_module_from_def_id(id.owner.def_id) } - pub fn impl_subject(self, def_id: DefId) -> ImplSubject<'tcx> { - self.impl_trait_ref(def_id) - .map(|t| t.subst_identity()) - .map(ImplSubject::Trait) - .unwrap_or_else(|| ImplSubject::Inherent(self.type_of(def_id).subst_identity())) + pub fn impl_subject(self, def_id: DefId) -> EarlyBinder> { + EarlyBinder( + self.impl_trait_ref(def_id) + .map(|t| t.subst_identity()) + .map(ImplSubject::Trait) + .unwrap_or_else(|| ImplSubject::Inherent(self.type_of(def_id).subst_identity())), + ) } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 4411bcd927d7..c8a78ec03d94 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -708,10 +708,6 @@ impl<'tcx> TyCtxt<'tcx> { ty::EarlyBinder(self.explicit_item_bounds(def_id)) } - pub fn bound_impl_subject(self, def_id: DefId) -> ty::EarlyBinder> { - ty::EarlyBinder(self.impl_subject(def_id)) - } - /// Returns names of captured upvars for closures and generators. /// /// Here are some examples: diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 93e1dfcfaae1..20c2605f219a 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -306,7 +306,7 @@ fn negative_impl(tcx: TyCtxt<'_>, impl1_def_id: DefId, impl2_def_id: DefId) -> b &infcx, ObligationCause::dummy(), impl_env, - tcx.bound_impl_subject(impl1_def_id).subst_identity(), + tcx.impl_subject(impl1_def_id).subst_identity(), ) { Ok(s) => s, Err(err) => { diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 60630979b34e..20357d4d2501 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -198,7 +198,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>( impl_def_id: DefId, impl_substs: SubstsRef<'tcx>, ) -> (ImplSubject<'tcx>, impl Iterator>) { - let subject = selcx.tcx().bound_impl_subject(impl_def_id); + let subject = selcx.tcx().impl_subject(impl_def_id); let subject = subject.subst(selcx.tcx(), impl_substs); let InferOk { value: subject, obligations: normalization_obligations1 } = From 36febe1f4da6ea7e066983786171d5f85f7473d9 Mon Sep 17 00:00:00 2001 From: Bryan Garza <1396101+bryangarza@users.noreply.github.com> Date: Thu, 6 Apr 2023 01:58:53 +0000 Subject: [PATCH 261/272] Improve safe transmute error reporting This patch updates the error reporting when Safe Transmute is not possible between 2 types by including the reason. Also, fix some small bugs that occur when computing the `Answer` for transmutability. --- .../src/traits/error_reporting/mod.rs | 128 ++++++-- compiler/rustc_transmute/src/layout/tree.rs | 28 +- .../src/maybe_transmutable/mod.rs | 27 +- .../src/maybe_transmutable/tests.rs | 6 +- library/core/src/mem/transmutability.rs | 4 - .../should_require_well_defined_layout.stderr | 30 +- ...ve_reprs_should_have_correct_length.stderr | 100 +++--- .../should_require_well_defined_layout.stderr | 30 +- .../enums/should_pad_variants.stderr | 5 +- .../enums/should_respect_endianness.stderr | 5 +- .../primitives/bool.current.stderr | 5 +- .../primitives/bool.next.stderr | 5 +- .../primitives/numbers.current.stderr | 285 +++++++----------- .../primitives/numbers.next.stderr | 285 +++++++----------- .../primitives/unit.current.stderr | 5 +- .../primitives/unit.next.stderr | 5 +- .../transmutability/references.current.stderr | 5 +- .../ui/transmutability/references.next.stderr | 5 +- .../should_require_well_defined_layout.stderr | 60 ++-- .../should_require_well_defined_layout.stderr | 10 +- .../unions/should_pad_variants.stderr | 5 +- .../unions/should_reject_contraction.stderr | 5 +- .../unions/should_reject_disjoint.stderr | 10 +- .../unions/should_reject_intersecting.stderr | 10 +- ...uld_reject_if_dst_has_private_field.stderr | 5 +- ...d_reject_if_dst_has_private_variant.stderr | 5 +- ...reject_if_dst_has_unreachable_field.stderr | 5 +- ...ld_reject_if_dst_has_unreachable_ty.stderr | 5 +- .../ui/transmute/transmute-padding-ice.stderr | 5 +- 29 files changed, 495 insertions(+), 593 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 6ebf056f0e83..b9d6ade5313f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -663,6 +663,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return; } let trait_ref = trait_predicate.to_poly_trait_ref(); + let (post_message, pre_message, type_def) = self .get_parent_trait_ref(obligation.cause.code()) .map(|(t, s)| { @@ -702,33 +703,45 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { (message, note, append_const_msg) }; - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0277, - "{}", - message - .and_then(|cannot_do_this| { - match (predicate_is_const, append_const_msg) { - // do nothing if predicate is not const - (false, _) => Some(cannot_do_this), - // suggested using default post message - (true, Some(None)) => { - Some(format!("{cannot_do_this} in const contexts")) - } - // overridden post message - (true, Some(Some(post_message))) => { - Some(format!("{cannot_do_this}{post_message}")) - } - // fallback to generic message - (true, None) => None, + let err_msg = message + .and_then(|cannot_do_this| { + match (predicate_is_const, append_const_msg) { + // do nothing if predicate is not const + (false, _) => Some(cannot_do_this), + // suggested using default post message + (true, Some(None)) => { + Some(format!("{cannot_do_this} in const contexts")) } - }) - .unwrap_or_else(|| format!( + // overridden post message + (true, Some(Some(post_message))) => { + Some(format!("{cannot_do_this}{post_message}")) + } + // fallback to generic message + (true, None) => None, + } + }) + .unwrap_or_else(|| { + format!( "the trait bound `{}` is not satisfied{}", trait_predicate, post_message, - )) - ); + ) + }); + + let (err_msg, safe_transmute_explanation) = if Some(trait_ref.def_id()) + == self.tcx.lang_items().transmute_trait() + { + // Recompute the safe transmute reason and use that for the error reporting + self.get_safe_transmute_error_and_reason( + trait_predicate, + obligation.clone(), + trait_ref, + span, + ) + } else { + (err_msg, None) + }; + + let mut err = struct_span_err!(self.tcx.sess, span, E0277, "{}", err_msg); if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) { err.span_label( @@ -818,6 +831,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // at the type param with a label to suggest constraining it. err.help(&explanation); } + } else if let Some(custom_explanation) = safe_transmute_explanation { + err.span_label(span, custom_explanation); } else { err.span_label(span, explanation); } @@ -1601,6 +1616,14 @@ trait InferCtxtPrivExt<'tcx> { obligated_types: &mut Vec>, cause_code: &ObligationCauseCode<'tcx>, ) -> bool; + + fn get_safe_transmute_error_and_reason( + &self, + trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, + obligation: Obligation<'tcx, ty::Predicate<'tcx>>, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + span: Span, + ) -> (String, Option); } impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { @@ -2879,6 +2902,63 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } false } + + fn get_safe_transmute_error_and_reason( + &self, + trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, + obligation: Obligation<'tcx, ty::Predicate<'tcx>>, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + span: Span, + ) -> (String, Option) { + let src_and_dst = trait_predicate.map_bound(|p| rustc_transmute::Types { + dst: p.trait_ref.substs.type_at(0), + src: p.trait_ref.substs.type_at(1), + }); + let scope = trait_ref.skip_binder().substs.type_at(2); + let Some(assume) = + rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.skip_binder().substs.const_at(3)) else { + span_bug!(span, "Unable to construct rustc_transmute::Assume where it was previously possible"); + }; + match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable( + obligation.cause, + src_and_dst, + scope, + assume, + ) { + rustc_transmute::Answer::No(reason) => { + let dst = trait_ref.skip_binder().substs.type_at(0); + let src = trait_ref.skip_binder().substs.type_at(1); + let custom_err_msg = format!("`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`").to_string(); + let reason_msg = match reason { + rustc_transmute::Reason::SrcIsUnspecified => { + format!("`{src}` does not have a well-specified layout").to_string() + } + rustc_transmute::Reason::DstIsUnspecified => { + format!("`{dst}` does not have a well-specified layout").to_string() + } + rustc_transmute::Reason::DstIsBitIncompatible => { + format!("At least one value of `{src}` isn't a bit-valid value of `{dst}`") + .to_string() + } + rustc_transmute::Reason::DstIsPrivate => format!( + "`{dst}` is or contains a type or field that is not visible in that scope" + ) + .to_string(), + // FIXME(bryangarza): Include the number of bytes of src and dst + rustc_transmute::Reason::DstIsTooBig => { + format!("The size of `{src}` is smaller than the size of `{dst}`") + } + }; + (custom_err_msg, Some(reason_msg)) + } + // Should never get a Yes at this point! We already ran it before, and did not get a Yes. + rustc_transmute::Answer::Yes => span_bug!( + span, + "Inconsistent rustc_transmute::is_transmutable(...) result, got Yes", + ), + _ => span_bug!(span, "Unsupported rustc_transmute::Reason variant"), + } + } } /// Crude way of getting back an `Expr` from a `Span`. diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 295b65c2cc92..2a89494c80b0 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -167,31 +167,31 @@ where } } -#[derive(Debug, Copy, Clone)] -pub(crate) enum Err { - /// The layout of the type is unspecified. - Unspecified, - /// This error will be surfaced elsewhere by rustc, so don't surface it. - Unknown, -} - #[cfg(feature = "rustc")] pub(crate) mod rustc { - use super::{Err, Tree}; + use super::Tree; use crate::layout::rustc::{Def, Ref}; - use rustc_middle::ty; use rustc_middle::ty::layout::LayoutError; use rustc_middle::ty::util::Discr; use rustc_middle::ty::AdtDef; use rustc_middle::ty::ParamEnv; use rustc_middle::ty::SubstsRef; - use rustc_middle::ty::Ty; - use rustc_middle::ty::TyCtxt; use rustc_middle::ty::VariantDef; + use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; + use rustc_span::ErrorGuaranteed; use rustc_target::abi::Align; use std::alloc; + #[derive(Debug, Copy, Clone)] + pub(crate) enum Err { + /// The layout of the type is unspecified. + Unspecified, + /// This error will be surfaced elsewhere by rustc, so don't surface it. + Unknown, + TypeError(ErrorGuaranteed), + } + impl<'tcx> From> for Err { fn from(err: LayoutError<'tcx>) -> Self { match err { @@ -261,6 +261,10 @@ pub(crate) mod rustc { use rustc_middle::ty::UintTy::*; use rustc_target::abi::HasDataLayout; + if let Err(e) = ty.error_reported() { + return Err(Err::TypeError(e)); + } + let target = tcx.data_layout(); match ty.kind() { diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 1186eac37abd..2e2fb90e71c1 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -56,7 +56,7 @@ where #[cfg(feature = "rustc")] mod rustc { use super::*; - use crate::layout::tree::Err; + use crate::layout::tree::rustc::Err; use rustc_middle::ty::Ty; use rustc_middle::ty::TyCtxt; @@ -71,19 +71,20 @@ mod rustc { // representations. If these conversions fail, conclude that the transmutation is // unacceptable; the layouts of both the source and destination types must be // well-defined. - let src = Tree::from_ty(src, context).map_err(|err| match err { - // Answer `Yes` here, because "Unknown Type" will already be reported by - // rustc. No need to spam the user with more errors. - Err::Unknown => Answer::Yes, - Err::Unspecified => Answer::No(Reason::SrcIsUnspecified), - })?; + let src = Tree::from_ty(src, context); + let dst = Tree::from_ty(dst, context); - let dst = Tree::from_ty(dst, context).map_err(|err| match err { - Err::Unknown => Answer::Yes, - Err::Unspecified => Answer::No(Reason::DstIsUnspecified), - })?; - - Ok((src, dst)) + match (src, dst) { + // Answer `Yes` here, because 'unknown layout' and type errors will already + // be reported by rustc. No need to spam the user with more errors. + (Err(Err::TypeError(_)), _) => Err(Answer::Yes), + (_, Err(Err::TypeError(_))) => Err(Answer::Yes), + (Err(Err::Unknown), _) => Err(Answer::Yes), + (_, Err(Err::Unknown)) => Err(Answer::Yes), + (Err(Err::Unspecified), _) => Err(Answer::No(Reason::SrcIsUnspecified)), + (_, Err(Err::Unspecified)) => Err(Answer::No(Reason::DstIsUnspecified)), + (Ok(src), Ok(dst)) => Ok((src, dst)), + } }); match query_or_answer { diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs index 4d5772a4f2ea..a8675f4ae37d 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs @@ -1,6 +1,6 @@ use super::query_context::test::{Def, UltraMinimal}; use crate::maybe_transmutable::MaybeTransmutableQuery; -use crate::{layout, Answer, Reason, Set}; +use crate::{layout, Answer, Reason}; use itertools::Itertools; mod bool { @@ -48,9 +48,9 @@ mod bool { let into_set = |alts: Vec<_>| { #[cfg(feature = "rustc")] - let mut set = Set::default(); + let mut set = crate::Set::default(); #[cfg(not(feature = "rustc"))] - let mut set = Set::new(); + let mut set = std::collections::HashSet::new(); set.extend(alts); set }; diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index 3b98efff2938..b53a330fa560 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -5,10 +5,6 @@ /// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied. #[unstable(feature = "transmutability", issue = "99571")] #[lang = "transmute_trait"] -#[rustc_on_unimplemented( - message = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`.", - label = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`." -)] pub unsafe trait BikeshedIntrinsicFrom where Src: ?Sized, diff --git a/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr b/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr index 164e88ede202..1a0a5d3ae946 100644 --- a/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr +++ b/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr @@ -1,10 +1,9 @@ -error[E0277]: `[String; 0]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. +error[E0277]: `[String; 0]` cannot be safely transmuted into `()` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:26:52 | LL | assert::is_maybe_transmutable::(); - | ^^ `[String; 0]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. + | ^^ `[String; 0]` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom<[String; 0], assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -20,13 +19,12 @@ LL | | .and(Assume::VALIDITY) LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `u128` cannot be safely transmuted into `[String; 0]` in the defining scope of `assert::Context`. +error[E0277]: `u128` cannot be safely transmuted into `[String; 0]` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:27:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 0]` in the defining scope of `assert::Context`. + | ^^^^^^^^^ `[String; 0]` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 0]` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -42,13 +40,12 @@ LL | | .and(Assume::VALIDITY) LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `[String; 1]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. +error[E0277]: `[String; 1]` cannot be safely transmuted into `()` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:32:52 | LL | assert::is_maybe_transmutable::(); - | ^^ `[String; 1]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. + | ^^ `[String; 1]` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom<[String; 1], assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -64,13 +61,12 @@ LL | | .and(Assume::VALIDITY) LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `u128` cannot be safely transmuted into `[String; 1]` in the defining scope of `assert::Context`. +error[E0277]: `u128` cannot be safely transmuted into `[String; 1]` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:33:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 1]` in the defining scope of `assert::Context`. + | ^^^^^^^^^ `[String; 1]` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 1]` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -86,13 +82,12 @@ LL | | .and(Assume::VALIDITY) LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `[String; 2]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. +error[E0277]: `[String; 2]` cannot be safely transmuted into `()` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:38:52 | LL | assert::is_maybe_transmutable::(); - | ^^ `[String; 2]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. + | ^^ `[String; 2]` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom<[String; 2], assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -108,13 +103,12 @@ LL | | .and(Assume::VALIDITY) LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `u128` cannot be safely transmuted into `[String; 2]` in the defining scope of `assert::Context`. +error[E0277]: `u128` cannot be safely transmuted into `[String; 2]` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:39:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 2]` in the defining scope of `assert::Context`. + | ^^^^^^^^^ `[String; 2]` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 2]` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | diff --git a/tests/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr b/tests/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr index 0f0f77f16837..9877a6606a9f 100644 --- a/tests/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr +++ b/tests/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr @@ -1,10 +1,9 @@ -error[E0277]: `Zst` cannot be safely transmuted into `V0i8` in the defining scope of `n8::Context`. +error[E0277]: `Zst` cannot be safely transmuted into `V0i8` in the defining scope of `n8::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:48:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ `Zst` cannot be safely transmuted into `V0i8` in the defining scope of `n8::Context`. + | ^^^^^^^ The size of `Zst` is smaller than the size of `V0i8` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0i8` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -21,13 +20,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `V0i8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`. +error[E0277]: `V0i8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:50:44 | LL | assert::is_transmutable::(); - | ^^^^^^ `V0i8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`. + | ^^^^^^ The size of `V0i8` is smaller than the size of `u16` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u16` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -44,13 +42,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `Zst` cannot be safely transmuted into `V0u8` in the defining scope of `n8::Context`. +error[E0277]: `Zst` cannot be safely transmuted into `V0u8` in the defining scope of `n8::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:56:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ `Zst` cannot be safely transmuted into `V0u8` in the defining scope of `n8::Context`. + | ^^^^^^^ The size of `Zst` is smaller than the size of `V0u8` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0u8` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -67,13 +64,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `V0u8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`. +error[E0277]: `V0u8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:58:44 | LL | assert::is_transmutable::(); - | ^^^^^^ `V0u8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`. + | ^^^^^^ The size of `V0u8` is smaller than the size of `u16` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u16` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -90,13 +86,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `V0i16` in the defining scope of `n16::Context`. +error[E0277]: `u8` cannot be safely transmuted into `V0i16` in the defining scope of `n16::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:72:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ `u8` cannot be safely transmuted into `V0i16` in the defining scope of `n16::Context`. + | ^^^^^^^ At least one value of `u8` isn't a bit-valid value of `V0i16` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0i16` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -113,13 +108,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `V0i16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`. +error[E0277]: `V0i16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:74:44 | LL | assert::is_transmutable::(); - | ^^^^^^ `V0i16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`. + | ^^^^^^ The size of `V0i16` is smaller than the size of `u32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -136,13 +130,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `V0u16` in the defining scope of `n16::Context`. +error[E0277]: `u8` cannot be safely transmuted into `V0u16` in the defining scope of `n16::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:80:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ `u8` cannot be safely transmuted into `V0u16` in the defining scope of `n16::Context`. + | ^^^^^^^ At least one value of `u8` isn't a bit-valid value of `V0u16` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0u16` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -159,13 +152,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `V0u16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`. +error[E0277]: `V0u16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:82:44 | LL | assert::is_transmutable::(); - | ^^^^^^ `V0u16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`. + | ^^^^^^ The size of `V0u16` is smaller than the size of `u32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -182,13 +174,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `u16` cannot be safely transmuted into `V0i32` in the defining scope of `n32::Context`. +error[E0277]: `u16` cannot be safely transmuted into `V0i32` in the defining scope of `n32::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:96:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ `u16` cannot be safely transmuted into `V0i32` in the defining scope of `n32::Context`. + | ^^^^^^^ At least one value of `u16` isn't a bit-valid value of `V0i32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0i32` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -205,13 +196,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `V0i32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`. +error[E0277]: `V0i32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:98:44 | LL | assert::is_transmutable::(); - | ^^^^^^ `V0i32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`. + | ^^^^^^ The size of `V0i32` is smaller than the size of `u64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -228,13 +218,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `u16` cannot be safely transmuted into `V0u32` in the defining scope of `n32::Context`. +error[E0277]: `u16` cannot be safely transmuted into `V0u32` in the defining scope of `n32::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:104:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ `u16` cannot be safely transmuted into `V0u32` in the defining scope of `n32::Context`. + | ^^^^^^^ At least one value of `u16` isn't a bit-valid value of `V0u32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0u32` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -251,13 +240,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `V0u32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`. +error[E0277]: `V0u32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:106:44 | LL | assert::is_transmutable::(); - | ^^^^^^ `V0u32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`. + | ^^^^^^ The size of `V0u32` is smaller than the size of `u64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -274,13 +262,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `u32` cannot be safely transmuted into `V0i64` in the defining scope of `n64::Context`. +error[E0277]: `u32` cannot be safely transmuted into `V0i64` in the defining scope of `n64::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:120:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ `u32` cannot be safely transmuted into `V0i64` in the defining scope of `n64::Context`. + | ^^^^^^^ At least one value of `u32` isn't a bit-valid value of `V0i64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0i64` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -297,13 +284,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `V0i64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`. +error[E0277]: `V0i64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:122:44 | LL | assert::is_transmutable::(); - | ^^^^^^ `V0i64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`. + | ^^^^^^ The size of `V0i64` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -320,13 +306,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `u32` cannot be safely transmuted into `V0u64` in the defining scope of `n64::Context`. +error[E0277]: `u32` cannot be safely transmuted into `V0u64` in the defining scope of `n64::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:128:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ `u32` cannot be safely transmuted into `V0u64` in the defining scope of `n64::Context`. + | ^^^^^^^ At least one value of `u32` isn't a bit-valid value of `V0u64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0u64` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -343,13 +328,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `V0u64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`. +error[E0277]: `V0u64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:130:44 | LL | assert::is_transmutable::(); - | ^^^^^^ `V0u64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`. + | ^^^^^^ The size of `V0u64` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -366,13 +350,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `V0isize` in the defining scope of `nsize::Context`. +error[E0277]: `u8` cannot be safely transmuted into `V0isize` in the defining scope of `nsize::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:144:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ `u8` cannot be safely transmuted into `V0isize` in the defining scope of `nsize::Context`. + | ^^^^^^^ At least one value of `u8` isn't a bit-valid value of `V0isize` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0isize` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -389,13 +372,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `V0isize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`. +error[E0277]: `V0isize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:146:44 | LL | assert::is_transmutable::(); - | ^^^^^^ `V0isize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`. + | ^^^^^^ The size of `V0isize` is smaller than the size of `[usize; 2]` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `[usize; 2]` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -412,13 +394,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `V0usize` in the defining scope of `nsize::Context`. +error[E0277]: `u8` cannot be safely transmuted into `V0usize` in the defining scope of `nsize::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:152:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ `u8` cannot be safely transmuted into `V0usize` in the defining scope of `nsize::Context`. + | ^^^^^^^ At least one value of `u8` isn't a bit-valid value of `V0usize` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0usize` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -435,13 +416,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_transmutable` -error[E0277]: `V0usize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`. +error[E0277]: `V0usize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context` --> $DIR/primitive_reprs_should_have_correct_length.rs:154:44 | LL | assert::is_transmutable::(); - | ^^^^^^ `V0usize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`. + | ^^^^^^ The size of `V0usize` is smaller than the size of `[usize; 2]` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `[usize; 2]` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | diff --git a/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr b/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr index d456a746f5eb..1612b6b3661e 100644 --- a/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr +++ b/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr @@ -1,10 +1,9 @@ -error[E0277]: `void::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. +error[E0277]: `void::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:28:52 | LL | assert::is_maybe_transmutable::(); - | ^^ `void::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. + | ^^ `void::repr_rust` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 | @@ -21,13 +20,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `u128` cannot be safely transmuted into `void::repr_rust` in the defining scope of `assert::Context`. +error[E0277]: `u128` cannot be safely transmuted into `void::repr_rust` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:29:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ `u128` cannot be safely transmuted into `void::repr_rust` in the defining scope of `assert::Context`. + | ^^^^^^^^^ `void::repr_rust` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `void::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 | @@ -44,13 +42,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `singleton::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. +error[E0277]: `singleton::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:34:52 | LL | assert::is_maybe_transmutable::(); - | ^^ `singleton::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. + | ^^ `singleton::repr_rust` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 | @@ -67,13 +64,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `u128` cannot be safely transmuted into `singleton::repr_rust` in the defining scope of `assert::Context`. +error[E0277]: `u128` cannot be safely transmuted into `singleton::repr_rust` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:35:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ `u128` cannot be safely transmuted into `singleton::repr_rust` in the defining scope of `assert::Context`. + | ^^^^^^^^^ `singleton::repr_rust` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `singleton::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 | @@ -90,13 +86,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `duplex::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. +error[E0277]: `duplex::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:40:52 | LL | assert::is_maybe_transmutable::(); - | ^^ `duplex::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. + | ^^ `duplex::repr_rust` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 | @@ -113,13 +108,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `u128` cannot be safely transmuted into `duplex::repr_rust` in the defining scope of `assert::Context`. +error[E0277]: `u128` cannot be safely transmuted into `duplex::repr_rust` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:41:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ `u128` cannot be safely transmuted into `duplex::repr_rust` in the defining scope of `assert::Context`. + | ^^^^^^^^^ `duplex::repr_rust` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `duplex::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 | diff --git a/tests/ui/transmutability/enums/should_pad_variants.stderr b/tests/ui/transmutability/enums/should_pad_variants.stderr index f4988239df94..bfbef8b25fcf 100644 --- a/tests/ui/transmutability/enums/should_pad_variants.stderr +++ b/tests/ui/transmutability/enums/should_pad_variants.stderr @@ -1,10 +1,9 @@ -error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`. +error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context` --> $DIR/should_pad_variants.rs:44:36 | LL | assert::is_transmutable::(); - | ^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`. + | ^^^ The size of `Src` is smaller than the size of `Dst` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` note: required by a bound in `is_transmutable` --> $DIR/should_pad_variants.rs:13:14 | diff --git a/tests/ui/transmutability/enums/should_respect_endianness.stderr b/tests/ui/transmutability/enums/should_respect_endianness.stderr index 350583b0b851..e59301a8ce9e 100644 --- a/tests/ui/transmutability/enums/should_respect_endianness.stderr +++ b/tests/ui/transmutability/enums/should_respect_endianness.stderr @@ -1,10 +1,9 @@ -error[E0277]: `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`. +error[E0277]: `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context` --> $DIR/should_respect_endianness.rs:36:36 | LL | assert::is_transmutable::(); - | ^^^^^^^^^^ `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`. + | ^^^^^^^^^^ At least one value of `Src` isn't a bit-valid value of `Unexpected` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Unexpected` note: required by a bound in `is_transmutable` --> $DIR/should_respect_endianness.rs:14:14 | diff --git a/tests/ui/transmutability/primitives/bool.current.stderr b/tests/ui/transmutability/primitives/bool.current.stderr index 999302224eeb..47c8438a251c 100644 --- a/tests/ui/transmutability/primitives/bool.current.stderr +++ b/tests/ui/transmutability/primitives/bool.current.stderr @@ -1,10 +1,9 @@ -error[E0277]: `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context` --> $DIR/bool.rs:24:35 | LL | assert::is_transmutable::(); - | ^^^^ `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`. + | ^^^^ At least one value of `u8` isn't a bit-valid value of `bool` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `bool` note: required by a bound in `is_transmutable` --> $DIR/bool.rs:14:14 | diff --git a/tests/ui/transmutability/primitives/bool.next.stderr b/tests/ui/transmutability/primitives/bool.next.stderr index 999302224eeb..47c8438a251c 100644 --- a/tests/ui/transmutability/primitives/bool.next.stderr +++ b/tests/ui/transmutability/primitives/bool.next.stderr @@ -1,10 +1,9 @@ -error[E0277]: `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context` --> $DIR/bool.rs:24:35 | LL | assert::is_transmutable::(); - | ^^^^ `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`. + | ^^^^ At least one value of `u8` isn't a bit-valid value of `bool` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `bool` note: required by a bound in `is_transmutable` --> $DIR/bool.rs:14:14 | diff --git a/tests/ui/transmutability/primitives/numbers.current.stderr b/tests/ui/transmutability/primitives/numbers.current.stderr index bbf1f1669995..d12e172971c3 100644 --- a/tests/ui/transmutability/primitives/numbers.current.stderr +++ b/tests/ui/transmutability/primitives/numbers.current.stderr @@ -1,10 +1,9 @@ -error[E0277]: `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context` --> $DIR/numbers.rs:65:40 | LL | assert::is_transmutable::< i8, i16>(); - | ^^^ `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. + | ^^^ The size of `i8` is smaller than the size of `i16` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i16` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -14,13 +13,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context` --> $DIR/numbers.rs:66:40 | LL | assert::is_transmutable::< i8, u16>(); - | ^^^ `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. + | ^^^ The size of `i8` is smaller than the size of `u16` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u16` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -30,13 +28,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:67:40 | LL | assert::is_transmutable::< i8, i32>(); - | ^^^ `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. + | ^^^ The size of `i8` is smaller than the size of `i32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -46,13 +43,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:68:40 | LL | assert::is_transmutable::< i8, f32>(); - | ^^^ `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. + | ^^^ The size of `i8` is smaller than the size of `f32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -62,13 +58,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:69:40 | LL | assert::is_transmutable::< i8, u32>(); - | ^^^ `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. + | ^^^ The size of `i8` is smaller than the size of `u32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -78,13 +73,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:70:40 | LL | assert::is_transmutable::< i8, u64>(); - | ^^^ `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | ^^^ The size of `i8` is smaller than the size of `u64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -94,13 +88,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:71:40 | LL | assert::is_transmutable::< i8, i64>(); - | ^^^ `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | ^^^ The size of `i8` is smaller than the size of `i64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -110,13 +103,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:72:40 | LL | assert::is_transmutable::< i8, f64>(); - | ^^^ `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | ^^^ The size of `i8` is smaller than the size of `f64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -126,13 +118,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:73:39 | LL | assert::is_transmutable::< i8, u128>(); - | ^^^^ `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `i8` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -142,13 +133,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:74:39 | LL | assert::is_transmutable::< i8, i128>(); - | ^^^^ `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `i8` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -158,13 +148,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context` --> $DIR/numbers.rs:76:40 | LL | assert::is_transmutable::< u8, i16>(); - | ^^^ `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. + | ^^^ The size of `u8` is smaller than the size of `i16` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i16` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -174,13 +163,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context` --> $DIR/numbers.rs:77:40 | LL | assert::is_transmutable::< u8, u16>(); - | ^^^ `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. + | ^^^ The size of `u8` is smaller than the size of `u16` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u16` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -190,13 +178,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:78:40 | LL | assert::is_transmutable::< u8, i32>(); - | ^^^ `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. + | ^^^ The size of `u8` is smaller than the size of `i32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -206,13 +193,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:79:40 | LL | assert::is_transmutable::< u8, f32>(); - | ^^^ `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. + | ^^^ The size of `u8` is smaller than the size of `f32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -222,13 +208,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:80:40 | LL | assert::is_transmutable::< u8, u32>(); - | ^^^ `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. + | ^^^ The size of `u8` is smaller than the size of `u32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -238,13 +223,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:81:40 | LL | assert::is_transmutable::< u8, u64>(); - | ^^^ `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | ^^^ The size of `u8` is smaller than the size of `u64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -254,13 +238,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:82:40 | LL | assert::is_transmutable::< u8, i64>(); - | ^^^ `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | ^^^ The size of `u8` is smaller than the size of `i64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -270,13 +253,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:83:40 | LL | assert::is_transmutable::< u8, f64>(); - | ^^^ `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | ^^^ The size of `u8` is smaller than the size of `f64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -286,13 +268,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:84:39 | LL | assert::is_transmutable::< u8, u128>(); - | ^^^^ `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `u8` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -302,13 +283,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:85:39 | LL | assert::is_transmutable::< u8, i128>(); - | ^^^^ `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `u8` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -318,13 +298,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. +error[E0277]: `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:87:40 | LL | assert::is_transmutable::< i16, i32>(); - | ^^^ `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. + | ^^^ The size of `i16` is smaller than the size of `i32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -334,13 +313,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. +error[E0277]: `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:88:40 | LL | assert::is_transmutable::< i16, f32>(); - | ^^^ `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. + | ^^^ The size of `i16` is smaller than the size of `f32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -350,13 +328,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. +error[E0277]: `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:89:40 | LL | assert::is_transmutable::< i16, u32>(); - | ^^^ `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. + | ^^^ The size of `i16` is smaller than the size of `u32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -366,13 +343,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. +error[E0277]: `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:90:40 | LL | assert::is_transmutable::< i16, u64>(); - | ^^^ `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | ^^^ The size of `i16` is smaller than the size of `u64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -382,13 +358,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. +error[E0277]: `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:91:40 | LL | assert::is_transmutable::< i16, i64>(); - | ^^^ `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | ^^^ The size of `i16` is smaller than the size of `i64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -398,13 +373,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. +error[E0277]: `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:92:40 | LL | assert::is_transmutable::< i16, f64>(); - | ^^^ `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | ^^^ The size of `i16` is smaller than the size of `f64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -414,13 +388,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:93:39 | LL | assert::is_transmutable::< i16, u128>(); - | ^^^^ `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `i16` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -430,13 +403,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:94:39 | LL | assert::is_transmutable::< i16, i128>(); - | ^^^^ `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `i16` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -446,13 +418,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. +error[E0277]: `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:96:40 | LL | assert::is_transmutable::< u16, i32>(); - | ^^^ `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. + | ^^^ The size of `u16` is smaller than the size of `i32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -462,13 +433,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. +error[E0277]: `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:97:40 | LL | assert::is_transmutable::< u16, f32>(); - | ^^^ `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. + | ^^^ The size of `u16` is smaller than the size of `f32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -478,13 +448,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. +error[E0277]: `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:98:40 | LL | assert::is_transmutable::< u16, u32>(); - | ^^^ `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. + | ^^^ The size of `u16` is smaller than the size of `u32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -494,13 +463,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. +error[E0277]: `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:99:40 | LL | assert::is_transmutable::< u16, u64>(); - | ^^^ `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | ^^^ The size of `u16` is smaller than the size of `u64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -510,13 +478,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. +error[E0277]: `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:100:40 | LL | assert::is_transmutable::< u16, i64>(); - | ^^^ `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | ^^^ The size of `u16` is smaller than the size of `i64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -526,13 +493,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. +error[E0277]: `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:101:40 | LL | assert::is_transmutable::< u16, f64>(); - | ^^^ `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | ^^^ The size of `u16` is smaller than the size of `f64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -542,13 +508,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:102:39 | LL | assert::is_transmutable::< u16, u128>(); - | ^^^^ `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `u16` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -558,13 +523,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:103:39 | LL | assert::is_transmutable::< u16, i128>(); - | ^^^^ `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `u16` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -574,13 +538,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. +error[E0277]: `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:105:40 | LL | assert::is_transmutable::< i32, u64>(); - | ^^^ `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | ^^^ The size of `i32` is smaller than the size of `u64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -590,13 +553,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. +error[E0277]: `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:106:40 | LL | assert::is_transmutable::< i32, i64>(); - | ^^^ `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | ^^^ The size of `i32` is smaller than the size of `i64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -606,13 +568,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. +error[E0277]: `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:107:40 | LL | assert::is_transmutable::< i32, f64>(); - | ^^^ `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | ^^^ The size of `i32` is smaller than the size of `f64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -622,13 +583,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:108:39 | LL | assert::is_transmutable::< i32, u128>(); - | ^^^^ `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `i32` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -638,13 +598,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:109:39 | LL | assert::is_transmutable::< i32, i128>(); - | ^^^^ `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `i32` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -654,13 +613,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. +error[E0277]: `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:111:40 | LL | assert::is_transmutable::< f32, u64>(); - | ^^^ `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | ^^^ The size of `f32` is smaller than the size of `u64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -670,13 +628,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. +error[E0277]: `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:112:40 | LL | assert::is_transmutable::< f32, i64>(); - | ^^^ `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | ^^^ The size of `f32` is smaller than the size of `i64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -686,13 +643,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. +error[E0277]: `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:113:40 | LL | assert::is_transmutable::< f32, f64>(); - | ^^^ `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | ^^^ The size of `f32` is smaller than the size of `f64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -702,13 +658,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:114:39 | LL | assert::is_transmutable::< f32, u128>(); - | ^^^^ `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `f32` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -718,13 +673,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:115:39 | LL | assert::is_transmutable::< f32, i128>(); - | ^^^^ `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `f32` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -734,13 +688,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. +error[E0277]: `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:117:40 | LL | assert::is_transmutable::< u32, u64>(); - | ^^^ `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | ^^^ The size of `u32` is smaller than the size of `u64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -750,13 +703,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. +error[E0277]: `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:118:40 | LL | assert::is_transmutable::< u32, i64>(); - | ^^^ `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | ^^^ The size of `u32` is smaller than the size of `i64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -766,13 +718,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. +error[E0277]: `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:119:40 | LL | assert::is_transmutable::< u32, f64>(); - | ^^^ `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | ^^^ The size of `u32` is smaller than the size of `f64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -782,13 +733,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:120:39 | LL | assert::is_transmutable::< u32, u128>(); - | ^^^^ `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `u32` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -798,13 +748,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:121:39 | LL | assert::is_transmutable::< u32, i128>(); - | ^^^^ `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `u32` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -814,13 +763,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:123:39 | LL | assert::is_transmutable::< u64, u128>(); - | ^^^^ `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `u64` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -830,13 +778,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:124:39 | LL | assert::is_transmutable::< u64, i128>(); - | ^^^^ `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `u64` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -846,13 +793,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:126:39 | LL | assert::is_transmutable::< i64, u128>(); - | ^^^^ `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `i64` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -862,13 +808,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:127:39 | LL | assert::is_transmutable::< i64, i128>(); - | ^^^^ `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `i64` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -878,13 +823,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:129:39 | LL | assert::is_transmutable::< f64, u128>(); - | ^^^^ `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `f64` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -894,13 +838,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:130:39 | LL | assert::is_transmutable::< f64, i128>(); - | ^^^^ `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `f64` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | diff --git a/tests/ui/transmutability/primitives/numbers.next.stderr b/tests/ui/transmutability/primitives/numbers.next.stderr index bbf1f1669995..d12e172971c3 100644 --- a/tests/ui/transmutability/primitives/numbers.next.stderr +++ b/tests/ui/transmutability/primitives/numbers.next.stderr @@ -1,10 +1,9 @@ -error[E0277]: `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context` --> $DIR/numbers.rs:65:40 | LL | assert::is_transmutable::< i8, i16>(); - | ^^^ `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. + | ^^^ The size of `i8` is smaller than the size of `i16` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i16` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -14,13 +13,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context` --> $DIR/numbers.rs:66:40 | LL | assert::is_transmutable::< i8, u16>(); - | ^^^ `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. + | ^^^ The size of `i8` is smaller than the size of `u16` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u16` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -30,13 +28,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:67:40 | LL | assert::is_transmutable::< i8, i32>(); - | ^^^ `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. + | ^^^ The size of `i8` is smaller than the size of `i32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -46,13 +43,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:68:40 | LL | assert::is_transmutable::< i8, f32>(); - | ^^^ `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. + | ^^^ The size of `i8` is smaller than the size of `f32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -62,13 +58,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:69:40 | LL | assert::is_transmutable::< i8, u32>(); - | ^^^ `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. + | ^^^ The size of `i8` is smaller than the size of `u32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -78,13 +73,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:70:40 | LL | assert::is_transmutable::< i8, u64>(); - | ^^^ `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | ^^^ The size of `i8` is smaller than the size of `u64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -94,13 +88,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:71:40 | LL | assert::is_transmutable::< i8, i64>(); - | ^^^ `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | ^^^ The size of `i8` is smaller than the size of `i64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -110,13 +103,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:72:40 | LL | assert::is_transmutable::< i8, f64>(); - | ^^^ `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | ^^^ The size of `i8` is smaller than the size of `f64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -126,13 +118,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:73:39 | LL | assert::is_transmutable::< i8, u128>(); - | ^^^^ `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `i8` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -142,13 +133,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:74:39 | LL | assert::is_transmutable::< i8, i128>(); - | ^^^^ `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `i8` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -158,13 +148,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context` --> $DIR/numbers.rs:76:40 | LL | assert::is_transmutable::< u8, i16>(); - | ^^^ `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. + | ^^^ The size of `u8` is smaller than the size of `i16` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i16` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -174,13 +163,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context` --> $DIR/numbers.rs:77:40 | LL | assert::is_transmutable::< u8, u16>(); - | ^^^ `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. + | ^^^ The size of `u8` is smaller than the size of `u16` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u16` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -190,13 +178,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:78:40 | LL | assert::is_transmutable::< u8, i32>(); - | ^^^ `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. + | ^^^ The size of `u8` is smaller than the size of `i32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -206,13 +193,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:79:40 | LL | assert::is_transmutable::< u8, f32>(); - | ^^^ `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. + | ^^^ The size of `u8` is smaller than the size of `f32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -222,13 +208,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:80:40 | LL | assert::is_transmutable::< u8, u32>(); - | ^^^ `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. + | ^^^ The size of `u8` is smaller than the size of `u32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -238,13 +223,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:81:40 | LL | assert::is_transmutable::< u8, u64>(); - | ^^^ `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | ^^^ The size of `u8` is smaller than the size of `u64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -254,13 +238,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:82:40 | LL | assert::is_transmutable::< u8, i64>(); - | ^^^ `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | ^^^ The size of `u8` is smaller than the size of `i64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -270,13 +253,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:83:40 | LL | assert::is_transmutable::< u8, f64>(); - | ^^^ `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | ^^^ The size of `u8` is smaller than the size of `f64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -286,13 +268,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:84:39 | LL | assert::is_transmutable::< u8, u128>(); - | ^^^^ `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `u8` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -302,13 +283,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:85:39 | LL | assert::is_transmutable::< u8, i128>(); - | ^^^^ `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `u8` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -318,13 +298,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. +error[E0277]: `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:87:40 | LL | assert::is_transmutable::< i16, i32>(); - | ^^^ `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. + | ^^^ The size of `i16` is smaller than the size of `i32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -334,13 +313,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. +error[E0277]: `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:88:40 | LL | assert::is_transmutable::< i16, f32>(); - | ^^^ `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. + | ^^^ The size of `i16` is smaller than the size of `f32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -350,13 +328,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. +error[E0277]: `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:89:40 | LL | assert::is_transmutable::< i16, u32>(); - | ^^^ `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. + | ^^^ The size of `i16` is smaller than the size of `u32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -366,13 +343,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. +error[E0277]: `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:90:40 | LL | assert::is_transmutable::< i16, u64>(); - | ^^^ `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | ^^^ The size of `i16` is smaller than the size of `u64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -382,13 +358,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. +error[E0277]: `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:91:40 | LL | assert::is_transmutable::< i16, i64>(); - | ^^^ `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | ^^^ The size of `i16` is smaller than the size of `i64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -398,13 +373,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. +error[E0277]: `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:92:40 | LL | assert::is_transmutable::< i16, f64>(); - | ^^^ `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | ^^^ The size of `i16` is smaller than the size of `f64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -414,13 +388,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:93:39 | LL | assert::is_transmutable::< i16, u128>(); - | ^^^^ `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `i16` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -430,13 +403,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:94:39 | LL | assert::is_transmutable::< i16, i128>(); - | ^^^^ `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `i16` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -446,13 +418,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. +error[E0277]: `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:96:40 | LL | assert::is_transmutable::< u16, i32>(); - | ^^^ `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. + | ^^^ The size of `u16` is smaller than the size of `i32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -462,13 +433,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. +error[E0277]: `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:97:40 | LL | assert::is_transmutable::< u16, f32>(); - | ^^^ `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. + | ^^^ The size of `u16` is smaller than the size of `f32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -478,13 +448,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. +error[E0277]: `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context` --> $DIR/numbers.rs:98:40 | LL | assert::is_transmutable::< u16, u32>(); - | ^^^ `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. + | ^^^ The size of `u16` is smaller than the size of `u32` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -494,13 +463,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. +error[E0277]: `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:99:40 | LL | assert::is_transmutable::< u16, u64>(); - | ^^^ `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | ^^^ The size of `u16` is smaller than the size of `u64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -510,13 +478,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. +error[E0277]: `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:100:40 | LL | assert::is_transmutable::< u16, i64>(); - | ^^^ `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | ^^^ The size of `u16` is smaller than the size of `i64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -526,13 +493,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. +error[E0277]: `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:101:40 | LL | assert::is_transmutable::< u16, f64>(); - | ^^^ `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | ^^^ The size of `u16` is smaller than the size of `f64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -542,13 +508,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:102:39 | LL | assert::is_transmutable::< u16, u128>(); - | ^^^^ `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `u16` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -558,13 +523,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:103:39 | LL | assert::is_transmutable::< u16, i128>(); - | ^^^^ `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `u16` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -574,13 +538,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. +error[E0277]: `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:105:40 | LL | assert::is_transmutable::< i32, u64>(); - | ^^^ `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | ^^^ The size of `i32` is smaller than the size of `u64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -590,13 +553,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. +error[E0277]: `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:106:40 | LL | assert::is_transmutable::< i32, i64>(); - | ^^^ `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | ^^^ The size of `i32` is smaller than the size of `i64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -606,13 +568,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. +error[E0277]: `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:107:40 | LL | assert::is_transmutable::< i32, f64>(); - | ^^^ `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | ^^^ The size of `i32` is smaller than the size of `f64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -622,13 +583,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:108:39 | LL | assert::is_transmutable::< i32, u128>(); - | ^^^^ `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `i32` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -638,13 +598,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:109:39 | LL | assert::is_transmutable::< i32, i128>(); - | ^^^^ `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `i32` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -654,13 +613,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. +error[E0277]: `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:111:40 | LL | assert::is_transmutable::< f32, u64>(); - | ^^^ `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | ^^^ The size of `f32` is smaller than the size of `u64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -670,13 +628,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. +error[E0277]: `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:112:40 | LL | assert::is_transmutable::< f32, i64>(); - | ^^^ `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | ^^^ The size of `f32` is smaller than the size of `i64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -686,13 +643,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. +error[E0277]: `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:113:40 | LL | assert::is_transmutable::< f32, f64>(); - | ^^^ `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | ^^^ The size of `f32` is smaller than the size of `f64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -702,13 +658,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:114:39 | LL | assert::is_transmutable::< f32, u128>(); - | ^^^^ `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `f32` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -718,13 +673,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:115:39 | LL | assert::is_transmutable::< f32, i128>(); - | ^^^^ `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `f32` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -734,13 +688,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. +error[E0277]: `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:117:40 | LL | assert::is_transmutable::< u32, u64>(); - | ^^^ `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. + | ^^^ The size of `u32` is smaller than the size of `u64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -750,13 +703,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. +error[E0277]: `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:118:40 | LL | assert::is_transmutable::< u32, i64>(); - | ^^^ `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. + | ^^^ The size of `u32` is smaller than the size of `i64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -766,13 +718,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. +error[E0277]: `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context` --> $DIR/numbers.rs:119:40 | LL | assert::is_transmutable::< u32, f64>(); - | ^^^ `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. + | ^^^ The size of `u32` is smaller than the size of `f64` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -782,13 +733,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:120:39 | LL | assert::is_transmutable::< u32, u128>(); - | ^^^^ `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `u32` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -798,13 +748,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:121:39 | LL | assert::is_transmutable::< u32, i128>(); - | ^^^^ `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `u32` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -814,13 +763,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:123:39 | LL | assert::is_transmutable::< u64, u128>(); - | ^^^^ `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `u64` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -830,13 +778,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:124:39 | LL | assert::is_transmutable::< u64, i128>(); - | ^^^^ `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `u64` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -846,13 +793,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:126:39 | LL | assert::is_transmutable::< i64, u128>(); - | ^^^^ `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `i64` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -862,13 +808,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:127:39 | LL | assert::is_transmutable::< i64, i128>(); - | ^^^^ `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `i64` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -878,13 +823,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. +error[E0277]: `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:129:39 | LL | assert::is_transmutable::< f64, u128>(); - | ^^^^ `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. + | ^^^^ The size of `f64` is smaller than the size of `u128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | @@ -894,13 +838,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. +error[E0277]: `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context` --> $DIR/numbers.rs:130:39 | LL | assert::is_transmutable::< f64, i128>(); - | ^^^^ `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. + | ^^^^ The size of `f64` is smaller than the size of `i128` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:15:14 | diff --git a/tests/ui/transmutability/primitives/unit.current.stderr b/tests/ui/transmutability/primitives/unit.current.stderr index c20355e16f5f..c49eb6097bd0 100644 --- a/tests/ui/transmutability/primitives/unit.current.stderr +++ b/tests/ui/transmutability/primitives/unit.current.stderr @@ -1,10 +1,9 @@ -error[E0277]: `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`. +error[E0277]: `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context` --> $DIR/unit.rs:31:35 | LL | assert::is_transmutable::<(), u8, Context>(); - | ^^ `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`. + | ^^ The size of `()` is smaller than the size of `u8` | - = help: the trait `BikeshedIntrinsicFrom<(), should_have_correct_size::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `u8` note: required by a bound in `is_transmutable` --> $DIR/unit.rs:15:14 | diff --git a/tests/ui/transmutability/primitives/unit.next.stderr b/tests/ui/transmutability/primitives/unit.next.stderr index c20355e16f5f..c49eb6097bd0 100644 --- a/tests/ui/transmutability/primitives/unit.next.stderr +++ b/tests/ui/transmutability/primitives/unit.next.stderr @@ -1,10 +1,9 @@ -error[E0277]: `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`. +error[E0277]: `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context` --> $DIR/unit.rs:31:35 | LL | assert::is_transmutable::<(), u8, Context>(); - | ^^ `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`. + | ^^ The size of `()` is smaller than the size of `u8` | - = help: the trait `BikeshedIntrinsicFrom<(), should_have_correct_size::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `u8` note: required by a bound in `is_transmutable` --> $DIR/unit.rs:15:14 | diff --git a/tests/ui/transmutability/references.current.stderr b/tests/ui/transmutability/references.current.stderr index 39d42cc4fa6c..ecb095354a51 100644 --- a/tests/ui/transmutability/references.current.stderr +++ b/tests/ui/transmutability/references.current.stderr @@ -1,10 +1,9 @@ -error[E0277]: `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`. +error[E0277]: `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context` --> $DIR/references.rs:29:52 | LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); - | ^^^^^^^^^^^^^ `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`. + | ^^^^^^^^^^^^^ `&'static Unit` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom<&'static Unit, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `&'static Unit` note: required by a bound in `is_maybe_transmutable` --> $DIR/references.rs:16:14 | diff --git a/tests/ui/transmutability/references.next.stderr b/tests/ui/transmutability/references.next.stderr index 39d42cc4fa6c..ecb095354a51 100644 --- a/tests/ui/transmutability/references.next.stderr +++ b/tests/ui/transmutability/references.next.stderr @@ -1,10 +1,9 @@ -error[E0277]: `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`. +error[E0277]: `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context` --> $DIR/references.rs:29:52 | LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); - | ^^^^^^^^^^^^^ `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`. + | ^^^^^^^^^^^^^ `&'static Unit` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom<&'static Unit, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `&'static Unit` note: required by a bound in `is_maybe_transmutable` --> $DIR/references.rs:16:14 | diff --git a/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr b/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr index d9aebac6417b..4c5062cd3b30 100644 --- a/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr +++ b/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr @@ -1,10 +1,9 @@ -error[E0277]: `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. +error[E0277]: `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:28:52 | LL | assert::is_maybe_transmutable::(); - | ^^ `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. + | ^^ `should_reject_repr_rust::unit::repr_rust` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -21,13 +20,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` in the defining scope of `assert::Context`. +error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:29:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` in the defining scope of `assert::Context`. + | ^^^^^^^^^ `should_reject_repr_rust::unit::repr_rust` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::unit::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -44,13 +42,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. +error[E0277]: `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:34:52 | LL | assert::is_maybe_transmutable::(); - | ^^ `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. + | ^^ `should_reject_repr_rust::tuple::repr_rust` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -67,13 +64,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` in the defining scope of `assert::Context`. +error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:35:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` in the defining scope of `assert::Context`. + | ^^^^^^^^^ `should_reject_repr_rust::tuple::repr_rust` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::tuple::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -90,13 +86,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. +error[E0277]: `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:40:52 | LL | assert::is_maybe_transmutable::(); - | ^^ `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. + | ^^ `should_reject_repr_rust::braces::repr_rust` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -113,13 +108,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` in the defining scope of `assert::Context`. +error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:41:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` in the defining scope of `assert::Context`. + | ^^^^^^^^^ `should_reject_repr_rust::braces::repr_rust` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::braces::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -136,13 +130,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `aligned::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. +error[E0277]: `aligned::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:46:52 | LL | assert::is_maybe_transmutable::(); - | ^^ `aligned::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. + | ^^ `aligned::repr_rust` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -159,13 +152,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `u128` cannot be safely transmuted into `aligned::repr_rust` in the defining scope of `assert::Context`. +error[E0277]: `u128` cannot be safely transmuted into `aligned::repr_rust` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:47:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ `u128` cannot be safely transmuted into `aligned::repr_rust` in the defining scope of `assert::Context`. + | ^^^^^^^^^ `aligned::repr_rust` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `aligned::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -182,13 +174,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `packed::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. +error[E0277]: `packed::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:52:52 | LL | assert::is_maybe_transmutable::(); - | ^^ `packed::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. + | ^^ `packed::repr_rust` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -205,13 +196,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `u128` cannot be safely transmuted into `packed::repr_rust` in the defining scope of `assert::Context`. +error[E0277]: `u128` cannot be safely transmuted into `packed::repr_rust` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:53:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ `u128` cannot be safely transmuted into `packed::repr_rust` in the defining scope of `assert::Context`. + | ^^^^^^^^^ `packed::repr_rust` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `packed::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -228,13 +218,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `nested::repr_c` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. +error[E0277]: `nested::repr_c` cannot be safely transmuted into `()` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:59:49 | LL | assert::is_maybe_transmutable::(); - | ^^ `nested::repr_c` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. + | ^^ `nested::repr_c` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -251,13 +240,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `u128` cannot be safely transmuted into `nested::repr_c` in the defining scope of `assert::Context`. +error[E0277]: `u128` cannot be safely transmuted into `nested::repr_c` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:60:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^ `u128` cannot be safely transmuted into `nested::repr_c` in the defining scope of `assert::Context`. + | ^^^^^^ `nested::repr_c` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `nested::repr_c` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | diff --git a/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr b/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr index aa0cbc51b1b2..4293d34f47b2 100644 --- a/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr +++ b/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr @@ -1,10 +1,9 @@ -error[E0277]: `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. +error[E0277]: `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:30:48 | LL | assert::is_maybe_transmutable::(); - | ^^ `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. + | ^^ `should_reject_repr_rust::repr_rust` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -21,13 +20,12 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` in the defining scope of `assert::Context`. +error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` in the defining scope of `assert::Context` --> $DIR/should_require_well_defined_layout.rs:31:43 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` in the defining scope of `assert::Context`. + | ^^^^^^^^^ `should_reject_repr_rust::repr_rust` does not have a well-specified layout | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | diff --git a/tests/ui/transmutability/unions/should_pad_variants.stderr b/tests/ui/transmutability/unions/should_pad_variants.stderr index f4988239df94..bfbef8b25fcf 100644 --- a/tests/ui/transmutability/unions/should_pad_variants.stderr +++ b/tests/ui/transmutability/unions/should_pad_variants.stderr @@ -1,10 +1,9 @@ -error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`. +error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context` --> $DIR/should_pad_variants.rs:44:36 | LL | assert::is_transmutable::(); - | ^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`. + | ^^^ The size of `Src` is smaller than the size of `Dst` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` note: required by a bound in `is_transmutable` --> $DIR/should_pad_variants.rs:13:14 | diff --git a/tests/ui/transmutability/unions/should_reject_contraction.stderr b/tests/ui/transmutability/unions/should_reject_contraction.stderr index fa7dcc3d22a9..553f655a10ac 100644 --- a/tests/ui/transmutability/unions/should_reject_contraction.stderr +++ b/tests/ui/transmutability/unions/should_reject_contraction.stderr @@ -1,10 +1,9 @@ -error[E0277]: `Superset` cannot be safely transmuted into `Subset` in the defining scope of `assert::Context`. +error[E0277]: `Superset` cannot be safely transmuted into `Subset` in the defining scope of `assert::Context` --> $DIR/should_reject_contraction.rs:35:41 | LL | assert::is_transmutable::(); - | ^^^^^^ `Superset` cannot be safely transmuted into `Subset` in the defining scope of `assert::Context`. + | ^^^^^^ At least one value of `Superset` isn't a bit-valid value of `Subset` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Subset` note: required by a bound in `is_transmutable` --> $DIR/should_reject_contraction.rs:13:14 | diff --git a/tests/ui/transmutability/unions/should_reject_disjoint.stderr b/tests/ui/transmutability/unions/should_reject_disjoint.stderr index 880e4cd89403..178ae6f08c49 100644 --- a/tests/ui/transmutability/unions/should_reject_disjoint.stderr +++ b/tests/ui/transmutability/unions/should_reject_disjoint.stderr @@ -1,10 +1,9 @@ -error[E0277]: `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`. +error[E0277]: `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context` --> $DIR/should_reject_disjoint.rs:33:40 | LL | assert::is_maybe_transmutable::(); - | ^ `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`. + | ^ At least one value of `A` isn't a bit-valid value of `B` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `B` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_reject_disjoint.rs:13:14 | @@ -14,13 +13,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`. +error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context` --> $DIR/should_reject_disjoint.rs:34:40 | LL | assert::is_maybe_transmutable::(); - | ^ `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`. + | ^ At least one value of `B` isn't a bit-valid value of `A` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `A` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_reject_disjoint.rs:13:14 | diff --git a/tests/ui/transmutability/unions/should_reject_intersecting.stderr b/tests/ui/transmutability/unions/should_reject_intersecting.stderr index 501760b08096..73c29ab1c970 100644 --- a/tests/ui/transmutability/unions/should_reject_intersecting.stderr +++ b/tests/ui/transmutability/unions/should_reject_intersecting.stderr @@ -1,10 +1,9 @@ -error[E0277]: `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`. +error[E0277]: `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context` --> $DIR/should_reject_intersecting.rs:36:34 | LL | assert::is_transmutable::(); - | ^ `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`. + | ^ At least one value of `A` isn't a bit-valid value of `B` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `B` note: required by a bound in `is_transmutable` --> $DIR/should_reject_intersecting.rs:14:14 | @@ -14,13 +13,12 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`. +error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context` --> $DIR/should_reject_intersecting.rs:37:34 | LL | assert::is_transmutable::(); - | ^ `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`. + | ^ At least one value of `B` isn't a bit-valid value of `A` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `A` note: required by a bound in `is_transmutable` --> $DIR/should_reject_intersecting.rs:14:14 | diff --git a/tests/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr b/tests/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr index afbba653b834..863ada3c2c44 100644 --- a/tests/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr +++ b/tests/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr @@ -1,10 +1,9 @@ -error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. +error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context` --> $DIR/should_reject_if_dst_has_private_field.rs:35:41 | LL | assert::is_transmutable::(); - | ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. + | ^^^^^^^^ `Dst` is or contains a type or field that is not visible in that scope | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` note: required by a bound in `is_transmutable` --> $DIR/should_reject_if_dst_has_private_field.rs:13:14 | diff --git a/tests/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr b/tests/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr index f14b5d8b2cb5..7b0f1b4d56ec 100644 --- a/tests/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr +++ b/tests/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr @@ -1,10 +1,9 @@ -error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. +error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context` --> $DIR/should_reject_if_dst_has_private_variant.rs:36:41 | LL | assert::is_transmutable::(); - | ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. + | ^^^^^^^^ `Dst` is or contains a type or field that is not visible in that scope | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` note: required by a bound in `is_transmutable` --> $DIR/should_reject_if_dst_has_private_variant.rs:13:14 | diff --git a/tests/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr b/tests/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr index 01ae8bea2561..df19477ef269 100644 --- a/tests/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr +++ b/tests/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr @@ -1,10 +1,9 @@ -error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. +error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context` --> $DIR/should_reject_if_dst_has_unreachable_field.rs:37:41 | LL | assert::is_transmutable::(); - | ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. + | ^^^^^^^^ `Dst` is or contains a type or field that is not visible in that scope | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` note: required by a bound in `is_transmutable` --> $DIR/should_reject_if_dst_has_unreachable_field.rs:15:14 | diff --git a/tests/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr b/tests/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr index 20a680a74845..ea488980cdd1 100644 --- a/tests/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr +++ b/tests/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr @@ -10,13 +10,12 @@ note: the struct `Dst` is defined here LL | #[repr(C)] pub(self) struct Dst { | ^^^^^^^^^^^^^^^^^^^^ -error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. +error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context` --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:38:41 | LL | assert::is_transmutable::(); - | ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. + | ^^^^^^^^ `Dst` is or contains a type or field that is not visible in that scope | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` note: required by a bound in `is_transmutable` --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:15:14 | diff --git a/tests/ui/transmute/transmute-padding-ice.stderr b/tests/ui/transmute/transmute-padding-ice.stderr index 87fd4fb66308..f5480e0b9fb8 100644 --- a/tests/ui/transmute/transmute-padding-ice.stderr +++ b/tests/ui/transmute/transmute-padding-ice.stderr @@ -1,10 +1,9 @@ -error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`. +error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context` --> $DIR/transmute-padding-ice.rs:27:40 | LL | assert::is_maybe_transmutable::(); - | ^ `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`. + | ^ The size of `B` is smaller than the size of `A` | - = help: the trait `BikeshedIntrinsicFrom` is not implemented for `A` note: required by a bound in `is_maybe_transmutable` --> $DIR/transmute-padding-ice.rs:11:14 | From 8d5ee1a0729b91545e856dbf14fd75687dc9e2b8 Mon Sep 17 00:00:00 2001 From: Kyle Matsuda Date: Thu, 13 Apr 2023 16:43:34 -0600 Subject: [PATCH 262/272] make impl_subject more readable --- compiler/rustc_middle/src/hir/mod.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 50a3067c5595..7770a5e47641 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -105,12 +105,10 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn impl_subject(self, def_id: DefId) -> EarlyBinder> { - EarlyBinder( - self.impl_trait_ref(def_id) - .map(|t| t.subst_identity()) - .map(ImplSubject::Trait) - .unwrap_or_else(|| ImplSubject::Inherent(self.type_of(def_id).subst_identity())), - ) + match self.impl_trait_ref(def_id) { + Some(t) => t.map_bound(ImplSubject::Trait), + None => self.type_of(def_id).map_bound(ImplSubject::Inherent), + } } } From 7dbd2e2370897c8363f4b17eb87a3a376811deaa Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 13 Apr 2023 12:31:40 +1000 Subject: [PATCH 263/272] Remove one use of `BrAnon(Some(_))`. --- compiler/rustc_hir_typeck/src/generator_interior/mod.rs | 2 +- tests/ui/generic-associated-types/bugs/issue-100013.stderr | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 161db618b6fe..0a9992c9557e 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -258,7 +258,7 @@ pub fn resolve_interior<'a, 'tcx>( } // FIXME: these should use `BrNamed` ty::ReEarlyBound(region) => { - mk_bound_region(ty::BrAnon(Some(fcx.tcx.def_span(region.def_id)))) + mk_bound_region(ty::BrNamed(region.def_id, region.name)) } ty::ReLateBound(_, ty::BoundRegion { kind, .. }) | ty::ReFree(ty::FreeRegion { bound_region: kind, .. }) => match kind { diff --git a/tests/ui/generic-associated-types/bugs/issue-100013.stderr b/tests/ui/generic-associated-types/bugs/issue-100013.stderr index 9db124a81e48..c023e743e837 100644 --- a/tests/ui/generic-associated-types/bugs/issue-100013.stderr +++ b/tests/ui/generic-associated-types/bugs/issue-100013.stderr @@ -62,12 +62,12 @@ LL | | async {}.await; // a yield point LL | | } | |_____^ | -note: the lifetime defined here... +note: the lifetime `'b` defined here... --> $DIR/issue-100013.rs:28:18 | LL | fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send { | ^^ -note: ...must outlive the lifetime defined here +note: ...must outlive the lifetime `'a` defined here --> $DIR/issue-100013.rs:28:10 | LL | fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send { From f07c335e90d2705f2db5a18f0b912a08652610f5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 13 Apr 2023 12:41:12 +1000 Subject: [PATCH 264/272] Remove another use of `BrAnon(Some(_))`. --- compiler/rustc_hir_typeck/src/generator_interior/mod.rs | 5 ++--- tests/ui/generic-associated-types/bugs/issue-100013.stderr | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 0a9992c9557e..f39710804433 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -256,15 +256,14 @@ pub fn resolve_interior<'a, 'tcx>( _ => mk_bound_region(ty::BrAnon(None)), } } - // FIXME: these should use `BrNamed` ty::ReEarlyBound(region) => { mk_bound_region(ty::BrNamed(region.def_id, region.name)) } ty::ReLateBound(_, ty::BoundRegion { kind, .. }) | ty::ReFree(ty::FreeRegion { bound_region: kind, .. }) => match kind { ty::BoundRegionKind::BrAnon(span) => mk_bound_region(ty::BrAnon(span)), - ty::BoundRegionKind::BrNamed(def_id, _) => { - mk_bound_region(ty::BrAnon(Some(fcx.tcx.def_span(def_id)))) + ty::BoundRegionKind::BrNamed(def_id, sym) => { + mk_bound_region(ty::BrNamed(def_id, sym)) } ty::BoundRegionKind::BrEnv => mk_bound_region(ty::BrAnon(None)), }, diff --git a/tests/ui/generic-associated-types/bugs/issue-100013.stderr b/tests/ui/generic-associated-types/bugs/issue-100013.stderr index c023e743e837..86dbad84d99d 100644 --- a/tests/ui/generic-associated-types/bugs/issue-100013.stderr +++ b/tests/ui/generic-associated-types/bugs/issue-100013.stderr @@ -28,12 +28,12 @@ LL | | async {}.await; // a yield point LL | | } | |_____^ | -note: the lifetime defined here... +note: the lifetime `'b` defined here... --> $DIR/issue-100013.rs:21:14 | LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send { | ^^ -note: ...must outlive the lifetime defined here +note: ...must outlive the lifetime `'a` defined here --> $DIR/issue-100013.rs:21:10 | LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send { From 2ffb0de8cfda57cafdfd71a690f14c2e17216d85 Mon Sep 17 00:00:00 2001 From: jyn Date: Sun, 2 Apr 2023 18:09:11 -0400 Subject: [PATCH 265/272] Move most ui-fulldeps tests to ui They pass fine. Only tests that required `extern crate rustc_*` or were marked `ignore-stage1` have been keep in fulldeps. --- src/tools/tidy/src/ui_tests.rs | 2 +- tests/{ui-fulldeps => ui}/auxiliary/issue-13560-1.rs | 0 tests/{ui-fulldeps => ui}/auxiliary/issue-13560-2.rs | 0 tests/{ui-fulldeps => ui}/auxiliary/issue-13560-3.rs | 0 tests/{ui-fulldeps => ui}/auxiliary/issue-16822.rs | 0 tests/{ui-fulldeps => ui}/auxiliary/issue-18502.rs | 0 tests/{ui-fulldeps => ui}/auxiliary/issue-24106.rs | 0 tests/{ui-fulldeps => ui}/extern-mod-syntax.rs | 0 .../{ui-fulldeps => ui}/internal-lints/diagnostics_incorrect.rs | 0 .../internal-lints/diagnostics_incorrect.stderr | 0 .../{ui-fulldeps => ui}/internal-lints/existing_doc_keyword.rs | 0 .../internal-lints/existing_doc_keyword.stderr | 0 .../internal-lints/query_stability_incorrect.rs | 0 .../internal-lints/query_stability_incorrect.stderr | 0 .../internal-lints/rustc_pass_by_value_self.rs | 0 .../internal-lints/rustc_pass_by_value_self.stderr | 0 tests/{ui-fulldeps => ui}/issue-11881.rs | 0 tests/{ui-fulldeps => ui}/issue-13560.rs | 0 tests/{ui-fulldeps => ui}/issue-15924.rs | 0 tests/{ui-fulldeps => ui}/issue-16822.rs | 0 tests/{ui-fulldeps => ui}/issue-18502.rs | 0 tests/{ui-fulldeps => ui}/issue-24106.rs | 0 tests/{ui-fulldeps => ui}/issue-2804.rs | 0 tests/{ui-fulldeps => ui}/myriad-closures.rs | 0 tests/{ui-fulldeps => ui}/std/issue-15149.rs | 0 .../{ui-fulldeps => ui}/std/issue-81357-unsound-file-methods.rs | 0 tests/{ui-fulldeps => ui}/std/stdio-from.rs | 0 tests/{ui-fulldeps => ui}/std/switch-stdout.rs | 0 28 files changed, 1 insertion(+), 1 deletion(-) rename tests/{ui-fulldeps => ui}/auxiliary/issue-13560-1.rs (100%) rename tests/{ui-fulldeps => ui}/auxiliary/issue-13560-2.rs (100%) rename tests/{ui-fulldeps => ui}/auxiliary/issue-13560-3.rs (100%) rename tests/{ui-fulldeps => ui}/auxiliary/issue-16822.rs (100%) rename tests/{ui-fulldeps => ui}/auxiliary/issue-18502.rs (100%) rename tests/{ui-fulldeps => ui}/auxiliary/issue-24106.rs (100%) rename tests/{ui-fulldeps => ui}/extern-mod-syntax.rs (100%) rename tests/{ui-fulldeps => ui}/internal-lints/diagnostics_incorrect.rs (100%) rename tests/{ui-fulldeps => ui}/internal-lints/diagnostics_incorrect.stderr (100%) rename tests/{ui-fulldeps => ui}/internal-lints/existing_doc_keyword.rs (100%) rename tests/{ui-fulldeps => ui}/internal-lints/existing_doc_keyword.stderr (100%) rename tests/{ui-fulldeps => ui}/internal-lints/query_stability_incorrect.rs (100%) rename tests/{ui-fulldeps => ui}/internal-lints/query_stability_incorrect.stderr (100%) rename tests/{ui-fulldeps => ui}/internal-lints/rustc_pass_by_value_self.rs (100%) rename tests/{ui-fulldeps => ui}/internal-lints/rustc_pass_by_value_self.stderr (100%) rename tests/{ui-fulldeps => ui}/issue-11881.rs (100%) rename tests/{ui-fulldeps => ui}/issue-13560.rs (100%) rename tests/{ui-fulldeps => ui}/issue-15924.rs (100%) rename tests/{ui-fulldeps => ui}/issue-16822.rs (100%) rename tests/{ui-fulldeps => ui}/issue-18502.rs (100%) rename tests/{ui-fulldeps => ui}/issue-24106.rs (100%) rename tests/{ui-fulldeps => ui}/issue-2804.rs (100%) rename tests/{ui-fulldeps => ui}/myriad-closures.rs (100%) rename tests/{ui-fulldeps => ui}/std/issue-15149.rs (100%) rename tests/{ui-fulldeps => ui}/std/issue-81357-unsound-file-methods.rs (100%) rename tests/{ui-fulldeps => ui}/std/stdio-from.rs (100%) rename tests/{ui-fulldeps => ui}/std/switch-stdout.rs (100%) diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 7b7ee62a2474..3d7f9828a7eb 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -9,7 +9,7 @@ use std::path::{Path, PathBuf}; // FIXME: The following limits should be reduced eventually. const ENTRY_LIMIT: usize = 885; -const ROOT_ENTRY_LIMIT: usize = 880; +const ROOT_ENTRY_LIMIT: usize = 891; const ISSUES_ENTRY_LIMIT: usize = 1978; fn check_entries(tests_path: &Path, bad: &mut bool) { diff --git a/tests/ui-fulldeps/auxiliary/issue-13560-1.rs b/tests/ui/auxiliary/issue-13560-1.rs similarity index 100% rename from tests/ui-fulldeps/auxiliary/issue-13560-1.rs rename to tests/ui/auxiliary/issue-13560-1.rs diff --git a/tests/ui-fulldeps/auxiliary/issue-13560-2.rs b/tests/ui/auxiliary/issue-13560-2.rs similarity index 100% rename from tests/ui-fulldeps/auxiliary/issue-13560-2.rs rename to tests/ui/auxiliary/issue-13560-2.rs diff --git a/tests/ui-fulldeps/auxiliary/issue-13560-3.rs b/tests/ui/auxiliary/issue-13560-3.rs similarity index 100% rename from tests/ui-fulldeps/auxiliary/issue-13560-3.rs rename to tests/ui/auxiliary/issue-13560-3.rs diff --git a/tests/ui-fulldeps/auxiliary/issue-16822.rs b/tests/ui/auxiliary/issue-16822.rs similarity index 100% rename from tests/ui-fulldeps/auxiliary/issue-16822.rs rename to tests/ui/auxiliary/issue-16822.rs diff --git a/tests/ui-fulldeps/auxiliary/issue-18502.rs b/tests/ui/auxiliary/issue-18502.rs similarity index 100% rename from tests/ui-fulldeps/auxiliary/issue-18502.rs rename to tests/ui/auxiliary/issue-18502.rs diff --git a/tests/ui-fulldeps/auxiliary/issue-24106.rs b/tests/ui/auxiliary/issue-24106.rs similarity index 100% rename from tests/ui-fulldeps/auxiliary/issue-24106.rs rename to tests/ui/auxiliary/issue-24106.rs diff --git a/tests/ui-fulldeps/extern-mod-syntax.rs b/tests/ui/extern-mod-syntax.rs similarity index 100% rename from tests/ui-fulldeps/extern-mod-syntax.rs rename to tests/ui/extern-mod-syntax.rs diff --git a/tests/ui-fulldeps/internal-lints/diagnostics_incorrect.rs b/tests/ui/internal-lints/diagnostics_incorrect.rs similarity index 100% rename from tests/ui-fulldeps/internal-lints/diagnostics_incorrect.rs rename to tests/ui/internal-lints/diagnostics_incorrect.rs diff --git a/tests/ui-fulldeps/internal-lints/diagnostics_incorrect.stderr b/tests/ui/internal-lints/diagnostics_incorrect.stderr similarity index 100% rename from tests/ui-fulldeps/internal-lints/diagnostics_incorrect.stderr rename to tests/ui/internal-lints/diagnostics_incorrect.stderr diff --git a/tests/ui-fulldeps/internal-lints/existing_doc_keyword.rs b/tests/ui/internal-lints/existing_doc_keyword.rs similarity index 100% rename from tests/ui-fulldeps/internal-lints/existing_doc_keyword.rs rename to tests/ui/internal-lints/existing_doc_keyword.rs diff --git a/tests/ui-fulldeps/internal-lints/existing_doc_keyword.stderr b/tests/ui/internal-lints/existing_doc_keyword.stderr similarity index 100% rename from tests/ui-fulldeps/internal-lints/existing_doc_keyword.stderr rename to tests/ui/internal-lints/existing_doc_keyword.stderr diff --git a/tests/ui-fulldeps/internal-lints/query_stability_incorrect.rs b/tests/ui/internal-lints/query_stability_incorrect.rs similarity index 100% rename from tests/ui-fulldeps/internal-lints/query_stability_incorrect.rs rename to tests/ui/internal-lints/query_stability_incorrect.rs diff --git a/tests/ui-fulldeps/internal-lints/query_stability_incorrect.stderr b/tests/ui/internal-lints/query_stability_incorrect.stderr similarity index 100% rename from tests/ui-fulldeps/internal-lints/query_stability_incorrect.stderr rename to tests/ui/internal-lints/query_stability_incorrect.stderr diff --git a/tests/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs b/tests/ui/internal-lints/rustc_pass_by_value_self.rs similarity index 100% rename from tests/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs rename to tests/ui/internal-lints/rustc_pass_by_value_self.rs diff --git a/tests/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr b/tests/ui/internal-lints/rustc_pass_by_value_self.stderr similarity index 100% rename from tests/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr rename to tests/ui/internal-lints/rustc_pass_by_value_self.stderr diff --git a/tests/ui-fulldeps/issue-11881.rs b/tests/ui/issue-11881.rs similarity index 100% rename from tests/ui-fulldeps/issue-11881.rs rename to tests/ui/issue-11881.rs diff --git a/tests/ui-fulldeps/issue-13560.rs b/tests/ui/issue-13560.rs similarity index 100% rename from tests/ui-fulldeps/issue-13560.rs rename to tests/ui/issue-13560.rs diff --git a/tests/ui-fulldeps/issue-15924.rs b/tests/ui/issue-15924.rs similarity index 100% rename from tests/ui-fulldeps/issue-15924.rs rename to tests/ui/issue-15924.rs diff --git a/tests/ui-fulldeps/issue-16822.rs b/tests/ui/issue-16822.rs similarity index 100% rename from tests/ui-fulldeps/issue-16822.rs rename to tests/ui/issue-16822.rs diff --git a/tests/ui-fulldeps/issue-18502.rs b/tests/ui/issue-18502.rs similarity index 100% rename from tests/ui-fulldeps/issue-18502.rs rename to tests/ui/issue-18502.rs diff --git a/tests/ui-fulldeps/issue-24106.rs b/tests/ui/issue-24106.rs similarity index 100% rename from tests/ui-fulldeps/issue-24106.rs rename to tests/ui/issue-24106.rs diff --git a/tests/ui-fulldeps/issue-2804.rs b/tests/ui/issue-2804.rs similarity index 100% rename from tests/ui-fulldeps/issue-2804.rs rename to tests/ui/issue-2804.rs diff --git a/tests/ui-fulldeps/myriad-closures.rs b/tests/ui/myriad-closures.rs similarity index 100% rename from tests/ui-fulldeps/myriad-closures.rs rename to tests/ui/myriad-closures.rs diff --git a/tests/ui-fulldeps/std/issue-15149.rs b/tests/ui/std/issue-15149.rs similarity index 100% rename from tests/ui-fulldeps/std/issue-15149.rs rename to tests/ui/std/issue-15149.rs diff --git a/tests/ui-fulldeps/std/issue-81357-unsound-file-methods.rs b/tests/ui/std/issue-81357-unsound-file-methods.rs similarity index 100% rename from tests/ui-fulldeps/std/issue-81357-unsound-file-methods.rs rename to tests/ui/std/issue-81357-unsound-file-methods.rs diff --git a/tests/ui-fulldeps/std/stdio-from.rs b/tests/ui/std/stdio-from.rs similarity index 100% rename from tests/ui-fulldeps/std/stdio-from.rs rename to tests/ui/std/stdio-from.rs diff --git a/tests/ui-fulldeps/std/switch-stdout.rs b/tests/ui/std/switch-stdout.rs similarity index 100% rename from tests/ui-fulldeps/std/switch-stdout.rs rename to tests/ui/std/switch-stdout.rs From 88ee6e5a6c5fad39494d4f5dcbfe026fa7fac621 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 9 Apr 2023 09:11:00 -0500 Subject: [PATCH 266/272] Fix tests on wasm The `std` test straightforwardly can't work without file descriptors; #99417 tracks moving it out of tests/ui. `issue-13560.rs` requires the target to support dynamic linking. `extern-mod-syntax` is interesting. The original test was added to check if `extern mod` could be parsed correctly and used `extern mod std` and an import: https://github.com/rust-lang/rust/commit/138dc3048af36f0a20f857542c357fe8df563013#diff-73700e1e851b7a37bc92174635dab726124c82e5bfabbbc45b4a3c2e8e14fadd At some point `std::json::Object` was moved out of std to an unstable rustc-only `extras` crate, and rather than just changing the import it got changed to use the unstable crate. When `extras` was removed, people assumed the test was meant to also test rustc_private and changed it to another unstable crate rather than using something in std. This changes the test to remove the `rustc_private` import, to allow it to work properly when cross-compiling. --- tests/ui/extern-mod-syntax.rs | 8 ++++---- tests/ui/issue-13560.rs | 1 + tests/ui/std/switch-stdout.rs | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/ui/extern-mod-syntax.rs b/tests/ui/extern-mod-syntax.rs index 230194c53779..65dfa6a0f579 100644 --- a/tests/ui/extern-mod-syntax.rs +++ b/tests/ui/extern-mod-syntax.rs @@ -1,11 +1,11 @@ // run-pass #![allow(unused_imports)] -#![feature(rustc_private)] +#![no_std] -extern crate libc; -use libc::c_void; +extern crate std; +use std::ffi::c_void; pub fn main() { - println!("Hello world!"); + std::println!("Hello world!"); } diff --git a/tests/ui/issue-13560.rs b/tests/ui/issue-13560.rs index 5f7d647e2301..3397202bef2f 100644 --- a/tests/ui/issue-13560.rs +++ b/tests/ui/issue-13560.rs @@ -1,4 +1,5 @@ // run-pass +// ignore-cross-compile (needs dylibs and compiletest doesn't have a more specific header) // aux-build:issue-13560-1.rs // aux-build:issue-13560-2.rs // aux-build:issue-13560-3.rs diff --git a/tests/ui/std/switch-stdout.rs b/tests/ui/std/switch-stdout.rs index e9501a809308..2d936d96b059 100644 --- a/tests/ui/std/switch-stdout.rs +++ b/tests/ui/std/switch-stdout.rs @@ -1,4 +1,5 @@ // run-pass +// ignore-wasm (needs file descriptors and env variables) use std::env; use std::fs::File; From b335c2d49f1698ada99e3622d3cd482c27c9fc9b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 11 Apr 2023 21:15:39 +0000 Subject: [PATCH 267/272] Assemble Unpin candidates specially for generators in new solver --- .../src/solve/trait_goals.rs | 19 ++++++++++++++++++- tests/ui/generator/non-static-is-unpin.rs | 2 ++ ...stderr => static-not-unpin.current.stderr} | 8 ++++---- .../ui/generator/static-not-unpin.next.stderr | 19 +++++++++++++++++++ tests/ui/generator/static-not-unpin.rs | 3 +++ 5 files changed, 46 insertions(+), 5 deletions(-) rename tests/ui/generator/{static-not-unpin.stderr => static-not-unpin.current.stderr} (71%) create mode 100644 tests/ui/generator/static-not-unpin.next.stderr diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 716d5acb324a..73c599e18140 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -3,7 +3,7 @@ use super::assembly::{self, structural_traits}; use super::{EvalCtxt, SolverMode}; use rustc_hir::def_id::DefId; -use rustc_hir::LangItem; +use rustc_hir::{LangItem, Movability}; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::util::supertraits; use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult}; @@ -168,6 +168,23 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"), + // Generators have one special built-in candidate, `Unpin`, which + // takes precedence over the structural auto trait candidate being + // assembled. + ty::Generator(_, _, movability) + if Some(goal.predicate.def_id()) == ecx.tcx().lang_items().unpin_trait() => + { + match movability { + Movability::Static => { + return Err(NoSolution); + } + Movability::Movable => { + return ecx + .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); + } + } + } + // For rigid types, we only register a builtin auto implementation // if there is no implementation that could ever apply to the self // type. diff --git a/tests/ui/generator/non-static-is-unpin.rs b/tests/ui/generator/non-static-is-unpin.rs index 96d0a8e28337..17e23f5bcd2f 100644 --- a/tests/ui/generator/non-static-is-unpin.rs +++ b/tests/ui/generator/non-static-is-unpin.rs @@ -1,3 +1,5 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next // run-pass #![feature(generators, generator_trait)] diff --git a/tests/ui/generator/static-not-unpin.stderr b/tests/ui/generator/static-not-unpin.current.stderr similarity index 71% rename from tests/ui/generator/static-not-unpin.stderr rename to tests/ui/generator/static-not-unpin.current.stderr index 7376116b3380..ecd8ca60c6f2 100644 --- a/tests/ui/generator/static-not-unpin.stderr +++ b/tests/ui/generator/static-not-unpin.current.stderr @@ -1,15 +1,15 @@ -error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 11:34]` cannot be unpinned - --> $DIR/static-not-unpin.rs:14:18 +error[E0277]: `[static generator@$DIR/static-not-unpin.rs:14:25: 14:34]` cannot be unpinned + --> $DIR/static-not-unpin.rs:17:18 | LL | assert_unpin(generator); - | ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 11:34]` + | ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:14:25: 14:34]` | | | required by a bound introduced by this call | = note: consider using the `pin!` macro consider using `Box::pin` if you need to access the pinned value outside of the current scope note: required by a bound in `assert_unpin` - --> $DIR/static-not-unpin.rs:7:20 + --> $DIR/static-not-unpin.rs:10:20 | LL | fn assert_unpin(_: T) { | ^^^^^ required by this bound in `assert_unpin` diff --git a/tests/ui/generator/static-not-unpin.next.stderr b/tests/ui/generator/static-not-unpin.next.stderr new file mode 100644 index 000000000000..ecd8ca60c6f2 --- /dev/null +++ b/tests/ui/generator/static-not-unpin.next.stderr @@ -0,0 +1,19 @@ +error[E0277]: `[static generator@$DIR/static-not-unpin.rs:14:25: 14:34]` cannot be unpinned + --> $DIR/static-not-unpin.rs:17:18 + | +LL | assert_unpin(generator); + | ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:14:25: 14:34]` + | | + | required by a bound introduced by this call + | + = note: consider using the `pin!` macro + consider using `Box::pin` if you need to access the pinned value outside of the current scope +note: required by a bound in `assert_unpin` + --> $DIR/static-not-unpin.rs:10:20 + | +LL | fn assert_unpin(_: T) { + | ^^^^^ required by this bound in `assert_unpin` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/generator/static-not-unpin.rs b/tests/ui/generator/static-not-unpin.rs index cfcb94737be6..30d3f2918709 100644 --- a/tests/ui/generator/static-not-unpin.rs +++ b/tests/ui/generator/static-not-unpin.rs @@ -1,3 +1,6 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + #![feature(generators)] // normalize-stderr-test "std::pin::Unpin" -> "std::marker::Unpin" From 319c790600c2f8bfccf112da216e64566a61e5b6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Apr 2023 18:56:19 +0000 Subject: [PATCH 268/272] Move auto trait built-in candidate disqualification to a separate method --- .../src/solve/assembly/mod.rs | 8 + .../src/solve/trait_goals.rs | 170 ++++++++++-------- 2 files changed, 101 insertions(+), 77 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 7f0ceb6646ce..10d817f75ac7 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -348,6 +348,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ) { let lang_items = self.tcx().lang_items(); let trait_def_id = goal.predicate.trait_def_id(self.tcx()); + + // N.B. When assembling built-in candidates for lang items that are also + // `auto` traits, then the auto trait candidate that is assembled in + // `consider_auto_trait_candidate` MUST be disqualified to remain sound. + // + // Instead of adding the logic here, it's a better idea to add it in + // `EvalCtxt::disqualify_auto_trait_candidate_due_to_possible_impl` in + // `solve::trait_goals` instead. let result = if self.tcx().trait_is_auto(trait_def_id) { G::consider_auto_trait_candidate(self, goal) } else if self.tcx().trait_is_alias(trait_def_id) { diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 73c599e18140..abd11a15ac23 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -147,83 +147,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { - let self_ty = goal.predicate.self_ty(); - match *self_ty.kind() { - // Stall int and float vars until they are resolved to a concrete - // numerical type. That's because the check for impls below treats - // int vars as matching any impl. Even if we filtered such impls, - // we probably don't want to treat an `impl !AutoTrait for i32` as - // disqualifying the built-in auto impl for `i64: AutoTrait` either. - ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => { - return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); - } - - // These types cannot be structurally decomposed into constitutent - // types, and therefore have no builtin impl. - ty::Dynamic(..) - | ty::Param(..) - | ty::Foreign(..) - | ty::Alias(ty::Projection, ..) - | ty::Placeholder(..) => return Err(NoSolution), - - ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"), - - // Generators have one special built-in candidate, `Unpin`, which - // takes precedence over the structural auto trait candidate being - // assembled. - ty::Generator(_, _, movability) - if Some(goal.predicate.def_id()) == ecx.tcx().lang_items().unpin_trait() => - { - match movability { - Movability::Static => { - return Err(NoSolution); - } - Movability::Movable => { - return ecx - .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); - } - } - } - - // For rigid types, we only register a builtin auto implementation - // if there is no implementation that could ever apply to the self - // type. - // - // This differs from the current stable behavior and fixes #84857. - // Due to breakage found via crater, we currently instead lint - // patterns which can be used to exploit this unsoundness on stable, - // see #93367 for more details. - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Str - | ty::Array(_, _) - | ty::Slice(_) - | ty::RawPtr(_) - | ty::Ref(_, _, _) - | ty::FnDef(_, _) - | ty::FnPtr(_) - | ty::Closure(_, _) - | ty::Generator(_, _, _) - | ty::GeneratorWitness(_) - | ty::GeneratorWitnessMIR(_, _) - | ty::Never - | ty::Tuple(_) - | ty::Error(_) - | ty::Adt(_, _) - | ty::Alias(ty::Opaque, _) => { - if let Some(def_id) = ecx.tcx().find_map_relevant_impl( - goal.predicate.def_id(), - goal.predicate.self_ty(), - TreatProjections::NextSolverLookup, - Some, - ) { - debug!(?def_id, ?goal, "disqualified auto-trait implementation"); - return Err(NoSolution); - } - } + if let Some(result) = ecx.disqualify_auto_trait_candidate_due_to_possible_impl(goal) { + return result; } ecx.probe_and_evaluate_goal_for_constituent_tys( @@ -647,6 +572,97 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } impl<'tcx> EvalCtxt<'_, 'tcx> { + // Return `Some` if there is an impl (built-in or user provided) that may + // hold for the self type of the goal, which for coherence and soundness + // purposes must disqualify the built-in auto impl assembled by considering + // the type's constituent types. + fn disqualify_auto_trait_candidate_due_to_possible_impl( + &mut self, + goal: Goal<'tcx, TraitPredicate<'tcx>>, + ) -> Option> { + let self_ty = goal.predicate.self_ty(); + match *self_ty.kind() { + // Stall int and float vars until they are resolved to a concrete + // numerical type. That's because the check for impls below treats + // int vars as matching any impl. Even if we filtered such impls, + // we probably don't want to treat an `impl !AutoTrait for i32` as + // disqualifying the built-in auto impl for `i64: AutoTrait` either. + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => { + Some(self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)) + } + + // These types cannot be structurally decomposed into constitutent + // types, and therefore have no built-in auto impl. + ty::Dynamic(..) + | ty::Param(..) + | ty::Foreign(..) + | ty::Alias(ty::Projection, ..) + | ty::Placeholder(..) => Some(Err(NoSolution)), + + ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"), + + // Generators have one special built-in candidate, `Unpin`, which + // takes precedence over the structural auto trait candidate being + // assembled. + ty::Generator(_, _, movability) + if Some(goal.predicate.def_id()) == self.tcx().lang_items().unpin_trait() => + { + match movability { + Movability::Static => Some(Err(NoSolution)), + Movability::Movable => { + Some(self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) + } + } + } + + // For rigid types, any possible implementation that could apply to + // the type (even if after unification and processing nested goals + // it does not hold) will disqualify the built-in auto impl. + // + // This differs from the current stable behavior and fixes #84857. + // Due to breakage found via crater, we currently instead lint + // patterns which can be used to exploit this unsoundness on stable, + // see #93367 for more details. + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Closure(_, _) + | ty::Generator(_, _, _) + | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(_, _) + | ty::Never + | ty::Tuple(_) + | ty::Adt(_, _) + // FIXME: Handling opaques here is kinda sus. Especially because we + // simplify them to PlaceholderSimplifiedType. + | ty::Alias(ty::Opaque, _) => { + if let Some(def_id) = self.tcx().find_map_relevant_impl( + goal.predicate.def_id(), + goal.predicate.self_ty(), + TreatProjections::NextSolverLookup, + Some, + ) { + debug!(?def_id, ?goal, "disqualified auto-trait implementation"); + // No need to actually consider the candidate here, + // since we do that in `consider_impl_candidate`. + return Some(Err(NoSolution)); + } else { + None + } + } + ty::Error(_) => None, + } + } + /// Convenience function for traits that are structural, i.e. that only /// have nested subgoals that only change the self type. Unlike other /// evaluate-like helpers, this does a probe, so it doesn't need to be From c68c6c3942d8c3aab4d9e9406a0a4473218f8cea Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 14 Apr 2023 03:21:21 +0000 Subject: [PATCH 269/272] Add test for uniquifying regions --- tests/ui/traits/new-solver/iter-filter-projection.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/ui/traits/new-solver/iter-filter-projection.rs diff --git a/tests/ui/traits/new-solver/iter-filter-projection.rs b/tests/ui/traits/new-solver/iter-filter-projection.rs new file mode 100644 index 000000000000..8fb62323aa5a --- /dev/null +++ b/tests/ui/traits/new-solver/iter-filter-projection.rs @@ -0,0 +1,12 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +use std::{iter, slice}; + +struct Attr; + +fn test<'a, T: Iterator>() {} + +fn main() { + test::, fn(&&Attr) -> bool>>(); +} From 2386cd7b22174f277d5bd9ad802bcffc3b902ab6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 14 Apr 2023 14:27:34 +0200 Subject: [PATCH 270/272] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index f1ed3be2edd3..d394ab5a7aea 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -d4be8efc6296bace5b1e165f1b34d3c6da76aa8e +71ef9ecbdedb67c32f074884f503f8e582855c2f From e3de409aaa592a36548a9f453688c3e877b5caa1 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Fri, 14 Apr 2023 17:53:57 +0000 Subject: [PATCH 271/272] Move test from rustdoc-ui to rustdoc-json --- .../reexport/auxiliary/enum_with_discriminant.rs | 6 ++++++ .../rustdoc-json/reexport/doc_inline_external_crate.rs | 10 ++++++++++ tests/rustdoc-json/reexport/extern_crate_glob.rs | 10 ++++++++++ .../rustdoc-ui/intra-doc/auxiliary/inner-crate-enum.rs | 3 --- tests/rustdoc-ui/intra-doc/inline-external-enum.rs | 8 -------- 5 files changed, 26 insertions(+), 11 deletions(-) create mode 100644 tests/rustdoc-json/reexport/auxiliary/enum_with_discriminant.rs create mode 100644 tests/rustdoc-json/reexport/doc_inline_external_crate.rs create mode 100644 tests/rustdoc-json/reexport/extern_crate_glob.rs delete mode 100644 tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-enum.rs delete mode 100644 tests/rustdoc-ui/intra-doc/inline-external-enum.rs diff --git a/tests/rustdoc-json/reexport/auxiliary/enum_with_discriminant.rs b/tests/rustdoc-json/reexport/auxiliary/enum_with_discriminant.rs new file mode 100644 index 000000000000..4fa26204be91 --- /dev/null +++ b/tests/rustdoc-json/reexport/auxiliary/enum_with_discriminant.rs @@ -0,0 +1,6 @@ +//! Should not be inlined + +/// Should not be inlined +pub enum O { + L = -1, +} diff --git a/tests/rustdoc-json/reexport/doc_inline_external_crate.rs b/tests/rustdoc-json/reexport/doc_inline_external_crate.rs new file mode 100644 index 000000000000..40b681d7dbbe --- /dev/null +++ b/tests/rustdoc-json/reexport/doc_inline_external_crate.rs @@ -0,0 +1,10 @@ +// Regression Test for https://github.com/rust-lang/rust/issues/110138 +// aux-build: enum_with_discriminant.rs + +#[doc(inline)] +pub extern crate enum_with_discriminant; + +// @!has '$.index[*][?(@.docs == "Should not be inlined")]' +// @is '$.index[*][?(@.name == "enum_with_discriminant")].kind' '"extern_crate"' +// @set enum_with_discriminant = '$.index[*][?(@.name == "enum_with_discriminant")].id' +// @is '$.index[*][?(@.name == "doc_inline_external_crate")].inner.items[*]' $enum_with_discriminant diff --git a/tests/rustdoc-json/reexport/extern_crate_glob.rs b/tests/rustdoc-json/reexport/extern_crate_glob.rs new file mode 100644 index 000000000000..8efb94fd3f17 --- /dev/null +++ b/tests/rustdoc-json/reexport/extern_crate_glob.rs @@ -0,0 +1,10 @@ +// aux-build: enum_with_discriminant.rs + +extern crate enum_with_discriminant; + +#[doc(inline)] +pub use enum_with_discriminant::*; + +// @!has '$.index[*][?(@.docs == "Should not be inlined")]' +// @set use = '$.index[*][?(@.inner.name == "enum_with_discriminant")].id' +// @is '$.index[*][?(@.name == "extern_crate_glob")].inner.items[*]' $use diff --git a/tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-enum.rs b/tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-enum.rs deleted file mode 100644 index 6c48f5aa01f9..000000000000 --- a/tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-enum.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub enum O { - L = -1, -} diff --git a/tests/rustdoc-ui/intra-doc/inline-external-enum.rs b/tests/rustdoc-ui/intra-doc/inline-external-enum.rs deleted file mode 100644 index 363dd7f64c22..000000000000 --- a/tests/rustdoc-ui/intra-doc/inline-external-enum.rs +++ /dev/null @@ -1,8 +0,0 @@ -// check-pass -// aux-build: inner-crate-enum.rs -// compile-flags:-Z unstable-options --output-format json - -#[doc(inline)] -pub extern crate inner_crate_enum; - -fn main() {} From 8a9e03a618e68f5e67cf940e3fb2b361f0d92850 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 14 Apr 2023 14:27:02 +0200 Subject: [PATCH 272/272] add test for recent unwind UB issue --- src/tools/miri/tests/panic/oob_subslice.rs | 7 +++++++ src/tools/miri/tests/panic/oob_subslice.stderr | 2 ++ 2 files changed, 9 insertions(+) create mode 100644 src/tools/miri/tests/panic/oob_subslice.rs create mode 100644 src/tools/miri/tests/panic/oob_subslice.stderr diff --git a/src/tools/miri/tests/panic/oob_subslice.rs b/src/tools/miri/tests/panic/oob_subslice.rs new file mode 100644 index 000000000000..4e79b6a99e9c --- /dev/null +++ b/src/tools/miri/tests/panic/oob_subslice.rs @@ -0,0 +1,7 @@ +// This once failed with "unwinding past a stack frame that does not allow unwinding", +// fixed by https://github.com/rust-lang/rust/issues/110233. + +fn main() { + let x = [1, 2, 3, 4]; + let _val = &x[..=4]; +} diff --git a/src/tools/miri/tests/panic/oob_subslice.stderr b/src/tools/miri/tests/panic/oob_subslice.stderr new file mode 100644 index 000000000000..4c6deaeccf61 --- /dev/null +++ b/src/tools/miri/tests/panic/oob_subslice.stderr @@ -0,0 +1,2 @@ +thread 'main' panicked at 'range end index 5 out of range for slice of length 4', $DIR/oob_subslice.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace